Yoga Docs: Delete the Old website (#1612)

Summary:
Pull Request resolved: https://github.com/facebook/yoga/pull/1612

Moving new website to `/website` before publishing, so that edit links point to the right eventual place in the GitHub repo.

Reviewed By: joevilches

Differential Revision: D54837808

fbshipit-source-id: 46de8a638ad9bce18558fd768ed8c080892b828e
This commit is contained in:
Nick Gerleman
2024-03-13 15:53:21 -07:00
committed by Facebook GitHub Bot
parent d7faf2c101
commit 108c2f30a2
86 changed files with 1 additions and 17082 deletions

View File

@@ -1,23 +0,0 @@
name: Setup Website envirionment
runs:
using: "composite"
steps:
# TODO: Update to latest when website is moved to the workspace version of
# yoga-layout
- name: Setup Node environment
uses: actions/setup-node@v3
with:
node-version: 12.x
cache: yarn
cache-dependency-path: website/yarn.lock
env:
# https://github.com/actions/setup-node/issues/317
FORCE_COLOR: 0
# TODO: the website should be in a yarn workspace with the library, but the
# current version of gatsby is incompatible with hoisting.
- name: yarn install
shell: bash
run: yarn install --frozen-lockfile --network-timeout 1000000
working-directory: website

View File

@@ -1,35 +0,0 @@
name: Publish Website
on:
push:
branches:
- main
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}
jobs:
publish:
name: Publish to GitHub Pages
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-website
- name: yarn build
run: yarn build
working-directory: website
- uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_branch: gh-pages
publish_dir: website/public
cname: yogalayout.dev
keep_files: true
user_name: 'Yoga-bot'
user_email: 'yogabot@fb.com'

View File

@@ -10,22 +10,8 @@ on:
workflow_dispatch:
jobs:
build:
name: Build [Gatsby]
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-website
- name: yarn build
run: yarn build
working-directory: website
build_next:
name: Build [Docusaurus]
name: Build
runs-on: ubuntu-latest
steps:

View File

@@ -1,15 +0,0 @@
[ignore]
[include]
[libs]
[lints]
[options]
types_first=false
[strict]
[version]
^0.140.0

7
website/.gitignore vendored
View File

@@ -1,7 +0,0 @@
# Project dependencies
.cache/
# Build directory
public/
.DS_Store
yarn-error.log
src/components/Playground/dist

View File

@@ -1,35 +0,0 @@
# Yoga documentation and playground
This site uses [gatsby.js](https://www.gatsbyjs.org/) as static site generator. Which transforms all markdown and react code to static HTML and JS files.
## Development
```
yarn install
yarn develop
```
### Structure
Documentation pages are generated from the Markdown files in `contents/`. The files are organized in 4 sections/folders (getting-started, properties, examples, contributing) which are dynamically listed on the docs overview page. The Markdown files can have some header files containing metadata.
```
---
path: "docs/flexDirection"
title: "Flex Direction"
hasPlayground: true
editableProperties: ['flexDirection']
---
```
The `path` can be any URL this page should be available at. The `title` is used as the page's HTML-title and when referencing the file from the documentation overview. There are two kinds of templates for a page: with and without playground. `hasPlayground` selects the corresponding template (`src/templates/{with|without}Playground.js`). When using `hasPlayground: true`, `editableProperties` can list all Yoga properties which are editable in the playground.
### Design
We are using [antd](https://ant.design) for various UI elements. See their documentation for the components available. `gatsby-config.js` can be used to overwrite LESS-variables from antd.
For styling react components we create a CSS-file with the same name next to each component and import it in the component. E.g. there is `index.js` and `index.css`. In the react-component we import the stylesheet: `import './index.css'`.
## Build
To generate the static files run:
```
yarn build
```
The output will be in `public/` and can be published on GitHub pages.

View File

@@ -1,51 +0,0 @@
---
path: "/contributing/opening-a-pull-request"
title: "Opening a Pull Request"
hasPlayground: false
---
# Opening a Pull Request
Before opening your first pull request to Yoga you have to know how to get the code,
install build time dependencies, and test the code locally.
### Clone
```
$> git clone https://github.com/facebook/yoga.git
$> cd yoga
```
### Install dependencies
```
$> git submodule init
$> git submodule update
$> brew install buck
```
### Build and Test
```
$> buck build //:yoga
$> buck test //:yoga
```
## Making a Change
Now all you need to do is make your change and test it before submitting a pull request for review.
Below is the general structure of the repo and where you may want to make your change. One you have
made your change see the [testing documentation](/contributing/testing) for more on how to test your change.
``` bash
/yoga
|-- yoga # Home to the main Yoga codebase written in C++. Any algorithmic changes should be made here
|-- lib # Yoga external dependencies. Be thoughtful adding any new ones
|-- tests # Yoga's C++ test suite. Both manaul and generated tests
|-- gentest
| |-- fixtures # html fixtures for generated tests
|-- java
| |-- com/facebook/yoga # Java binding code
| |-- jni # JNI binding code
|-- javascript # emscripten / javascript bindings
```

View File

@@ -1,43 +0,0 @@
---
path: "/contributing/testing"
title: "Testing"
hasPlayground: false
---
# Testing
Yoga tries to be as close as possible to chrome in its flexbox behaviour.
To ensure this most of Yoga's test suite is automatically generateded from
running the corresponding layout in chrome using a webdriver which then generates
C++ test which asserts that Yoga will produce matching outputs for that layout.
## Running the Test Suite
1. Yoga builds with [buck](https://buckbuild.com). Follow their documentation to get up and running.
2. For testing Yoga relies on [gtest](https://github.com/google/googletest) as a submodule. After cloning Yoga run `git submodule init` followed by `git submodule update`.
3. In a terminal from the root of your Yoga checkout run `buck test //:yoga`.
## Adding a Test
Instead of manually writing a test which ensures parity with web implementations
of Flexbox we make use of a generated test suite. We use `gentest/gentest.rb` to
generate this test suite. Write the html which you want to verify in Yoga and put
it in the `gentest/fixtures` folder, such as the following.
```html
<div id="my_test" style="width: 100px; height: 100px; align-items: center;">
<div style="width: 50px; height: 50px;"></div>
</div>
```
Run `gentest/gentest.rb` to generate test code and re-run `buck test //:yoga`
to validate the behavior. One test case will be generated for every root `div`
in the input html with the string in the `id` corresponding to the test name.
You should run `bundle install` in the `gentest` directory to install dependencies for the `gentest/gentest.rb` Ruby script.
## Manual test
For some aspects of Yoga we cannot generate a test using the test generation
infrastructure described earlier. For these cases we manually write a test in
the `/tests` directory.

View File

@@ -1,52 +0,0 @@
---
path: "/contributing/writing-documentation"
title: "Writing Documentation"
hasPlayground: false
---
## Writing Documentation
Documentation pages are generated from Markdown files in `contents/`.
The files are organized in 4 sections/folders (getting-started, properties,
examples, contributing) which are dynamically listed on the docs overview page.
The Markdown files should contain a header with metadata.
```markdown
---
path: "docs/flexDirection"
title: "Flex Direction"
hasPlayground: true
initialPlayground: eyJ3aWR0aCI6IjYwMCIsImhlaWdodCI6NTAwLCJjaGlsZHJlbiI6W3t9LHt9LHt9XX0=
---
```
- The `path` indicates the URL path this page will be available at.
- The `title` is used as the page's HTML-title and when referencing
the file from the documentation overview.
- The `hasPlayground` property indicates whether this documentation
has an associated playground to test out the documented feature.
- The `initialPlayground` property is only relevant for documentation
pages with playgrounds and contains the initial playground state.
This base64 string is a reference to the hash (content after #)
of a [playground](/playground) url.
- The `redirect` property allows to redirect to the other page, the path of which is mentioned in the property `path`.
Within the markdown of a documentation page which has an associated
playground you can add controls to let the user play around with the feature
directly from the documenation page.
```markdown
<controls prop="alignContent"></controls>
```
If you would like to redirect to another page (potentially an external link) the header would look something like this.
```markdown
---
path: "/playground?eyJ3aWR0aCI6IjYwMCIsImhlaWdodCI6NTAwLCJjaGlsZHJlbiI6W3t9LHt9LHt9XX0="
title: "Flex Direction"
redirect: true
---
```

View File

@@ -1,5 +0,0 @@
---
path: "/playground?eyJ3aWR0aCI6NTAwLCJoZWlnaHQiOjUwMCwiY2hpbGRyZW4iOlt7IndpZHRoIjoiNjAiLCJoZWlnaHQiOiI2MCIsIm1hcmdpbiI6eyJ0b3AiOiIyMCIsInJpZ2h0IjoiMjAiLCJib3R0b20iOiIyMCIsImxlZnQiOiIyMCJ9fSx7ImhlaWdodCI6IjYwIiwibWFyZ2luIjp7InRvcCI6IjIwIiwicmlnaHQiOiIyMCIsImJvdHRvbSI6IjIwIiwibGVmdCI6IjIwIn0sImZsZXhHcm93IjoiMSJ9LHsid2lkdGgiOiI0MCIsImhlaWdodCI6IjQwIiwibWFyZ2luIjp7InRvcCI6IjIwIiwicmlnaHQiOiIyMCIsImJvdHRvbSI6IjIwIiwibGVmdCI6IjIwIn19XX0="
title: "Flexible Text"
redirect: true
---

View File

@@ -1,5 +0,0 @@
---
path: "/playground?eyJ3aWR0aCI6NTAwLCJoZWlnaHQiOjUwMCwiY2hpbGRyZW4iOlt7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJwb3NpdGlvbiI6eyJ0b3AiOiJhdXRvIiwicmlnaHQiOiIxMCIsImJvdHRvbSI6IjEwIiwibGVmdCI6ImF1dG8ifSwicG9zaXRpb25UeXBlIjoxLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfV0sIm1pbldpZHRoIjpudWxsLCJtYXhXaWR0aCI6bnVsbCwibWluSGVpZ2h0IjpudWxsLCJtYXhIZWlnaHQiOm51bGx9"
title: "Floating Buttons"
redirect: true
---

View File

@@ -1,5 +0,0 @@
---
path: "/playground?eyJ3aWR0aCI6NTAwLCJoZWlnaHQiOjUwMCwiY2hpbGRyZW4iOlt7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoiMTAwJSIsImhlaWdodCI6IjEwMCUiLCJwb3NpdGlvblR5cGUiOjEsIm1pbldpZHRoIjpudWxsLCJtYXhXaWR0aCI6bnVsbCwibWluSGVpZ2h0IjpudWxsLCJtYXhIZWlnaHQiOm51bGx9XSwibWluV2lkdGgiOm51bGwsIm1heFdpZHRoIjpudWxsLCJtaW5IZWlnaHQiOm51bGwsIm1heEhlaWdodCI6bnVsbH0="
title: "Overlays"
redirect: true
---

View File

@@ -1,5 +0,0 @@
---
path: "https://componentkit.org/docs/getting-started/"
title: "ComponentKit"
redirect: true
---

View File

@@ -1,5 +0,0 @@
---
path: "https://fblitho.com/docs/getting-started"
title: "Litho"
redirect: true
---

View File

@@ -1,5 +0,0 @@
---
path: "https://reactnative.dev/docs/getting-started"
title: "React Native"
redirect: true
---

View File

@@ -1,72 +0,0 @@
---
path: "/getting-started/standalone"
title: "Standalone"
hasPlayground: false
---
# Standalone
Adding Yoga to a project is as simple as adding the dependency to your package manager of choice.
### Android
```groovy
dependencies {
implementation 'com.facebook.yoga.android:yoga-layout:x.x.x'
}
```
### Javascript
The JavaScript bindings for Yoga can be used from node.js and within the browser.
When using Yoga from node.js the native library is used, in browsers a pure JS
version is used (cross-compiled using [emscripten](https://emscripten.org/)).
```
$> yarn add yoga-layout
```
This is an example on how to use Yoga in JavaScript. For a full API reference,
have a look at the [TypeScript type definitions](https://github.com/facebook/yoga/blob/main/javascript/src/wrapAssembly.ts).
```js
import {loadYoga} from 'yoga-layout';
const Yoga = await loadYoga();
const root = Yoga.Node.create();
root.setWidth(500);
root.setHeight(300);
root.setJustifyContent(Yoga.JUSTIFY_CENTER);
root.setFlexDirection(Yoga.FLEX_DIRECTION_ROW);
const node1 = Yoga.Node.create();
node1.setWidth(100);
node1.setHeight(100);
const node2 = Yoga.Node.create();
node2.setWidth(100);
node2.setHeight(100);
root.insertChild(node1, 0);
root.insertChild(node2, 1);
root.calculateLayout(500, 300, Yoga.DIRECTION_LTR);
console.log(root.getComputedLayout());
// {left: 0, top: 0, width: 500, height: 300}
console.log(node1.getComputedLayout());
// {left: 150, top: 0, width: 100, height: 100}
console.log(node2.getComputedLayout());
// {left: 250, top: 0, width: 100, height: 100}
```
### iOS
```
pod 'YogaKit', '~> 1.7'
```
## Including Yoga From Source
If you plan to include Yoga from Source in a C++ project then all you have to do is inlude
the top level `yoga` folder. Make sure to look at the top level `BUCK` file to ensure you build
using the same compiler flags.

View File

@@ -1,30 +0,0 @@
---
path: "/docs/absolute-relative-layout"
title: "Absolute/Relative Layout"
hasPlayground: true
---
## Absolute/Relative Layout
The `position type` of an element defines how it is
positioned within its parent.
**RELATIVE (DEFAULT)** By default an element is positioned
relatively. This means an element is positioned according to the
normal flow of the layout, and then offset relative to that position
based on the values of `top`, `right`, `bottom`, and `left`.
The offset does not affect the position of any sibling or parent elements.
**ABSOLUTE** When positioned absolutely an element doesn't take
part in the normal layout flow. It is instead laid out independent
of its siblings. The position is determined based on the
`top`, `right`, `bottom`, and `left` values.
<controls prop="positionType"></controls>
The position values `top`, `right`, `bottom`, and `left` behave
differently depending on the `position type` of the element. For
a `relative` element they offset the position of the element in the
direction specified. For `absolute` element though these properties
specify the offset of the element's side from the same side on the parent.
<controls prop="position"></controls>

View File

@@ -1,29 +0,0 @@
---
path: "/docs/align-content"
title: "Align Content"
hasPlayground: true
initialPlayground: eyJ3aWR0aCI6NTAwLCJoZWlnaHQiOjUwMCwiYWxpZ25Db250ZW50IjoxLCJmbGV4V3JhcCI6MSwiY2hpbGRyZW4iOlt7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJhbGlnbkNvbnRlbnQiOjIsIm1pbldpZHRoIjpudWxsLCJtYXhXaWR0aCI6bnVsbCwibWluSGVpZ2h0IjpudWxsLCJtYXhIZWlnaHQiOm51bGx9XSwibWluV2lkdGgiOm51bGwsIm1heFdpZHRoIjpudWxsLCJtaW5IZWlnaHQiOm51bGwsIm1heEhlaWdodCI6bnVsbH0=
---
## Align Content
Align content defines the distribution of lines along the cross-axis. This only
has effect when items are wrapped to multiple lines using [`flex wrap`](/docs/flex-wrap).
**FLEX START (DEFAULT)** Align wrapped lines to the start of the container's cross axis.
**FLEX END** Align wrapped lines to the end of the container's cross axis.
**STRETCH** Stretch wrapped lines to match the `height` of the container's cross axis.
**CENTER** Align wrapped lines in the center of the container's cross axis.
**SPACE BETWEEN** Evenly space wrapped lines across the container's main axis, distributing
remaining space between the lines.
**SPACE AROUND** Evenly space wrapped lines across the container's main axis, distributing
remaining space around the lines. Compared to `space between` using
`space around` will result in space being distributed to the begining of
the first lines and end of the last line.
<controls prop="alignContent"></controls>

View File

@@ -1,32 +0,0 @@
---
path: "/docs/align-items"
title: "Align Items / Self"
hasPlayground: true
---
## Align Items
Align items describes how to align children along the cross axis of their container.
Align items is very similar to [`justify content`](/docs/justify-content) but instead of
applying to the main axis, `align items` applies to the cross axis.
**STRETCH (DEFAULT)** Stretch children of a container to match the `height` of the container's cross axis.
**FLEX START** Align children of a container to the start of the container's cross axis.
**FLEX END** Align children of a container to the end of the container's cross axis.
**CENTER** Align children of a container in the center of the container's cross axis.
**BASELINE** Align children of a container along a common baseline. Individual children can be set to be the reference baseline for their parents.
<controls prop="alignItems"></controls>
## Align Self
Align self has the same options and effect as `align items` but instead of
affecting the children within a container, you can apply this property to
a single child to change its alignment within its parent. `align self`
overrides any option set by the parent with `align items`.
<controls prop="alignSelf"></controls>

View File

@@ -1,21 +0,0 @@
---
path: "/docs/aspect-ratio"
title: "Aspect Ratio"
hasPlayground: true
---
## Aspect Ratio
AspectRatio is a property introduced by Yoga and is not present as a settable
property in the css flexbox specification. Flexbox does have the notion of
aspect ratio though for things with intrinsic aspect ratio such as images.
The `aspect ratio` property in Yoga has the following properties:
- Accepts any floating point value > 0, the default is undefined.
- Defined as the ratio between the `width` and the `height` of a node e.g. if a node has an aspect ratio of 2 then its `width` is twice the size of its `height`.
- Respects the `min` and `max` dimensions of an item.
- Has higher priority than `flex grow`
- If `aspect ratio`, `width`, and `height` are set then the cross axis dimension is overridden.
<controls prop="aspectRatio"></controls>

View File

@@ -1,26 +0,0 @@
---
path: "/docs/flex-direction"
title: "Flex Direction"
hasPlayground: true
---
## Flex Direction
Flex direction controls the direction in which children of a node are laid out.
This is also referred to as the main axis. The main axis is the direction in
which children are laid out. The cross axis is the axis perpendicular to the
main axis, or the axis which wrapping lines are laid out in.
**ROW (DEFAULT)** Align children from left to right. If [wrapping](/docs/flex-wrap) is enabled then
the next line will start under the first item on the left of the container.
**COLUMN** Align children from top to bottom. If [wrapping](/docs/flex-wrap) is enabled then
the next line will start to the left first item on the top of the container.
**ROW REVERSE** Align children from right to left. If [wrapping](/docs/flex-wrap) is enabled then
the next line will start under the first item on the right of the container.
**COLUMN REVERSE** Align children from bottom to top. If [wrapping](/docs/flex-wrap) is enabled then
the next line will start to the left first item on the bottom of the container.
<controls prop="flexDirection"></controls>

View File

@@ -1,21 +0,0 @@
---
path: "/docs/flex-wrap"
title: "Flex Wrap"
hasPlayground: true
initialPlayground: eyJ3aWR0aCI6NTAwLCJoZWlnaHQiOjUwMCwiYWxpZ25Db250ZW50IjoxLCJmbGV4V3JhcCI6MSwiY2hpbGRyZW4iOlt7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfSx7IndpZHRoIjoxMDAsImhlaWdodCI6MTAwLCJtaW5XaWR0aCI6bnVsbCwibWF4V2lkdGgiOm51bGwsIm1pbkhlaWdodCI6bnVsbCwibWF4SGVpZ2h0IjpudWxsfV0sIm1pbldpZHRoIjpudWxsLCJtYXhXaWR0aCI6bnVsbCwibWluSGVpZ2h0IjpudWxsLCJtYXhIZWlnaHQiOm51bGx9
---
## Flex Wrap
The `flex wrap` property is set on containers and controls what happens when
children overflow the size of the container along the main axis. By default
children are forced into a single line (which can shrink elements).
If wrapping is allowed items are wrapped into multiple lines along the main
axis if needed. `wrap reverse` behaves the same, but the order of the lines is
reversed.
<controls prop="flexWrap"></controls>
When wrapping lines [`align content`](/docs/align-content) can be used to specify how the
lines are placed in the container.

View File

@@ -1,36 +0,0 @@
---
path: "/docs/flex"
title: "Flex Basis, Grow, and Shrink"
hasPlayground: true
---
## Flex Basis, Grow, and Shrink
**FLEX BASIS** is an axis-independent way of providing the default size of an item
along the main axis. Setting the flex basis of a child is similar to setting the `width` of that
child if its parent is a container with `flex direction: row` or setting the `height` of a child
if its parent is a container with `flex direction: column`. The flex basis of an item is the
default size of that item, the size of the item before any flex grow and flex shrink
calculations are performed.
<controls prop="flexBasis"></controls>
**FLEX GROW** describes how any space within a container should be distributed
among its children along the main axis. After laying out its children, a container will
distribute any remaining space according to the flex grow values specified by its children.
Flex grow accepts any floating point value >= 0, with 0 being the default value.
A container will distribute any remaining space among its children weighted by the childs flex grow value.
<controls prop="flexGrow"></controls>
**FLEX SHRINK** describes how to shrink children along the main axis in the
case that the total size of the children overflow the size of the container on the main axis.
flex shrink is very similar to flex grow and can be thought of in the same way if
any overflowing size is considered to be negative remaining space.
These two properties also work well together by allowing children to grow and shrink as needed.
Flex shrink accepts any floating point value >= 0, with 1 being the default value.
A container will shrink its children weighted by the childs flex shrink value.
<controls prop="flexShrink"></controls>

View File

@@ -1,30 +0,0 @@
---
path: "/docs/justify-content"
title: "Justify Content"
hasPlayground: true
---
## Justify Content
Justify content describes how to align children within the main axis of their container.
For example, you can use this property to center a child horizontally within a container
with `flex direction` set to `row` or vertically within a container with `flex direction`
set to `column`.
**FLEX START (DEFAULT)** Align children of a container to the start of the container's main axis.
**FLEX END** Align children of a container to the end of the container's main axis.
**CENTER** Align children of a container in the center of the container's main axis.
**SPACE BETWEEN** Evenly space of children across the container's main axis, distributing
remaining space between the children.
**SPACE AROUND** Evenly space of children across the container's main axis, distributing
remaining space around the children. Compared to `space between` using
`space around` will result in space being distributed to the beginning of
the first child and end of the last child.
**SPACE EVENLY** Evenly distributed within the alignment container along the main axis. The spacing between each pair of adjacent items, the main-start edge and the first item, and the main-end edge and the last item, are all exactly the same.
<controls prop="justifyContent"></controls>

View File

@@ -1,23 +0,0 @@
---
path: "/docs/layout-direction"
title: "Layout Direction"
hasPlayground: false
---
## Layout Direction
Layout direction specifies the direction in which children and text
in a hierarchy should be laid out. Layout direction also effects what
edge `start` and `end` refer to. By default Yoga lays out with `LTR`
layout direction. In this mode `start` refers to `left` and `end`
refers to `right`. When localizing your apps for markets with RTL languages
you should customize this by either by passing a direction
to the `CalculateLayout` call or by setting the direction on the root node.
**LTR (DEFAULT)** Text and children and laid out from left to right. Margin and
padding applied the start of an element are applied on the left side.
**RTL** Text and children and laid out from right to left. Margin and
padding applied the start of an element are applied on the right side.
<controls prop="layoutDirection"></controls>

View File

@@ -1,28 +0,0 @@
---
path: "/docs/margins-paddings-borders"
title: "Margins, Paddings, and Borders"
hasPlayground: true
---
## Margins, Paddings, and Borders
**MARGIN** effects the spacing around the outside of a node. A node with margin
will offset itself from the bounds of its parent but also offset the
location of any siblings. The margin of a node contributes to the total size
of its parent if the parent is auto sized.
<controls prop="margin"></controls>
**PADDING** affects the size of the node it is applied to. Padding in Yoga acts as if
`box-sizing: border-box;` was set. That is padding will not add to the total size
of an element if it has an explicit size set. For auto sized nodes padding will increase
the size of the node as well as offset the location of any children.
<controls prop="padding"></controls>
**BORDER** in Yoga acts exactly like padding and only exists as a seperate property so
that higher level frameworks get a hint as to how thick to draw a border. Yoga however
does not do any drawing so just uses this information during layout where border
acts exactly like padding.
<controls prop="border"></controls>

View File

@@ -1,28 +0,0 @@
---
path: "/docs/min-max"
title: "Max / Min Width and Height"
hasPlayground: true
---
## Max / Min Width and Height
All the following properties set the maximum and minimum size constraints of an element.
These properties have higher priority than all other properties and will always be respected.
Constraints can be specified as either absolute pixel values or as percentages of their
parent's size. By default all these constraints are `undefined`.
### Max Width
<controls prop="maxWidth"></controls>
### Min Width
<controls prop="minWidth"></controls>
### Max Height
<controls prop="maxHeight"></controls>
### Min Height
<controls prop="minHeight"></controls>

View File

@@ -1,26 +0,0 @@
---
path: "/docs/width-height"
title: "Width and Height"
hasPlayground: true
---
## Width and Height
The `width` property in Yoga specifies the width of the element's content area.
Similarly `height` property specifies the height of the element's content area.
Both `width` and `height` can take following values:
**AUTO** Is the default Value, Yoga calculates the width/height for the element based
on its content, whether that is other children, text, or an image.
**PIXELS** Defines the width/height in absolute pixels. Depending on other properties set on
the Yoga node this may or may not be the final dimension of the node.
**PERCENTAGE** Defines the width or height in percentage of its parent's width or height respectively.
### Width
<controls prop="width"></controls>
### Height
<controls prop="height"></controls>

View File

@@ -1,67 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
module.exports = {
siteMetadata: {
title: 'Yoga Layout',
},
plugins: [
// using latest react version
'gatsby-plugin-react-next',
// setting head data like title from within components
'gatsby-plugin-react-helmet',
{
resolve: `gatsby-plugin-less`,
options: {
theme: {
'primary-color': '#6BCEBB',
},
},
},
// plugin for importing antd components
{
resolve: 'gatsby-plugin-antd',
options: {
style: true,
},
},
// reading files from the file-system (used for markdown files)
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/contents`,
name: 'markdown-pages',
},
},
// parse markdown files, used for content files
{
resolve: `gatsby-transformer-remark`,
options: {
// code-highlighting in markdown files
plugins: [
{
resolve: `gatsby-remark-prismjs`,
options: {
classPrefix: 'language-',
},
},
],
},
},
{
resolve: `gatsby-plugin-google-analytics`,
options: {
trackingId: 'UA-44373548-24',
head: false,
anonymize: true,
},
},
],
};

View File

@@ -1,52 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
const path = require('path');
exports.createPages = ({boundActionCreators, graphql}) => {
const {createPage} = boundActionCreators;
const withPlayground = path.resolve(`src/templates/withPlayground.js`);
const withoutPlayground = path.resolve(`src/templates/withoutPlayground.js`);
return graphql(`
{
allMarkdownRemark {
edges {
node {
frontmatter {
path
title
hasPlayground
initialPlayground
redirect
}
html
}
}
}
}
`).then(result => {
if (result.errors) {
return Promise.reject(result.errors);
}
result.data.allMarkdownRemark.edges.forEach(({node}) => {
if (!node.frontmatter.redirect) {
createPage({
path: node.frontmatter.path,
component: node.frontmatter.hasPlayground
? withPlayground
: withoutPlayground,
context: node,
});
}
});
});
};

View File

@@ -1,40 +0,0 @@
{
"name": "gatsby-starter-default",
"description": "Gatsby default starter",
"version": "1.0.0",
"author": "Kyle Mathews <mathews.kyle@gmail.com>",
"dependencies": {
"antd": "^3.6.5",
"atob": "^2.1.1",
"btoa": "^1.2.1",
"gatsby": "^1.9.273",
"gatsby-link": "^1.6.45",
"gatsby-plugin-antd": "^1.0.12",
"gatsby-plugin-google-analytics": "^1.0.31",
"gatsby-plugin-less": "^1.1.8",
"gatsby-plugin-react-helmet": "^2.0.11",
"gatsby-plugin-react-next": "^1.0.11",
"gatsby-remark-prismjs": "^2.0.4",
"gatsby-source-filesystem": "^1.5.39",
"gatsby-transformer-remark": "^1.7.44",
"immutable": "^4.0.0-rc.9",
"react-helmet": "^5.2.0",
"react-syntax-highlighter": "^8.0.0",
"yoga-layout": "^1.9.3"
},
"keywords": [
"gatsby"
],
"license": "MIT",
"main": "n/a",
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop"
},
"devDependencies": {
"prettier": "1.19.1"
},
"resolutions": {
"nbind": "https://github.com/charto/nbind.git#fe3abe0"
}
}

View File

@@ -1,33 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.DocsSidebar {
height: 100%;
width: 450px;
padding: 36px;
padding-top: 0px;
border-right: 1px solid #dddfe2;
overflow: auto;
}
.DocsSidebar h3 {
margin-bottom: 0;
}
.DocsSidebar h4 {
margin-top: 10px;
margin-bottom: 5px;
}
@media only screen and (max-width: 992px) {
.DocsSidebar {
width: 100%;
padding: 20px;
padding-top: 0px;
border: none;
}
}

View File

@@ -1,84 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import EditValue from '../components/Playground/src/EditValue';
import Link from 'gatsby-link';
import './DocsSidebar.css';
import type {LayoutRecordT} from './Playground/src/LayoutRecord';
const TAG_PATTERN = /<controls prop="([A-Za-z]+)"><\/controls>/gi;
type Props = {
markdown: string,
onChange: (property: string, value: any) => void,
layout: LayoutRecordT,
};
export default class DocsSidebar extends Component<Props> {
componentDidMount() {
this.renderControls(this.props);
}
componentWillReceiveProps(nextProps: Props) {
this.renderControls(nextProps);
}
renderControls = (props: Props) => {
let match;
while ((match = TAG_PATTERN.exec(props.markdown))) {
const prop = match[1];
const element = window.document.querySelector(
`controls[prop="${match[1]}"]`,
);
if (element) {
if (element.childNodes.length !== 0) {
console.warn(
`The element <controls type="${prop}"> is not empty. It's content will be replaced by the react-component mounted in this element.`,
);
}
ReactDOM.render(
<EditValue
property={prop}
value={props.layout[prop]}
onChange={(property, value) => {
if (window.ga) {
window.ga('send', {
hitType: 'event',
eventCategory: 'DocsSidebar',
eventAction: 'valueChanged',
eventLabel: prop,
});
}
props.onChange(property, value);
}}
/>,
element,
);
}
}
};
render() {
return (
<div className="DocsSidebar">
<div
className="markdown"
dangerouslySetInnerHTML={{__html: this.props.markdown}}
/>
<Link to="/docs" className="overview">
BACK TO OVERVIEW
</Link>
</div>
);
}
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React, {Component} from 'react';
export default () => (
<svg viewBox="0 0 1133.9 1133.9">
<g>
<path d="M 498.3 3.7 c 153.6 88.9 307.3 177.7 461.1 266.2 c 7.6 4.4 10.3 9.1 10.3 17.8 c -0.3 179.1 -0.2 358.3 0 537.4 c 0 8.1 -2.4 12.8 -9.7 17.1 c -154.5 88.9 -308.8 178.1 -462.9 267.5 c -9 5.2 -15.5 5.3 -24.6 0.1 c -153.9 -89.2 -307.9 -178 -462.1 -266.8 C 3 838.8 0 833.9 0 825.1 c 0.3 -179.1 0.2 -358.3 0 -537.4 c 0 -8.6 2.6 -13.6 10.2 -18 C 164.4 180.9 318.4 92 472.4 3 C 477 -1.5 494.3 -0.7 498.3 3.7 Z M 48.8 555.3 c 0 79.9 0.2 159.9 -0.2 239.8 c -0.1 10 3 15.6 11.7 20.6 c 137.2 78.8 274.2 157.8 411 237.3 c 9.9 5.7 17 5.7 26.8 0.1 c 137.5 -79.8 275.2 -159.2 412.9 -238.5 c 7.4 -4.3 10.5 -8.9 10.5 -17.8 c -0.3 -160.2 -0.3 -320.5 0 -480.7 c 0 -8.8 -2.8 -13.6 -10.3 -18 C 772.1 218 633.1 137.8 494.2 57.4 c -6.5 -3.8 -11.5 -4.5 -18.5 -0.5 C 336.8 137.4 197.9 217.7 58.8 297.7 c -7.7 4.4 -10.2 9.2 -10.2 17.9 C 48.9 395.5 48.8 475.4 48.8 555.3 Z" />
<path d="M 184.4 555.9 c 0 -33.3 -1 -66.7 0.3 -100 c 1.9 -48 24.1 -86 64.7 -110.9 c 54.8 -33.6 110.7 -65.5 167 -96.6 c 45.7 -25.2 92.9 -24.7 138.6 1 c 54.4 30.6 108.7 61.5 162.2 93.7 c 44 26.5 67.3 66.8 68 118.4 c 0.9 63.2 0.9 126.5 0 189.7 c -0.7 50.6 -23.4 90.7 -66.6 116.9 c -55 33.4 -110.8 65.4 -167.1 96.5 c -43.4 24 -89 24.2 -132.3 0.5 c -57.5 -31.3 -114.2 -64 -170 -98.3 c -41 -25.1 -62.9 -63.7 -64.5 -112.2 C 183.5 621.9 184.3 588.9 184.4 555.9 Z M 232.9 556.3 c 0 29.5 0.5 59.1 -0.1 88.6 c -0.8 39.2 16.9 67.1 50.2 86.2 c 51.2 29.4 102.2 59.2 153.4 88.4 c 31.4 17.9 63.6 18.3 95 0.6 c 53.7 -30.3 107.1 -61.2 160.3 -92.5 c 29.7 -17.5 45 -44.5 45.3 -78.8 c 0.6 -61.7 0.5 -123.5 0 -185.2 c -0.3 -34.4 -15.3 -61.5 -44.9 -79 C 637.7 352.6 583 320.8 527.9 290 c -27.5 -15.4 -57.2 -16.1 -84.7 -0.7 c -56.9 31.6 -113.4 64 -169.1 97.6 c -26.4 15.9 -40.7 41.3 -41.1 72.9 C 232.6 491.9 232.9 524.1 232.9 556.3 Z" />
<path d="M 484.9 424.4 c 69.8 -2.8 133.2 57.8 132.6 132 C 617 630 558.5 688.7 484.9 689.1 c -75.1 0.4 -132.6 -63.6 -132.7 -132.7 C 352.1 485 413.4 421.5 484.9 424.4 Z M 401.3 556.7 c -3.4 37.2 30.5 83.6 83 84.1 c 46.6 0.4 84.8 -37.6 84.9 -84 c 0.1 -46.6 -37.2 -84.4 -84.2 -84.6 C 432.2 472.1 397.9 518.3 401.3 556.7 Z" />
</g>
</svg>
);

View File

@@ -1,63 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.Footer {
display: flex;
padding: 20px 15px;
z-index: 4;
align-items: center;
background-color: white;
}
.Footer svg {
width: 30px;
height: 30px;
}
.Footer svg path {
fill: #606770;
}
.Footer .logoOSS {
display: flex;
align-items: center;
color: #606770;
}
.Footer .logoOSS svg {
margin-right: 20px;
}
.Footer a {
margin: 0 15px;
color: #606770;
font-weight: 700;
}
.Footer a:hover {
color: #6BCEBB;
}
.Footer .SocialNetwork {
display: flex;
margin-left: auto;
}
@media only screen and (max-width: 576px) {
.Footer {
padding: 10px 5px;
}
.Footer .logoOSS svg {
margin-right: 10px;
}
.Footer a {
margin: 0 10px;
font-size: 12px;
}
}

View File

@@ -1,32 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React, {Component} from 'react';
import Link from 'gatsby-link';
import {Icon} from 'antd';
import './Footer.css';
import FacebookOSSLogo from './FacebookOSSLogo';
export default class Footer extends Component<{}> {
render() {
return (
<div className="Footer">
<a href="https://code.facebook.com/projects/" className="logoOSS">
<FacebookOSSLogo />
Facebook Open Source
</a>
<div className="SocialNetwork">
<a href="https://github.com/facebook/yoga">GitHub</a>
<a href="https://twitter.com/yogalayout">Twitter</a>
</div>
</div>
);
}
}

View File

@@ -1,20 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.Padded {
width: 100%;
max-width: 1200px;
padding: 0 50px;
margin-left: auto;
margin-right: auto;
}
@media only screen and (max-width: 576px) {
.Padded {
padding: 0 20px;
}
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React from 'react';
import './Padded.css';
type Props = {
children: any,
className?: string,
};
export default (props: Props) => (
<div className={`Padded ${props.className || ''}`}>{props.children}</div>
);

View File

@@ -1,62 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
@import url('https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700|Source+Code+Pro');
html,
body {
margin: 0;
padding: 0;
font-family: 'Open Sans', sans-serif;
color: #303845;
font-size: 16px;
}
code,
pre {
font-family: 'Source Code Pro', monospace;
}
h1,
h2 {
font-weight: 500;
}
.gatsby-highlight pre[class*="language-"] {
background: none;
padding: 0;
font-size: 14px;
margin-bottom: 15px;
}
.Page {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.PageContent {
display: flex;
flex-direction: column;
flex-grow: 1;
}
.PageContent.withSpacing {
padding-top: 35px;
}
.Page .ant-dropdown-trigger {
display: flex;
align-items: center;
justify-content: space-between;
padding-left: 11px;
padding-right: 11px;
}
.Page .ant-dropdown-trigger .anticon {
margin-top: 3px;
}

View File

@@ -1,39 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React from 'react';
import Toolbar from './Toolbar';
import Footer from './Footer';
import Helmet from 'react-helmet';
import favicon from '../pages/logos/favicon.png';
import './Page.css';
require('prismjs/themes/prism.css');
type Props = {|
children: any,
title?: string,
className?: string,
withSpacing?: boolean,
shouldShowFooter?: boolean,
|};
export default (props: Props) => (
<div className={`Page ${props.className || ''}`}>
<Helmet>
<title>{`Yoga Layout${props.title ? ` | ${props.title}` : ''}`}</title>
<link rel="shortcut icon" type="image/png" href={favicon} />
</Helmet>
<Toolbar />
<div className={`PageContent ${props.withSpacing ? 'withSpacing' : ''}`}>
{props.children}
</div>
{props.shouldShowFooter && <Footer />}
</div>
);

View File

@@ -1,201 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// @flow
import yoga from 'yoga-layout/dist/entry-browser';
import LayoutRecord from './LayoutRecord';
import PositionRecord from './PositionRecord';
import type {LayoutRecordT} from './LayoutRecord';
import type {Yoga$Direction, Yoga$Node} from 'yoga-layout';
const enumLookup = {
flexDirection: {
[yoga.FLEX_DIRECTION_COLUMN]: 'CKFlexboxDirectionVertical',
[yoga.FLEX_DIRECTION_ROW]: 'CKFlexboxDirectionHorizontal',
[yoga.FLEX_DIRECTION_COLUMN_REVERSE]: 'CKFlexboxDirectionVerticalReverse',
[yoga.FLEX_DIRECTION_ROW_REVERSE]: 'CKFlexboxDirectionHorizontalReverse',
},
alignItems: {
[yoga.ALIGN_FLEX_START]: 'CKFlexboxAlignItemsStart',
[yoga.ALIGN_FLEX_END]: 'CKFlexboxAlignItemsEnd',
[yoga.ALIGN_CENTER]: 'CKFlexboxAlignItemsCenter',
[yoga.ALIGN_BASELINE]: 'CKFlexboxAlignItemsBaseline',
[yoga.ALIGN_STRETCH]: 'CKFlexboxAlignItemsStretch',
},
alignSelf: {
[yoga.ALIGN_AUTO]: 'CKFlexboxAlignSelfAuto',
[yoga.ALIGN_FLEX_START]: 'CKFlexboxAlignSelfStart',
[yoga.ALIGN_FLEX_END]: 'CKFlexboxAlignSelfEnd',
[yoga.ALIGN_CENTER]: 'CKFlexboxAlignSelfCenter',
[yoga.ALIGN_BASELINE]: 'CKFlexboxAlignSelfBaseline',
[yoga.ALIGN_STRETCH]: 'CKFlexboxAlignSelfStretch',
},
alignContent: {
[yoga.ALIGN_FLEX_START]: 'CKFlexboxAlignContentStart',
[yoga.ALIGN_FLEX_END]: 'CKFlexboxAlignContentEnd',
[yoga.ALIGN_CENTER]: 'CKFlexboxAlignContentCenter',
[yoga.ALIGN_SPACE_BETWEEN]: 'CKFlexboxAlignContentSpaceBetween',
[yoga.ALIGN_SPACE_AROUND]: 'CKFlexboxAlignContentSpaceAround',
[yoga.ALIGN_STRETCH]: 'CKFlexboxAlignContentStretch',
},
justifyContent: {
[yoga.JUSTIFY_FLEX_START]: 'CKFlexboxJustifyContentStart',
[yoga.JUSTIFY_CENTER]: 'CKFlexboxJustifyContentCenter',
[yoga.JUSTIFY_FLEX_END]: 'CKFlexboxJustifyContentEnd',
[yoga.JUSTIFY_SPACE_BETWEEN]: 'CKFlexboxJustifyContentSpaceBetween',
[yoga.JUSTIFY_SPACE_AROUND]: 'CKFlexboxJustifyContentSpaceAround',
},
flexWrap: {
[yoga.WRAP_NO_WRAP]: 'CKFlexboxWrapNoWrap',
[yoga.WRAP_WRAP]: 'CKFlexboxWrapWrap',
[yoga.WRAP_WRAP_REVERSE]: 'CKFlexboxWrapWrapReverse',
},
positionType: {
[yoga.POSITION_TYPE_RELATIVE]: 'CKFlexboxPositionTypeRelative',
[yoga.POSITION_TYPE_ABSOLUTE]: 'CKFlexboxPositionTypeAbsolute',
},
};
const untouchedLayout = LayoutRecord({});
const untouchedPosition = PositionRecord({});
function keyLookup(key: string): string {
const keyLookup = {
flexWrap: 'wrap',
flexDirection: 'direction',
};
return keyLookup[key] || key;
}
function getValue(value) {
if (typeof value === 'string' && /%$/.test(value)) {
return `RCRelativeDimension::Percent(${parseFloat(value)})`;
} else if (value === 'auto') {
return 'RCRelativeDimension::Auto()';
} else {
return String(parseFloat(value));
}
}
function getLayoutCode(
node: LayoutRecordT,
indent: string = '',
isRoot?: boolean,
): string {
const lines = [];
const isFlexbox = node.children.size > 0;
lines.push(
indent +
`${isRoot ? '' : `.component = \n${indent}`}[${
isFlexbox ? 'CKFlexboxComponent' : 'CKComponent'
}`,
);
lines.push(indent + ` newWithView:{}`);
lines.push(
indent + ` size:{${getValue(node.width)},${getValue(node.height)}}`,
);
const CKFlexboxComponentStyle = [
'direction',
'margin',
'justifyContent',
'alignItems',
'alignContent',
'wrap',
'padding',
'border',
];
const CKFlexboxComponentChild = [
'margin',
'padding',
'flexGrow',
'flexShrink',
'flexBasis',
'alignSelf',
'position',
];
if (isFlexbox) {
// render styles
lines.push(indent + ` style:{`);
indent += '\t';
CKFlexboxComponentStyle.forEach(key => {
let line = renderKey(node, key, indent);
if (line) {
lines.push(line);
}
});
indent = indent.substr(-1);
lines.push(indent + ` }`);
// render children
lines.push(indent + ' children:{');
lines.push(
...node.children
.toJSON()
.map(
child =>
`${indent}\t{\n${getLayoutCode(
child,
indent + '\t\t',
)}\n${indent}\t},`,
),
);
lines.push(indent + `}]${isRoot ? ';' : ','}`);
} else {
lines[lines.length - 1] += '],';
CKFlexboxComponentChild.forEach(key => {
let line = renderKey(node, key, indent);
if (line) {
lines.push(line);
}
});
}
return lines.join('\n');
}
function renderKey(node: Yoga$Node, key: string, indent: string): ?string {
if (
node[key] instanceof PositionRecord &&
!node[key].equals(untouchedPosition)
) {
const lines = [];
lines.push(indent + `.${key} = {`);
if (key === 'position') {
lines.push(
indent + `\t.type = ${enumLookup.positionType[node.positionType]},`,
);
}
['top', 'start', 'end', 'bottom'].forEach(pKey => {
if (node[key][pKey]) {
lines.push(indent + `\t.${pKey} = ${getValue(node[key][pKey])},`);
}
});
lines.push(indent + `},`);
return lines.join('\n');
} else if (node[key] !== untouchedLayout[key]) {
if (enumLookup[key]) {
return indent + `.${keyLookup(key)} = ${enumLookup[key][node[key]]},`;
} else {
console.error(`Unknown property ${key}`);
}
}
}
export default function generateCode(
root: LayoutRecordT,
direction: Yoga$Direction,
): string {
return ['CKFlexboxComponent *c =', getLayoutCode(root, '\t', true)].join(
'\n',
);
}

View File

@@ -1,27 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.CodeGeneratorsTitle {
display: flex;
justify-content: space-between;
}
.CodeGeneratorsTitle a {
font-size: 13px;
font-weight: normal;
margin-right: 20px;
}
.CodeGeneratorsCopyText {
position: absolute;
top: -9999em;
left: -9999em;
pointer-events: none;
width: 0;
height: 0;
}

View File

@@ -1,158 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React, {Component} from 'react';
import {Menu, Button, Row, Col, Dropdown, Icon, Modal, Tooltip} from 'antd';
import SyntaxHighlighter, {
registerLanguage,
} from 'react-syntax-highlighter/prism-light';
import styles from 'react-syntax-highlighter/styles/prism/prism';
import CodeJavaScript from './CodeJavaScript';
import CodeLitho from './CodeLitho';
import CodeReactNative from './CodeReactNative';
import CodeComponentKit from './CodeComponentKit';
import jsx from 'react-syntax-highlighter/languages/prism/jsx';
//import javascript from 'react-syntax-highlighter/languages/prism/javascript';
import java from 'react-syntax-highlighter/languages/prism/java';
import objectivec from 'react-syntax-highlighter/languages/prism/objectivec';
registerLanguage('jsx', jsx);
//registerLanguage('javascript', javascript);
registerLanguage('java', java);
registerLanguage('objectivec', objectivec);
import './CodeGenerators.css';
import type {LayoutRecordT} from './LayoutRecord';
import type {Yoga$Direction} from 'yoga-layout';
type Props = {
layoutDefinition: LayoutRecordT,
direction: Yoga$Direction,
};
type State = {
showModal: ?string,
copied: boolean,
};
const LANGUAGES = {
litho: {
title: 'Litho',
generator: CodeLitho,
syntax: 'java',
},
componentKit: {
title: 'ComponentKit',
generator: CodeComponentKit,
syntax: 'objectivec',
},
reactNative: {
title: 'React Native',
generator: CodeReactNative,
syntax: 'jsx',
},
};
['Litho', 'ComponentKit', 'React Native'];
export default class CodeGenerators extends Component<Props, State> {
state = {
showModal: null,
copied: false,
};
_ref: ?HTMLTextAreaElement;
onClick = ({key}: {key: string}) => {
this.setState({showModal: key});
if (window.ga) {
window.ga('send', {
hitType: 'event',
eventCategory: 'CodeGenerators',
eventAction: 'show',
eventLabel: key,
});
}
};
onCopy = () => {
if (this._ref) {
this._ref.select();
document.execCommand('Copy');
this.setState({copied: true});
}
};
render() {
const {showModal} = this.state;
const menu = (
<Menu onClick={this.onClick}>
{Object.keys(LANGUAGES).map(key => (
<Menu.Item key={key}>{LANGUAGES[key].title}</Menu.Item>
))}
</Menu>
);
const code = showModal
? LANGUAGES[showModal].generator(
this.props.layoutDefinition,
this.props.direction,
)
: '';
return [
<Modal
key="modal"
title={
showModal ? (
<div className="CodeGeneratorsTitle">
{LANGUAGES[showModal].title}
<Tooltip
title={this.state.copied ? 'Copied!' : 'Click to copy'}
onVisibleChange={() => this.setState({copied: false})}>
<a onClick={this.onCopy}>copy to clipboard</a>
</Tooltip>
</div>
) : (
''
)
}
visible={Boolean(showModal)}
footer={null}
bodyStyle={{padding: 0}}
onCancel={() => this.setState({showModal: null})}>
{showModal && (
<div>
<textarea
className="CodeGeneratorsCopyText"
value={code}
ref={ref => {
this._ref = ref;
}}
/>
<SyntaxHighlighter
language={LANGUAGES[showModal].syntax}
style={styles}
customStyle={{fontSize: '13px', backgroundColor: 'white'}}
lineNumberStyle={{userSelect: 'none', opacity: 0.5}}
codeTagProps={{style: {tabSize: 4}}}
showLineNumbers>
{code}
</SyntaxHighlighter>
</div>
)}
</Modal>,
<Dropdown overlay={menu} key="dropdown" trigger={['click']}>
<Button>
Get Code <Icon type="down" />
</Button>
</Dropdown>,
];
}
}

View File

@@ -1,138 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import yoga from 'yoga-layout/dist/entry-browser';
import LayoutRecord from './LayoutRecord';
import PositionRecord from './PositionRecord';
import type {LayoutRecordT} from './LayoutRecord';
import type {Yoga$Direction} from 'yoga-layout';
export const JSEnumLookup = {
justifyContent: 'JUSTIFY_',
alignItems: 'ALIGN_',
alignContent: 'ALIGN_',
alignSelf: 'ALIGN_',
position: 'POSITION_',
flexDirection: 'DIRECTION_',
flexWrap: 'WRAP_',
positionType: 'POSITION_TYPE_',
direction: 'DIRECTION_',
};
function getEnum(yogaEnum: string, value: string | number): string {
return `yoga.${
Object.keys(yoga)
.filter(key => key.toLowerCase().startsWith(yogaEnum.toLowerCase()))
.find(key => yoga[key] === value) || value
}`;
}
function setProperty(
name: string,
key: string,
value: string,
enumValue?: string,
): string {
return [
name,
'.set',
key[0].toUpperCase() + key.substr(1),
'(',
enumValue ? `${enumValue}, ` : '',
JSEnumLookup[key] ? getEnum(JSEnumLookup[key], value) : value,
');',
].join('');
}
function getLayoutCode(
node: LayoutRecordT,
name: string,
index: number,
): string {
const lines = [];
const childName = (i: number) => `${name === 'root' ? 'node' : name}_${i}`;
lines.push(
...node.children.map((node, i) => getLayoutCode(node, childName(i), i)),
);
lines.push('', `// create node ${name}`, `const ${name} = Node.create();`);
const untouchedNode = LayoutRecord({width: '', height: ''});
Object.keys(untouchedNode.toJS()).forEach(key => {
if (key !== 'children' && untouchedNode[key] !== node[key]) {
if (node[key] instanceof PositionRecord) {
// iterate through position record
const {top, left, right, bottom} = node[key].toJS();
if (
top !== untouchedNode[key].top &&
top === left &&
top === right &&
top === bottom
) {
// all edges
lines.push(setProperty(name, key, node[key].top, getEnum('edge', 8)));
return;
}
const alreadySet = [];
if (top !== untouchedNode[key].top && top === bottom) {
lines.push(setProperty(name, key, node[key].top, getEnum('edge', 7)));
alreadySet.push('top', 'bottom');
}
if (left !== untouchedNode[key].left && left === right) {
lines.push(
setProperty(name, key, node[key].left, getEnum('edge', 6)),
);
alreadySet.push('left', 'right');
}
['left', 'top', 'right', 'bottom'].forEach((pKey, i) => {
if (
node[key][pKey] !== untouchedNode[key][pKey] &&
alreadySet.indexOf(pKey) === -1
) {
lines.push(
setProperty(name, key, node[key][pKey], getEnum('edge', i)),
);
}
});
} else {
lines.push(setProperty(name, key, node[key]));
}
}
});
if (node.children && node.children.size > 0) {
lines.push(
'',
'// insert children',
...node.children.map(
(_, i) => `${name}.insertChild(${childName(i)}, ${i});`,
),
);
}
return lines.join('\n');
}
export default function generateCode(
root: LayoutRecordT,
direction: Yoga$Direction,
): string {
const rootNodeName = 'root';
return [
`import yoga, {Node} from 'yoga-layout';`,
getLayoutCode(root, rootNodeName, 0),
'',
`${rootNodeName}.calculateLayout(${root.width}, ${root.height}, ${getEnum(
'direction',
direction,
)});`,
`${rootNodeName}.getComputedLayout();`,
].join('\n');
}

View File

@@ -1,219 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import yoga from 'yoga-layout/dist/entry-browser';
import LayoutRecord from './LayoutRecord';
import PositionRecord from './PositionRecord';
import {JSEnumLookup} from './CodeJavaScript';
import type {LayoutRecordT} from './LayoutRecord';
import type {Yoga$Direction} from 'yoga-layout';
function getEnum(yogaEnum: string, value: string | number): string {
const enumLookup = {
justifyContent: 'Justify',
alignItems: 'Align',
alignContent: 'Align',
alignSelf: 'Align',
position: 'Position',
flexWrap: 'Wrap',
positionType: 'PositionType',
direction: 'Direction',
};
if (!enumLookup[yogaEnum]) {
return String(value);
} else {
const enumValue = Object.keys(yoga)
.filter(key =>
key.toLowerCase().startsWith(JSEnumLookup[yogaEnum].toLowerCase()),
)
.find(key => yoga[key] === value);
return `Yoga${enumLookup[yogaEnum]}.${
enumValue ? enumValue.replace(/^([A-Z]+)_/, '') : value
}`;
}
}
function dipOrPercent(value) {
console.log(value);
return value === 'auto'
? 'Auto'
: typeof value === 'string' && /%$/.test(value)
? 'Percent'
: 'Dip';
}
function getValue(value) {
return value === 'auto' ? '' : `, ${parseFloat(value)}`;
}
function getLayoutCode(
node: LayoutRecordT,
indent: string = '',
isReturning?: boolean,
): string {
const lines = [];
const flexDirection = {
[yoga.FLEX_DIRECTION_ROW]: 'Row',
[yoga.FLEX_DIRECTION_ROW_REVERSE]: 'RowReverse',
[yoga.FLEX_DIRECTION_COLUMN]: 'Column',
[yoga.FLEX_DIRECTION_COLUMN_REVERSE]: 'ColumnReverse',
};
lines.push(
indent +
`${isReturning ? 'return ' : ''}${
flexDirection[node.flexDirection]
}.create(c)`,
);
if (node.children.size > 0) {
lines.push(
...node.children
.toJSON()
.map(
child =>
`${indent}\t.child(\n${getLayoutCode(child, indent + '\t\t')})`,
),
);
}
const untouchedLayout = LayoutRecord();
const untouchedPosition = PositionRecord({});
Object.keys(node.toJSON()).forEach(key => {
if (
node[key] instanceof PositionRecord &&
!node[key].equals(untouchedPosition)
) {
if (key === 'border') {
lines.push(indent + '\t.border(', indent + '\t\tBorder.create(c)');
}
const {top, left, right, bottom} = node[key].toJS();
if (
top !== untouchedPosition.top &&
top === left &&
top === right &&
top === bottom
) {
// all edges
lines.push(
indent +
(key === 'border'
? `\t\t\t.width${dipOrPercent(
node[key].top,
)}(YogaEdge.ALL${getValue(node[key].top)})`
: `\t.${key}${dipOrPercent(node[key].top)}(YogaEdge.ALL${getValue(
node[key].top,
)})`),
);
return;
}
const alreadySet = [];
if (top !== untouchedPosition.top && top === bottom) {
lines.push(
indent +
(key === 'border'
? `\t\t\t.width${dipOrPercent(
node[key].top,
)}(YogaEdge.VERTICAL${getValue(node[key].top)})`
: `\t.${key}${dipOrPercent(
node[key].top,
)}(YogaEdge.VERTICAL${getValue(node[key].top)})`),
);
alreadySet.push('top', 'bottom');
}
if (left !== untouchedPosition.left && left === right) {
lines.push(
indent +
(key === 'border'
? `\t\t\t.width${dipOrPercent(
node[key].left,
)}(YogaEdge.HORIZONTAL${getValue(node[key].left)})`
: `\t.${key}${dipOrPercent(
node[key].left,
)}(YogaEdge.HORIZONTAL${getValue(node[key].left)})`),
);
alreadySet.push('left', 'right');
}
['left', 'top', 'right', 'bottom'].forEach((pKey, i) => {
if (
node[key][pKey] !== untouchedPosition[pKey] &&
alreadySet.indexOf(pKey) === -1 &&
node[key][pKey]
) {
lines.push(
indent +
(key === 'border'
? `\t\t\t.width${dipOrPercent(
node.border[pKey],
)}(YogaEdge.${pKey.toUpperCase()}${getValue(
node.border[pKey],
)})`
: `\t.${key}${dipOrPercent(
node[key][pKey],
)}(YogaEdge.${pKey.toUpperCase()}${getValue(
node[key][pKey],
)})`),
);
}
});
if (key === 'border') {
lines.push(
indent + '\t\t\t.color(YogaEdge.ALL, 0xfff36b7f)',
indent + '\t\t\t.build())',
);
}
} else if (
key !== 'children' &&
key !== 'flexDirection' &&
node[key] !== untouchedLayout[key] &&
node[key]
) {
if (node[key] === 'auto') {
lines.push(indent + `\t.${key}Auto(${getEnum(key, node[key])})`);
} else if (typeof node[key] === 'string' && /%$/.test(node[key])) {
lines.push(indent + `\t.${key}Percent(${parseFloat(node[key])})`);
} else if (
[
'width',
'height',
'minHeight',
'maxHeight',
'minWidth',
'maxWidth',
'flexBasis',
].indexOf(key) > -1
) {
lines.push(indent + `\t.${key}Dip(${getEnum(key, node[key])})`);
} else {
lines.push(indent + `\t.${key}(${getEnum(key, node[key])})`);
}
}
});
return lines.join('\n');
}
export default function generateCode(
root: LayoutRecordT,
direction: Yoga$Direction,
): string {
return [
'@LayoutSpec',
'public class PlaygroundComponentSpec {',
'\t@OnCreateLayout',
'\tstatic Component onCreateLayout(ComponentContext c) {',
getLayoutCode(root, '\t\t', true),
'\t\t\t.build();',
'\t}',
'}',
].join('\n');
}

View File

@@ -1,151 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import yoga from 'yoga-layout/dist/entry-browser';
import LayoutRecord from './LayoutRecord';
import PositionRecord from './PositionRecord';
import {JSEnumLookup} from './CodeJavaScript';
import type {LayoutRecordT} from './LayoutRecord';
import type {Yoga$Direction} from 'yoga-layout';
function getValue(value) {
return typeof value === 'number' || /^\d+$/.test(value)
? String(value)
: `'${value}'`;
}
function getEnum(yogaEnum: string, value: string | number): string {
console.log(yogaEnum);
const enumValue = Object.keys(yoga)
.filter(
key =>
JSEnumLookup[yogaEnum] &&
key.toLowerCase().startsWith(JSEnumLookup[yogaEnum].toLowerCase()),
)
.find(key => yoga[key] === value);
return enumValue
? "'" +
enumValue
.replace(/^([A-Z]+)_/, '')
.replace('_', '-')
.toLowerCase() +
"'"
: getValue(value);
}
function getLayoutCode(node: LayoutRecordT, indent: string = ''): string {
const lines = [];
const untouchedLayout = LayoutRecord();
lines.push(indent + '<View style={{');
lines.push(indent + ' flex: 1,');
Object.keys(node.toJSON()).forEach(key => {
if (key === 'border' && !node.border.equals(untouchedLayout[key])) {
['Top', 'Left', 'Right', 'Bottom'].forEach(pKey => {
if (
untouchedLayout[key][pKey.toLowerCase()] !==
node.border[pKey.toLowerCase()]
) {
lines.push(
indent +
` border${pKey}Width: ${getValue(
node.border[pKey.toLowerCase()],
)},`,
);
}
});
} else if (
node[key] instanceof PositionRecord &&
!node[key].equals(untouchedLayout[key])
) {
const {top, left, right, bottom} = node[key].toJS();
if (
top &&
top !== untouchedLayout[key].top &&
top === left &&
top === right &&
top === bottom
) {
// all edges
lines.push(indent + ` ${key}: ${node[key].top},`);
return;
}
const alreadySet = [];
if (top && top !== untouchedLayout[key].top && top === bottom) {
lines.push(indent + ` ${key}Vertical: ${getValue(node[key].top)},`);
alreadySet.push('top', 'bottom');
}
if (left && left !== untouchedLayout[key].left && left === right) {
lines.push(indent + ` ${key}Horizontal: ${getValue(node[key].left)},`);
alreadySet.push('left', 'right');
}
['left', 'top', 'right', 'bottom'].forEach((pKey, i) => {
if (
node[key][pKey] !== untouchedLayout[key][pKey] &&
alreadySet.indexOf(pKey) === -1 &&
node[key][pKey] &&
!Number.isNaN(node[key][pKey])
) {
lines.push(
indent +
` ${key}${pKey[0].toUpperCase()}${pKey.substr(1)}: ${getValue(
node[key][pKey],
)},`,
);
}
});
} else if (
key === 'positionType' &&
node[key] === yoga.POSITION_TYPE_ABSOLUTE
) {
lines.push(indent + ` position: 'absolute',`);
} else if (
key !== 'children' &&
node[key] !== untouchedLayout[key] &&
node[key]
) {
lines.push(indent + ` ${key}: ${getEnum(key, node[key])},`);
}
});
if (node.children.size > 0) {
lines.push(indent + '}}>');
} else {
lines.push(indent + '}} />');
}
if (node.children.size > 0) {
lines.push(
...node.children
.toJSON()
.map(child => getLayoutCode(child, indent + ' ')),
);
}
if (node.children.size > 0) {
lines.push(indent + '</View>');
}
return lines.join('\n');
}
export default function generateCode(
root: LayoutRecordT,
direction: Yoga$Direction,
): string {
return [
`import React, {Component} from 'react';`,
`import {View} from 'react-native';`,
'',
'export default class MyLayout extends Component {',
' render() {',
' return (',
getLayoutCode(root, ' '),
' );',
' }',
'};',
].join('\n');
}

View File

@@ -1,42 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React, {Component} from 'react';
import YogaEnumSelect from './YogaEnumSelect';
import YogaPositionEditor from './YogaPositionEditor';
import {Input} from 'antd';
type Props<T> = {
property: string,
disabled?: boolean,
value?: ?T,
onChange: (property: string, value: T) => void,
};
export default (props: Props<*>) => {
if (YogaEnumSelect.availableProperties.indexOf(props.property) > -1) {
return <YogaEnumSelect {...props} />;
} else if (
YogaPositionEditor.availableProperties.indexOf(props.property) > -1
) {
return <YogaPositionEditor {...props} />;
} else {
return (
<Input
type="text"
{...props}
onChange={e => props.onChange(props.property, e.target.value)}
placeholder={props.placeholder || 'undefined'}
onFocus={e => e.target.select()}
value={Number.isNaN(props.value) ? '' : props.value}
/>
);
}
};

View File

@@ -1,63 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.Editor {
display: flex;
flex-direction: column;
height: 100%;
border-top: 1px solid #E8E8E8;
}
.Editor .field {
display: flex;
}
.Editor .ant-btn {
width: 100%;
}
.Editor h2 {
margin-bottom: 8px;
margin-top: 20px;
font-size: 12px;
font-weight: 700;
color: #444950;
text-transform: uppercase;
}
.Editor h2:first-child {
margin-top: 0;
}
.Editor .ant-tabs-nav .ant-tabs-tab {
margin-left: 16px;
}
.Editor .EditorTabs {
flex-grow: 1;
}
.Editor .ant-tabs {
display: flex;
flex-direction: column;
}
.Editor .ant-tabs-bar {
margin-bottom: 0;
}
.Editor .ant-tabs-tabpane {
overflow-y: auto;
min-height: 320px;
height: 100%;
max-height: 25vh;
padding: 15px;
}
.Editor .EditorButtons {
padding: 15px;
}

View File

@@ -1,356 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React, {Component} from 'react';
import {Row, Col, Button, Tabs} from 'antd';
import EditValue from './EditValue';
import type {LayoutRecordT} from './LayoutRecord';
import type {Yoga$Direction} from 'yoga-layout';
import InfoText from './InfoText';
import './Editor.css';
const TabPane = Tabs.TabPane;
type Props = {
node: ?LayoutRecordT,
onChangeLayout: (key: string, value: any) => void,
onChangeSetting: (key: string, value: any) => void,
direction: Yoga$Direction,
selectedNodeIsRoot: boolean,
onRemove?: () => void,
onAdd?: () => void,
};
export default class Editor extends Component<Props> {
componentDidMount() {
document.addEventListener('keydown', this.onKeyDown);
}
componentWillUnmount() {
document.removeEventListener('keydown', this.onKeyDown);
}
onKeyDown = (e: KeyboardEvent) => {
if (
(e.key === 'Delete' || e.key === 'Backspace') &&
this.props.onRemove &&
!(e.target instanceof HTMLInputElement)
) {
this.props.onRemove();
}
};
render() {
const {node, selectedNodeIsRoot} = this.props;
const disabled = !Boolean(node);
return (
<div className="Editor">
<Tabs defaultActiveKey="1" className="EditorTabs">
<TabPane tab="Flex" key="1">
<h2>
Direction
<InfoText doclink="/docs/layout-direction">
Defines the direction of which text and items are laid out
</InfoText>
</h2>
<EditValue
property="direction"
value={this.props.direction}
onChange={this.props.onChangeSetting}
/>
<h2>
Flex Direction
<InfoText doclink="/docs/flex-direction">
Defines the direction of the main-axis
</InfoText>
</h2>
<EditValue
disabled={disabled}
property="flexDirection"
value={node ? node.flexDirection : undefined}
onChange={this.props.onChangeLayout}
/>
<Row gutter={15} style={{marginTop: 30}}>
<Col span={8}>
<h2>
Basis
<InfoText doclink="/docs/flex">
Default size of a node along the main axis
</InfoText>
</h2>
<EditValue
type="text"
property="flexBasis"
placeholder="auto"
disabled={disabled || selectedNodeIsRoot}
value={node ? node.flexBasis : undefined}
onChange={this.props.onChangeLayout}
/>
</Col>
<Col span={8}>
<h2>
Grow
<InfoText doclink="/docs/flex">
The factor of remaining space should be given to this node
</InfoText>
</h2>
<EditValue
type="text"
property="flexGrow"
placeholder="0"
disabled={disabled || selectedNodeIsRoot}
value={node ? node.flexGrow : undefined}
onChange={this.props.onChangeLayout}
/>
</Col>
<Col span={8}>
<h2>
Shrink
<InfoText doclink="/docs/flex">
The shrink factor of this element if parent has no space
left
</InfoText>
</h2>
<EditValue
type="text"
property="flexShrink"
placeholder="1"
disabled={disabled || selectedNodeIsRoot}
value={node ? node.flexShrink : undefined}
onChange={this.props.onChangeLayout}
/>
</Col>
</Row>
<h2>
Flex Wrap
<InfoText doclink="/docs/flex-wrap">
Wrapping behaviour when child nodes don't fit into a single line
</InfoText>
</h2>
<EditValue
disabled={disabled}
property="flexWrap"
value={node ? node.flexWrap : undefined}
onChange={this.props.onChangeLayout}
/>
</TabPane>
<TabPane tab="Alignment" key="2">
<h2>
Justify Content
<InfoText doclink="/docs/justify-content">
Aligns child nodes along the main-axis
</InfoText>
</h2>
<EditValue
disabled={disabled}
property="justifyContent"
value={node ? node.justifyContent : undefined}
onChange={this.props.onChangeLayout}
/>
<h2>
Align Items
<InfoText doclink="/docs/align-items">
Aligns child nodes along the cross-axis
</InfoText>
</h2>
<EditValue
disabled={disabled}
property="alignItems"
value={node ? node.alignItems : undefined}
onChange={this.props.onChangeLayout}
/>
<h2>
Align Self
<InfoText doclink="/docs/align-items">
Override align items of parent
</InfoText>
</h2>
<EditValue
disabled={disabled || selectedNodeIsRoot}
property="alignSelf"
value={node ? node.alignSelf : undefined}
onChange={this.props.onChangeLayout}
/>
<h2>
Align Content
<InfoText doclink="/docs/align-content">
Alignment of lines along the cross-axis when wrapping
</InfoText>
</h2>
<EditValue
disabled={disabled}
property="alignContent"
value={node ? node.alignContent : undefined}
onChange={this.props.onChangeLayout}
/>
</TabPane>
<TabPane tab="Layout" key="3" className="ant-tabs-tabpane">
<h2>
Width &times; Height
<InfoText doclink="/docs/width-height">
Dimensions of the node
</InfoText>
</h2>
<Row gutter={15}>
<Col span={12}>
<EditValue
type="text"
placeholder="auto"
property="width"
disabled={disabled}
value={node ? node.width : undefined}
onChange={this.props.onChangeLayout}
/>
</Col>
<Col span={12}>
<EditValue
type="text"
placeholder="auto"
property="height"
disabled={disabled}
value={node ? node.height : undefined}
onChange={this.props.onChangeLayout}
/>
</Col>
</Row>
<h2>
Max-Width &times; Max-Height
<InfoText doclink="/docs/min-max">
Maximum dimensions of the node
</InfoText>
</h2>
<Row gutter={15}>
<Col span={12}>
<EditValue
type="text"
placeholder="none"
property="maxWidth"
disabled={disabled}
value={node ? node.maxWidth : undefined}
onChange={this.props.onChangeLayout}
/>
</Col>
<Col span={12}>
<EditValue
type="text"
placeholder="none"
property="maxHeight"
disabled={disabled}
value={node ? node.maxHeight : undefined}
onChange={this.props.onChangeLayout}
/>
</Col>
</Row>
<h2>
Min-Width &times; Min-Height
<InfoText doclink="/docs/min-max">
Minimum dimensions of the node
</InfoText>
</h2>
<Row gutter={15}>
<Col span={12}>
<EditValue
type="text"
placeholder="0"
property="minWidth"
disabled={disabled}
value={node ? node.minWidth : undefined}
onChange={this.props.onChangeLayout}
/>
</Col>
<Col span={12}>
<EditValue
type="text"
placeholder="0"
property="minHeight"
disabled={disabled}
value={node ? node.minHeight : undefined}
onChange={this.props.onChangeLayout}
/>
</Col>
</Row>
<h2>
Aspect Ratio
<InfoText doclink="/docs/aspect-ratio">
Width/Height aspect ratio of node
</InfoText>
</h2>
<EditValue
type="text"
placeholder="auto"
property="aspectRatio"
disabled={disabled}
value={node ? node.aspectRatio : undefined}
onChange={this.props.onChangeLayout}
/>
{['padding', 'border', 'margin'].map(property => (
<EditValue
property={property}
key={property}
value={node ? node[property] : undefined}
onChange={this.props.onChangeLayout}
disabled={property === 'margin' && selectedNodeIsRoot}
/>
))}
<h2>
Position Type
<InfoText doclink="/docs/absolute-relative-layout">
Relative position offsets the node from it's calculated
position. Absolute position removes the node from the flexbox
flow and positions it at the given position.
</InfoText>
</h2>
<EditValue
disabled={disabled || selectedNodeIsRoot}
property="positionType"
value={node ? node.positionType : undefined}
onChange={this.props.onChangeLayout}
/>
<EditValue
disabled={selectedNodeIsRoot}
property="position"
value={node ? node.position : undefined}
onChange={this.props.onChangeLayout}
/>
</TabPane>
</Tabs>
<Row gutter={15} className="EditorButtons">
<Col span={12}>
<Button
icon="plus-circle-o"
disabled={!Boolean(this.props.onAdd)}
onClick={this.props.onAdd}
type="primary">
add child node
</Button>
</Col>
<Col span={12}>
<Button
icon="close-circle-o"
disabled={!Boolean(this.props.onRemove)}
onClick={this.props.onRemove}
type="danger">
remove node
</Button>
</Col>
</Row>
</div>
);
}
}

View File

@@ -1,22 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.InfoText {
max-width: 230px;
line-height: 130%;
}
.InfoText .docs-link {
margin-top: 0px;
font-size: 12px;
font-weight: 600;
}
.InfoTextIcon {
margin-left: 5px;
opacity: 0.5;
}

View File

@@ -1,38 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React, {Component} from 'react';
import {Popover, Icon} from 'antd';
import Link from 'gatsby-link';
import './InfoText.css';
type Props = {
children: any,
doclink: string,
};
export default class InfoText extends Component<Props> {
render() {
return (
<Popover
content={
<div className="InfoText">
<p>{this.props.children}</p>
<Link className="docs-link" to={this.props.doclink}>
DOCUMENTATION
</Link>
</div>
}
trigger="hover">
<Icon className="InfoTextIcon" type="info-circle-o" />
</Popover>
);
}
}

View File

@@ -1,89 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import {Record, List} from 'immutable';
import type {RecordOf} from 'immutable';
import PositionRecord from './PositionRecord';
import type {PositionRecordT} from './PositionRecord';
import yoga from 'yoga-layout/dist/entry-browser';
import type {
Yoga$Align,
Yoga$Justify,
Yoga$FlexDirection,
Yoga$Wrap,
Yoga$PositionType,
} from 'yoga-layout';
export type LayoutRecordT = RecordOf<{
width?: ?number,
height?: ?number,
minWidth?: ?number,
minHeight?: ?number,
maxWidth?: ?number,
maxHeight?: ?number,
justifyContent?: Yoga$Justify,
padding: PositionRecordT,
border: PositionRecordT,
margin: PositionRecordT,
position: PositionRecordT,
positionType: Yoga$PositionType,
alignItems?: Yoga$Align,
alignSelf?: Yoga$Align,
alignContent?: Yoga$Align,
flexDirection?: Yoga$FlexDirection,
flexBasis?: number | 'auto',
flexGrow?: number,
flexShrink?: number,
padding?: number,
flexWrap?: Yoga$Wrap,
aspectRatio?: number,
children?: List<LayoutRecordT>,
minWidth?: number,
maxWidth?: number,
minHeight?: number,
maxHeight?: number,
}>;
const r: LayoutRecordT = Record({
width: 'auto',
height: 'auto',
minWidth: 0,
minHeight: 0,
maxWidth: 'none',
maxHeight: 'none',
justifyContent: yoga.JUSTIFY_FLEX_START,
alignItems: yoga.ALIGN_STRETCH,
alignSelf: yoga.ALIGN_AUTO,
alignContent: yoga.ALIGN_STRETCH,
flexDirection: yoga.FLEX_DIRECTION_ROW,
padding: PositionRecord(),
margin: PositionRecord(),
border: PositionRecord(),
position: PositionRecord({
left: NaN,
top: NaN,
right: NaN,
bottom: NaN,
}),
positionType: yoga.POSITION_TYPE_RELATIVE,
flexWrap: yoga.WRAP_NO_WRAP,
flexBasis: 'auto',
flexGrow: 0,
flexShrink: 1,
children: List(),
aspectRatio: 'auto',
minWidth: NaN,
maxWidth: NaN,
minHeight: NaN,
maxHeight: NaN,
});
export default r;

View File

@@ -1,16 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.PositionGuide {
position: absolute;
pointer-events: none;
display: flex;
align-items: center;
justify-content: center;
font-size: 10px;
user-select: none;
}

View File

@@ -1,146 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React, {Component} from 'react';
import PositionRecord from './PositionRecord';
import type {PositionRecordT} from './PositionRecord';
import './PositionGuide.css';
type Props = {
inset?: boolean,
reverse?: boolean,
position: PositionRecordT,
offset: PositionRecordT,
color: string,
};
export default class PositionGuide extends Component<Props> {
static defaultProps = {
offset: PositionRecord({}),
};
render() {
const {position, offset, inset, color, reverse} = this.props;
let {top, left, right, bottom} = position;
let {top: oTop, left: oLeft, right: oRight, bottom: oBottom} = offset;
if (reverse) {
let temp1 = left;
left = right;
right = temp1;
temp1 = oLeft;
oLeft = oRight;
oRight = temp1;
}
if (!top) {
top = 0;
}
if (!left) {
left = 0;
}
if (!right) {
right = 0;
}
if (!bottom) {
bottom = 0;
}
if (!oTop) {
oTop = 0;
}
if (!oLeft) {
oLeft = 0;
}
if (!oRight) {
oRight = 0;
}
if (!oBottom) {
oBottom = 0;
}
if (!inset) {
if (top < 0) {
bottom -= top;
top = 0;
}
if (bottom < 0) {
top -= bottom;
bottom = 0;
}
if (left < 0) {
right -= left;
left = 0;
}
if (right < 0) {
left -= right;
right = 0;
}
}
return [
top !== 0 ? (
<div
key="top"
className="PositionGuide"
style={{
backgroundColor: color,
height: top,
top: inset ? oTop : -top - oTop,
left: inset ? left + oLeft : -left - oLeft,
right: inset ? right + oRight : -right - oRight,
}}>
{top}
</div>
) : null,
left !== 0 ? (
<div
key="left"
className="PositionGuide"
style={{
backgroundColor: color,
width: left,
top: inset ? oTop : -oTop,
bottom: inset ? oBottom : -oBottom,
left: inset ? oLeft : -left - oLeft,
}}>
{left}
</div>
) : null,
right !== 0 ? (
<div
key="right"
className="PositionGuide"
style={{
backgroundColor: color,
width: right,
top: inset ? oTop : -oTop,
bottom: inset ? oBottom : -oBottom,
right: inset ? oRight : -right - oRight,
}}>
{right}
</div>
) : null,
bottom !== 0 ? (
<div
key="bottom"
className="PositionGuide"
style={{
backgroundColor: color,
height: bottom,
bottom: inset ? oBottom : -bottom - oBottom,
left: inset ? left + oLeft : -left - oLeft,
right: inset ? right + oRight : -right - oRight,
}}>
{bottom}
</div>
) : null,
];
}
}

View File

@@ -1,28 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import {Record} from 'immutable';
import type {RecordOf} from 'immutable';
export type PositionRecordT = RecordOf<{
top: string | number,
right: string | number,
bottom: string | number,
left: string | number,
}>;
const r: PositionRecordT = Record({
top: 0,
right: 0,
bottom: 0,
left: 0,
});
export default r;

View File

@@ -1,22 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.Sidebar {
position: absolute;
z-index: 3;
top: 0;
right: 0;
width: 350px;
background: white;
display: flex;
flex-direction: column;
margin: 25px;
max-height: calc(100% - 50px);
border-radius: 6px;
bottom: auto;
box-shadow: 3px 3px 15px rgba(0, 0, 0, 0.15);
}

View File

@@ -1,27 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React, {Component} from 'react';
import './Sidebar.css';
type Props = {
width?: number,
children: any,
};
export default class Sidebar extends Component<Props> {
render() {
return (
<div className="Sidebar" style={{width: this.props.width}}>
{this.props.children}
</div>
);
}
}

View File

@@ -1,9 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.URLShortener {
}

View File

@@ -1,86 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React, {Component} from 'react';
import {Tooltip, notification, Button, Input} from 'antd';
import './URLShortener.css';
type State = {
shortURL: ?string,
loading: boolean,
};
export default class URLShortener extends Component<{}, State> {
_ref: ?HTMLElement = null;
state = {
loading: false,
shortURL: null,
};
componentDidMount() {
window.addEventListener('popstate', this.onHashChange);
}
componentWillUnmount() {
window.removeEventListener('popstate', this.onHashChange);
}
onHashChange = () => {
this.setState({shortURL: null});
};
onClick = () => {
this.setState(
{
loading: true,
},
() => {
if (window.ga) {
window.ga('send', {
hitType: 'event',
eventCategory: 'URLShortener',
eventAction: 'created',
});
}
fetch(
`https://cors-anywhere.herokuapp.com/tinyurl.com/api-create.php?url=${window.location.href}`,
)
.then(res => res.text())
.then(shortURL => this.setState({shortURL, loading: false}))
.catch(() => this.setState({shortURL: null, loading: false}));
},
);
};
render() {
return this.state.shortURL ? (
<Input
value={this.state.shortURL}
autoFocus
ref={ref => {
if (ref) {
ref.input.select();
}
}}
/>
) : (
<Button
className="URLShortener"
onClick={this.onClick}
icon="share-alt"
disabled={this.state.loading}
type="primary">
Share URL
</Button>
);
}
}

View File

@@ -1,25 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.YogaEnumSelect {
display: flex;
}
.YogaEnumSelect.ant-radio-group .ant-radio-button-wrapper {
flex-grow: 1;
flex-basis: 0;
text-align: center;
}
.YogaEnumSelect .ant-btn {
flex-grow: 1;
flex-basis: 0;
}
.YogaEnumSelect .ant-radio-button-wrapper {
white-space: nowrap;
}

View File

@@ -1,104 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React, {Component} from 'react';
import yoga from 'yoga-layout/dist/entry-browser';
import {Radio, Menu, Dropdown, Button, Icon} from 'antd';
import './YogaEnumSelect.css';
const RadioButton = Radio.Button;
const RadioGroup = Radio.Group;
const PROPERTY_LOOKUP = {
flexDirection: 'FLEX_DIRECTION',
direction: 'DIRECTION',
justifyContent: 'JUSTIFY',
alignSelf: 'ALIGN',
alignContent: 'ALIGN',
alignItems: 'ALIGN',
positionType: 'POSITION_TYPE',
flexWrap: 'WRAP',
};
type Property = $Keys<typeof PROPERTY_LOOKUP>;
type Props = {
property: Property,
disabled?: boolean,
value: string | number,
onChange: (property: Property, value: number) => void,
};
export default class YogaEnumSelect extends Component<Props> {
static availableProperties = Object.keys(PROPERTY_LOOKUP);
values: Array<{key: string, value: number}>;
constructor({property}: Props) {
super();
property = PROPERTY_LOOKUP[property];
// $FlowFixMe
this.values = Object.keys(yoga)
.map(key => ({key, value: yoga[key]}))
.filter(
({key}) => key.startsWith(property) && key !== `${property}_COUNT`,
);
}
handleMenuClick = ({key}: {key: string}) => {
this.props.onChange(this.props.property, yoga[key]);
};
getTitle = (property: string, key: string): string => {
const replacer = new RegExp(`^${property}_`);
return key.replace(replacer, '').replace('_', ' ').toLowerCase();
};
render() {
let {property, ...props} = this.props;
property = PROPERTY_LOOKUP[property];
const selected = this.values.find(
({key, value}) => value === this.props.value,
);
return this.values.length > 3 ? (
<div className="YogaEnumSelect">
<Dropdown
trigger={['click']}
disabled={props.disabled}
overlay={
<Menu onClick={this.handleMenuClick}>
{this.values.map(({key, value}) => (
<Menu.Item key={key} value={value}>
{this.getTitle(property, key)}
</Menu.Item>
))}
</Menu>
}>
<Button>
{selected ? this.getTitle(property, selected.key) : ''}
<Icon type="down" />
</Button>
</Dropdown>
</div>
) : (
<RadioGroup
{...props}
onChange={e => this.props.onChange(this.props.property, e.target.value)}
defaultValue="a"
className="YogaEnumSelect">
{this.values.map(({key, value}) => (
<RadioButton key={key} value={value}>
{this.getTitle(property, key)}
</RadioButton>
))}
</RadioGroup>
);
}
}

View File

@@ -1,57 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.YogaNode {
background: white;
position: absolute;
transform: scale(1);
box-shadow: inset 0 0 0px 1px rgba(48, 56, 69, 0.2);
transition: 0.2s all, 0s outline, 0s box-shadow;
cursor: pointer;
}
.YogaNode.hover {
background-color: #F0FFF9;
}
.YogaNode .YogaNode {
background: rgba(255, 255, 255, 0.7);
}
.YogaNode .YogaNode.hover{
background: rgba(240, 255, 249, 0.7);
}
.YogaNode:focus {
outline: 0;
}
.YogaNode.focused {
box-shadow: 0 0 0 2px #68CFBB, 0 0 15px rgba(0, 0, 0, 0.2),
inset 0 0 0px 1px rgba(255, 255, 255, 0.2);
z-index: 2;
}
.YogaNode.invisible {
transform: scale(0);
}
.YogaNode .label {
user-select: none;
pointer-events: none;
position: absolute;
left: 0;
bottom: 0;
right: 0;
top: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
font-weight: 300;
letter-spacing: 1px;
}

View File

@@ -1,296 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React, {Component} from 'react';
import yoga, {Node} from 'yoga-layout/dist/entry-browser';
import PositionGuide from './PositionGuide';
import PositionRecord from './PositionRecord';
import LayoutRecord from './LayoutRecord';
import type {LayoutRecordT} from './LayoutRecord';
import type {Yoga$Direction, Yoga$Node} from 'yoga-layout';
import './YogaNode.css';
type ComputedLayout = {|
left: number,
top: number,
width: number,
height: number,
children: Array<ComputedLayout>,
node: Yoga$Node,
|};
type Props = {|
layoutDefinition: LayoutRecordT,
className?: string,
computedLayout?: ComputedLayout,
path: Array<number>,
selectedNodePath?: ?Array<number>,
direction?: Yoga$Direction,
label?: string,
showGuides: boolean,
onClick?: (path: Array<number>) => void,
onDoubleClick?: (path: Array<number>) => void,
|};
type State = {
visible?: boolean,
hovered: boolean,
};
export default class YogaNode extends Component<Props, State> {
node: Yoga$Node;
static defaultProps = {
path: [],
label: 'root',
showGuides: true,
};
state = {
hovered: false,
};
computedLayout: ?ComputedLayout;
rootNode: ?Yoga$Node;
constructor(props: Props) {
super();
if (!props.computedLayout) {
// is root node
this.calculateLayout(props);
this.state = {
visible: !Boolean(props.computedLayout),
};
}
}
componentDidMount() {
setTimeout(() => this.setState({visible: true}), 200);
}
componentWillReceiveProps(nextProps: Props) {
if (
!nextProps.computedLayout &&
(!this.props.layoutDefinition.equals(nextProps.layoutDefinition) ||
this.props.direction !== nextProps.direction)
) {
// is root node and the layout definition or settings changed
this.calculateLayout(nextProps);
}
}
componentWillUnmount() {
if (this.rootNode) {
this.rootNode.freeRecursive();
}
}
onMouseMove = e => {
this.setState({hovered: e.target === this._ref});
};
calculateLayout(props: Props) {
const root = this.createYogaNodes(props.layoutDefinition);
root.calculateLayout(
props.layoutDefinition.width,
props.layoutDefinition.height,
props.direction,
);
this.computedLayout = this.getComputedLayout(root);
this.rootNode = root;
}
createYogaNodes = (layoutDefinition: LayoutRecordT): Yoga$Node => {
const root = Node.create();
const defaultLayout = LayoutRecord({});
[
'width',
'height',
'minWidth',
'maxWidth',
'minHeight',
'maxHeight',
'justifyContent',
'alignItems',
'alignSelf',
'alignContent',
'flexGrow',
'flexShrink',
'positionType',
'aspectRatio',
'flexWrap',
'flexDirection',
].forEach(key => {
try {
const value =
layoutDefinition[key] === ''
? defaultLayout[key]
: layoutDefinition[key];
root[`set${key[0].toUpperCase()}${key.substr(1)}`](value);
} catch (e) {}
});
['padding', 'margin', 'position', 'border'].forEach(key => {
['top', 'right', 'bottom', 'left'].forEach(direction => {
try {
root[`set${key[0].toUpperCase()}${key.substr(1)}`](
yoga[`EDGE_${direction.toUpperCase()}`],
layoutDefinition[key][direction],
);
} catch (e) {}
});
});
root.setDisplay(yoga.DISPLAY_FLEX);
(layoutDefinition.children || [])
.map(this.createYogaNodes)
.forEach((node, i) => {
root.insertChild(node, i);
});
return root;
};
getComputedLayout = (node: Yoga$Node): ComputedLayout => {
return {
...node.getComputedLayout(),
node,
children: Array.apply(null, Array(node.getChildCount())).map((_, i) =>
this.getComputedLayout(node.getChild(i)),
),
};
};
onClick = (e: SyntheticMouseEvent<>) => {
const {onClick} = this.props;
if (onClick) {
e.stopPropagation();
onClick(this.props.path);
}
};
onDoubleClick = (e: SyntheticMouseEvent<>) => {
const {onDoubleClick} = this.props;
if (onDoubleClick) {
e.stopPropagation();
onDoubleClick(this.props.path);
}
};
onMouseLeave = (e: SyntheticMouseEvent<>) => this.setState({hovered: false});
showPositionGuides({node}: ComputedLayout) {
const padding = PositionRecord({
top: node.getComputedPadding(yoga.EDGE_TOP),
left: node.getComputedPadding(yoga.EDGE_LEFT),
right: node.getComputedPadding(yoga.EDGE_RIGHT),
bottom: node.getComputedPadding(yoga.EDGE_BOTTOM),
});
const border = PositionRecord({
top: node.getComputedBorder(yoga.EDGE_TOP),
left: node.getComputedBorder(yoga.EDGE_LEFT),
right: node.getComputedBorder(yoga.EDGE_RIGHT),
bottom: node.getComputedBorder(yoga.EDGE_BOTTOM),
});
const margin = PositionRecord({
top: node.getComputedMargin(yoga.EDGE_TOP),
left: node.getComputedMargin(yoga.EDGE_LEFT),
right: node.getComputedMargin(yoga.EDGE_RIGHT),
bottom: node.getComputedMargin(yoga.EDGE_BOTTOM),
});
const position = PositionRecord({
top: node.getPosition(yoga.EDGE_TOP).value,
left: node.getPosition(yoga.EDGE_LEFT).value,
right: node.getPosition(yoga.EDGE_RIGHT).value,
bottom: node.getPosition(yoga.EDGE_BOTTOM).value,
});
return [
<PositionGuide
key="border"
inset
position={border}
color="rgba(251, 170, 51, 0.15)"
reverse={node.getFlexWrap() === yoga.WRAP_WRAP_REVERSE}
/>,
<PositionGuide
key="padding"
inset
offset={border}
position={padding}
color="rgba(123, 179, 41, 0.1)"
reverse={node.getFlexWrap() === yoga.WRAP_WRAP_REVERSE}
/>,
<PositionGuide
key="margin"
position={margin}
color="rgba(214, 43, 28, 0.1)"
/>,
<PositionGuide
key="position"
offset={margin}
position={position}
color="rgba(115, 51, 205, 0.1)"
/>,
];
}
render() {
const {layoutDefinition, className, path, selectedNodePath, label} =
this.props;
// $FlowFixMe
const computedLayout: ComputedLayout =
this.props.computedLayout || this.computedLayout;
const {left, top, width, height, children} = computedLayout;
const isFocused = selectedNodePath && selectedNodePath.length === 0;
return (
<div
className={`YogaNode ${isFocused ? 'focused' : ''} ${className || ''} ${
this.state.visible ? '' : 'invisible'
} ${this.state.hovered ? 'hover' : ''}`}
style={path.length == 0 ? {width, height} : {left, top, width, height}}
onDoubleClick={this.onDoubleClick}
onMouseMove={this.onMouseMove}
onMouseLeave={this.onMouseLeave}
ref={ref => {
this._ref = ref;
}}
onClick={this.onClick}>
{label && <div className="label">{label}</div>}
{isFocused &&
this.props.showGuides &&
this.showPositionGuides(computedLayout)}
{(children || []).map((child: ComputedLayout, i) => (
<YogaNode
key={i}
computedLayout={child}
label={String(i + 1)}
layoutDefinition={layoutDefinition.children.get(i)}
selectedNodePath={
selectedNodePath &&
selectedNodePath.length > 0 &&
selectedNodePath[0] === i
? selectedNodePath.slice(1)
: null
}
path={path.concat(i)}
onClick={this.props.onClick}
onDoubleClick={this.props.onDoubleClick}
showGuides={this.props.showGuides}
/>
))}
</div>
);
}
}

View File

@@ -1,30 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.YogaPositionEditor {
text-align: center;
margin-top: 20px;
margin-bottom: 20px;
width: 60%;
margin-left: auto;
margin-right: auto;
}
.YogaPositionEditor input {
width: 55px;
text-align: center;
}
.YogaPositionEditorRow {
display: flex;
justify-content: space-between;
align-items: center;
flex-direction: row;
font-size: 12px;
font-weight: 700;
color: #444950;
}

View File

@@ -1,73 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React, {Component} from 'react';
import {Input} from 'antd';
import PositionRecord from './PositionRecord';
import type {PositionRecordT} from './PositionRecord';
import './YogaPositionEditor.css';
type Property = 'position' | 'margin' | 'padding' | 'border';
type Props = {
value: PositionRecordT,
property: Property,
disabled?: boolean,
onChange: (property: Property, value: PositionRecordT) => void,
};
export default class YogaPositionEditor extends Component<Props> {
static availableProperties = ['position', 'margin', 'padding', 'border'];
static defaultProps = {
value: PositionRecord(),
};
render() {
const {onChange, value, property, disabled} = this.props;
return (
<div className="YogaPositionEditor">
<Input
type="text"
value={Number.isNaN(value.top) ? '' : value.top}
disabled={disabled}
onChange={e => onChange(property, value.set('top', e.target.value))}
/>
<div className="YogaPositionEditorRow">
<Input
type="text"
value={Number.isNaN(value.left) ? '' : value.left}
disabled={disabled}
onChange={e =>
onChange(property, value.set('left', e.target.value))
}
/>
{property.toUpperCase()}
<Input
type="text"
value={Number.isNaN(value.right) ? '' : value.right}
disabled={disabled}
onChange={e =>
onChange(property, value.set('right', e.target.value))
}
/>
</div>
<Input
type="text"
value={Number.isNaN(value.bottom) ? '' : value.bottom}
disabled={disabled}
onChange={e =>
onChange(property, value.set('bottom', e.target.value))
}
/>
</div>
);
}
}

View File

@@ -1,74 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.PlaygroundContainer {
display: flex;
flex-direction: row;
flex-grow: 1;
width: 100%;
}
.Playground {
display: flex;
flex-grow: 1;
position: relative;
width: 100%;
overflow: hidden;
background: linear-gradient(-90deg, rgba(0, 0, 0, 0.02) 1px, transparent 1px),
linear-gradient(rgba(0, 0, 0, 0.02) 1px, transparent 1px),
linear-gradient(-90deg, rgba(0, 0, 0, 0.03) 1px, transparent 1px),
linear-gradient(rgba(0, 0, 0, 0.03) 1px, transparent 1px),
linear-gradient(
transparent 4px,
#f5f5f5 4px,
#f5f5f5 97px,
transparent 97px
),
linear-gradient(-90deg, #e5e5e5 1px, transparent 1px),
linear-gradient(
-90deg,
transparent 4px,
#f5f5f5 4px,
#f5f5f5 97px,
transparent 97px
),
linear-gradient(#e5e5e5 1px, transparent 1px), #f5f5f5;
background-size: 10px 10px, 10px 10px, 100px 100px, 100px 100px, 100px 100px,
100px 100px, 100px 100px, 100px 100px;
}
.Playground > .YogaNode {
margin: auto;
position: static;
align-self: center;
}
.Playground.standalone > .YogaNode {
transform: translateX(-175px);
}
.Playground .Actions {
padding: 15px;
}
.Playground .Actions .ant-btn {
width: 100%;
}
.Playground .NoContent {
border-top: 1px solid #E8E8E8;
font-size: 18px;
padding: 30px 50px;
text-align: center;
color: #D9D9D9;
font-weight: 300;
line-height: 130%;
}
.ant-modal-content {
overflow: hidden;
}

View File

@@ -1,322 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React, {Component} from 'react';
import yoga from 'yoga-layout/dist/entry-browser';
import YogaNode from './YogaNode';
import CodeGenerators from './CodeGenerators';
import URLShortener from './URLShortener';
import Editor from './Editor';
import {List, setIn} from 'immutable';
import PositionRecord from './PositionRecord';
import LayoutRecord from './LayoutRecord';
import Sidebar from './Sidebar';
import {Row, Col, Button} from 'antd';
import btoa from 'btoa';
import type {LayoutRecordT} from './LayoutRecord';
import type {Yoga$Direction} from 'yoga-layout';
import './index.css';
type Props = {
layoutDefinition: Object,
direction: Yoga$Direction,
maxDepth: number,
maxChildren?: number,
minChildren?: number,
selectedNodePath?: Array<number>,
showGuides: boolean,
className?: string,
height?: string | number,
persist?: boolean,
renderSidebar?: (layoutDefinition: LayoutRecordT, onChange: Function) => any,
};
type State = {
selectedNodePath: ?Array<number>,
layoutDefinition: LayoutRecordT,
direction: Yoga$Direction,
};
function getPath(path: Array<number>): Array<mixed> {
return path.reduce((acc, cv) => acc.concat('children', cv), []);
}
export default class Playground extends Component<Props, State> {
_containerRef: ?HTMLElement;
static defaultProps = {
layoutDefinition: {
width: 500,
height: 500,
children: [
{width: 100, height: 100},
{width: 100, height: 100},
{width: 100, height: 100},
],
},
direction: yoga.DIRECTION_LTR,
maxDepth: 3,
showGuides: true,
persist: false,
};
rehydrate = (node: Object): LayoutRecord => {
let record = LayoutRecord(node);
record = record.set('padding', PositionRecord(record.padding));
record = record.set('border', PositionRecord(record.border));
record = record.set('margin', PositionRecord(record.margin));
record = record.set('position', PositionRecord(record.position));
record = record.set('children', List(record.children.map(this.rehydrate)));
return record;
};
state = {
selectedNodePath: this.props.selectedNodePath,
layoutDefinition: this.rehydrate(this.props.layoutDefinition),
direction: this.props.direction,
};
componentDidMount() {
document.addEventListener('keydown', this.onKeyDown);
// rehydrate
if (window.location.search && window.location.search.length > 1) {
try {
const restoredState = JSON.parse(
atob(window.location.search.substr(1)),
);
this.setState({layoutDefinition: this.rehydrate(restoredState)});
} catch (e) {
window.history.replaceState(
{},
null,
window.location.origin + window.location.pathname,
);
}
}
}
componentWillUnmount() {
document.removeEventListener('keydown', this.onKeyDown);
}
onKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
this.hideSidePanes();
}
};
onMouseDown = (e: MouseEvent) => {
if (e.target === this._containerRef) {
this.hideSidePanes();
}
};
hideSidePanes() {
if (!Boolean(this.props.renderSidebar)) {
// only unselect if we don't have an external sidebar, otherwise the
// sidebar may rely on a certain node to be selected
this.setState({
selectedNodePath: null,
});
}
}
onChangeLayout = (key: string, value: any) => {
const {selectedNodePath} = this.state;
if (selectedNodePath) {
this.modifyAtPath([...getPath(selectedNodePath), key], value);
}
};
onRemove = () => {
const {selectedNodePath, layoutDefinition} = this.state;
if (selectedNodePath) {
const index = selectedNodePath.pop();
const path = getPath(selectedNodePath).concat('children');
const updatedChildren = layoutDefinition.getIn(path).delete(index);
this.modifyAtPath(path, updatedChildren);
this.setState({selectedNodePath: null});
}
};
onAdd = () => {
const {selectedNodePath, layoutDefinition} = this.state;
if (selectedNodePath) {
const path = getPath(selectedNodePath).concat('children');
const updatedChildren = layoutDefinition
.getIn(path)
.push(LayoutRecord({width: 100, height: 100}));
this.modifyAtPath(path, updatedChildren);
}
};
modifyAtPath(
path: Array<any>,
value: any,
selectedNodePath?: ?Array<number> = this.state.selectedNodePath,
) {
// $FlowFixMe
const layoutDefinition = setIn(this.state.layoutDefinition, path, value);
this.setState({
layoutDefinition,
selectedNodePath,
});
if (this.props.persist) {
window.history.replaceState(
{},
null,
window.location.origin +
window.location.pathname +
'?' +
this.getHash(layoutDefinition),
);
}
}
getHash = (
layoutDefinition: LayoutRecordT = this.state.layoutDefinition,
): string =>
btoa(JSON.stringify(this.removeUnchangedProperties(layoutDefinition)));
removeUnchangedProperties = (node: LayoutRecordT): Object => {
const untouchedLayout = LayoutRecord({});
const untouchedPosition = PositionRecord({});
const result = {};
if (!node.equals(untouchedLayout)) {
Object.keys(node.toJS()).forEach(key => {
if (key === 'children' && node.children.size > 0) {
result.children = node.children
.toJSON()
.map(this.removeUnchangedProperties);
} else if (
node[key] instanceof PositionRecord &&
!node[key].equals(untouchedPosition)
) {
result[key] = {};
Object.keys(untouchedPosition.toJS()).forEach(position => {
if (node[key][position] !== untouchedPosition[position]) {
result[key][position] = node[key][position];
}
});
} else if (node[key] !== untouchedLayout[key]) {
result[key] = node[key];
}
});
}
return result;
};
getChildrenCountForSelectedPath = (): number => {
const selectedNode: ?LayoutRecordT = (
this.state.selectedNodePath || []
).reduce(
(node: LayoutRecordT, cv) => node.children.get(cv),
this.state.layoutDefinition,
);
return selectedNode ? selectedNode.children.size : 0;
};
render() {
const {layoutDefinition, selectedNodePath, direction} = this.state;
const {height} = this.props;
const selectedNode: ?LayoutRecordT = selectedNodePath
? layoutDefinition.getIn(getPath(selectedNodePath))
: null;
const playground = (
<div
className={`Playground ${this.props.renderSidebar ? '' : 'standalone'}`}
onMouseDown={this.onMouseDown}
style={{height, maxHeight: height}}
ref={ref => {
this._containerRef = ref;
}}>
<YogaNode
layoutDefinition={layoutDefinition}
selectedNodePath={selectedNodePath}
onClick={selectedNodePath => this.setState({selectedNodePath})}
onDoubleClick={this.onAdd}
direction={direction}
showGuides={this.props.showGuides}
/>
{!this.props.renderSidebar && (
<Sidebar>
<div className="Actions">
<Row gutter={15}>
<Col span={12}>
<CodeGenerators
layoutDefinition={layoutDefinition}
direction={direction}
/>
</Col>
<Col span={12}>
{this.props.persist ? (
<URLShortener />
) : (
<Button
href={`/playground?${this.getHash()}`}
type="primary">
Open Playground
</Button>
)}
</Col>
</Row>
</div>
{this.state.selectedNodePath ? (
<Editor
node={selectedNode}
selectedNodeIsRoot={
selectedNodePath ? selectedNodePath.length === 0 : false
}
onChangeLayout={this.onChangeLayout}
onChangeSetting={(key, value) => this.setState({[key]: value})}
direction={direction}
onRemove={
selectedNodePath && selectedNodePath.length > 0
? this.onRemove
: undefined
}
onAdd={
selectedNodePath &&
selectedNodePath.length < this.props.maxDepth
? this.onAdd
: undefined
}
/>
) : (
<div className="NoContent">
Select a node to edit its properties
</div>
)}
</Sidebar>
)}
</div>
);
if (this.props.renderSidebar) {
return (
<div className={`PlaygroundContainer ${this.props.className || ''}`}>
<div>
{this.props.renderSidebar(
layoutDefinition.getIn(getPath(selectedNodePath)),
this.onChangeLayout,
)}
</div>
{playground}
</div>
);
} else {
return playground;
}
}
}

View File

@@ -1,56 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.Toolbar {
display: flex;
padding: 20px 15px;
z-index: 4;
align-items: center;
background-color: white;
}
.Toolbar .selected {
color: #6BCEBB;
}
.Toolbar .logo {
display: flex;
align-items: center;
}
.Toolbar a {
margin: 0 15px;
color: #606770;
font-weight: 700;
}
.Toolbar a:hover {
color: #6BCEBB;
}
.Toolbar .ToolbarToggle {
font-size: 16px;
}
.Toolbar .ToolbarToggle i {
margin-right: 5px;
}
@media only screen and (max-width: 576px) {
.Toolbar {
padding: 10px 5px;
}
.Toolbar a {
margin: 0 10px;
font-size: 12px;
}
.Toolbar .ToolbarToggle {
font-size: 12px;
}
}

View File

@@ -1,52 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React, {Component} from 'react';
import Link from 'gatsby-link';
import {Icon, Row, Col} from 'antd';
import logo from '../pages/logos/logo.svg';
import './Toolbar.css';
type Props = {
onShowCode?: () => void,
};
export default class Toolbar extends Component<Props> {
render() {
return (
<div className="Toolbar">
<Link to="/" className="logo">
<img src={logo} width="42" alt="Yoga logo" />
</Link>
<Link to="/docs" activeClassName="selected">
Documentation
</Link>
<Row>
<Col lg={24} md={0} sm={0} xs={0}>
<Link to="/playground" activeClassName="selected">
Playground
</Link>
</Col>
</Row>
<a href="https://github.com/facebook/yoga">GitHub</a>
{this.props.onShowCode && (
<a className="ToolbarToggle" onClick={this.props.onShowCode}>
<Icon type={'code-o'} />
Code
</a>
)}
</div>
);
}
}

View File

@@ -1,20 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React from 'react';
const NotFoundPage = () => (
<div>
<h1>NOT FOUND</h1>
<p>You just hit a route that doesn&#39;t exist... the sadness.</p>
</div>
);
export default NotFoundPage;

View File

@@ -1,73 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.docs-landing .heading {
padding-top: 50px;
padding-bottom: 50px;
}
.docs-landing h1 {
color: #444950;
font-size: 48px;
font-weight: 300;
line-height: 110%;
}
.docs-landing p {
color: #444950;
font-size: 16px;
font-weight: 400;
line-height: 180%;
}
.category {
display: flex;
flex-direction: column;
margin-bottom: 50px;
}
.category h2 {
font-size: 16px;
font-weight: 700;
}
.category a {
font-size: 16px;
font-weight: 400;
line-height: 250%;
color: #606770;
}
.category a:hover {
color: #6BCEBB;
text-decoration: underline;
}
@media only screen and (max-width: 576px) {
.docs-landing .heading {
padding-top: 20px;
padding-bottom: 20px;
}
.docs-landing h1 {
font-size: 32px;
font-weight: 400;
}
.docs-landing p {
line-height: 160%;
font-size: 14px;
}
.category {
margin-bottom: 20px;
}
.category a {
line-height: 200%;
}
}

View File

@@ -1,87 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React from 'react';
import Link from 'gatsby-link';
import Page from '../../components/Page';
import Padded from '../../components/Padded';
import {Row, Col} from 'antd';
import './index.css';
const CATEGORY_TITLE = {
'getting-started': 'Getting Started',
properties: 'Properties',
examples: 'Examples',
contributing: 'Contributing',
};
export default ({data}) => (
<Page className="docs-landing" shouldShowFooter title="Documentation">
<Padded>
<Row className="heading">
<Col xl={16} lg={16} md={24} sm={24} xs={24}>
<h1>Documentation</h1>
<p>
Welcome to Yoga's documentation page. Below you will find helpful
documentation covering all the features of the library. Each page
comes with an interactive playground for you to explore that
feature. The examples section showcases some of the most common
layouts and how to build them. This is a community project and
contributions within documentation, code, and tests are more than
welcome. The contributing section below covers how to get started.
</p>
</Col>
</Row>
<Row>
{['getting-started', 'properties', 'examples', 'contributing'].map(
category => (
<Col lg={6} md={12} xs={24} key={category} className="category">
<h2>{CATEGORY_TITLE[category]}</h2>
{data.allMarkdownRemark.edges
.filter(
({node}) =>
node.fileAbsolutePath.indexOf(`/${category}/`) > -1,
)
.map(({node}) =>
node.frontmatter.redirect ? (
<a key={node.id} href={node.frontmatter.path}>
{node.frontmatter.title}
</a>
) : (
<Link key={node.id} to={node.frontmatter.path}>
{node.frontmatter.title}
</Link>
),
)}
</Col>
),
)}
</Row>
</Padded>
</Page>
);
export const query = graphql`
query IndexQuery {
allMarkdownRemark {
edges {
node {
id
frontmatter {
title
path
redirect
}
fileAbsolutePath
}
}
}
}
`;

View File

@@ -1,222 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.landing-page .hero {
padding-top: 100px;
padding-bottom: 100px;
display: flex;
align-items: center;
}
.landing-page .hero h3 {
color: #BEC3C9;
font-size: 16px;
font-weight: 700;
line-height: 200%;
}
.landing-page .hero h1 {
color: #444950;
font-size: 48px;
font-weight: 300;
line-height: 110%;
}
.landing-page .hero p {
color: #444950;
line-height: 180%;
font-size: 18px;
font-weight: 400;
margin-bottom: 1.5em;
}
.landing-page .hero .button {
color: white;
font-size: 14px;
font-weight: 700;
padding: 12px 30px;
height: auto;
}
.landing-page .hero .blueprint {
border-style: dashed;
border-color: #444950;
border-width: 1px;
}
.landing-page .hero .blueprint-container {
position: relative;
margin: auto;
height: 300px;
width: 300px;
}
.landing-page .hero .blueprint-avatar {
position: absolute;
left: 15px;
top: 15px;
height: 50px;
width: 50px;
}
.landing-page .hero .blueprint-title {
position: absolute;
left: 80px;
top: 20px;
height: 15px;
width: 150px;
}
.landing-page .hero .blueprint-subtitle {
position: absolute;
left: 80px;
top: 40px;
height: 15px;
width: 80px;
}
.landing-page .hero .blueprint-content {
position: absolute;
left: 15px;
right: 15px;
bottom: 15px;
top: 80px;
}
.landing-page hr {
width: 100%;
height: 1px;
background-color: #BEC3C9;
border-width: 0px;
}
.landing-page .about-section {
padding-top: 100px;
padding-bottom: 100px;
}
.landing-page .about-section h1 {
color: #444950;
font-size: 32px;
font-weight: 400;
line-height: 120%;
}
.landing-page .about-section h3 {
color: #6BCEBB;
font-size: 16px;
font-weight: 700;
margin-top: 50px;
}
.landing-page .about-section p {
color: #444950;
line-height: 180%;
font-size: 16px;
font-weight: 400;
}
.landing-page .logo-group {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-top: 50px;
}
.landing-page .logo-group .logo {
display: flex;
flex-direction: column;
align-items: center;
margin-right: 100px;
}
.landing-page .logo-group img {
height: 130px;
}
.landing-page .logo-group .logo h3 {
color: #606770;
font-size: 14px;
font-weight: 600;
margin-top: 20px;
text-align: center;
}
footer {
display: flex;
padding: 20px 15px;
padding-left: 87px;
z-index: 4;
align-items: center;
background-color: white;
}
footer a {
margin: 0 15px;
color: #606770;
}
footer a:hover {
color: #6BCEBB;
}
@media only screen and (max-width: 576px) {
.landing-page .hero {
padding-top: 20px;
padding-bottom: 20px;
}
.landing-page .hero h3 {
font-size: 14px;
}
.landing-page .hero h1 {
font-size: 32px;
font-weight: 400;
}
.landing-page .hero p {
line-height: 160%;
font-size: 14px;
}
.landing-page .about-section {
padding-top: 50px;
padding-bottom: 50px;
}
.landing-page .about-section h1 {
font-size: 24px;
line-height: 120%;
}
.landing-page .about-section h3 {
font-size: 14px;
margin-top: 20px;
}
.landing-page .about-section p {
line-height: 160%;
font-size: 14px;
}
.landing-page .logo-group .logo {
width: 33%;
padding: 20px;
margin-right: 0px;
}
.landing-page .logo-group img {
height: auto;
width: 100%;
}
.landing-page .logo-group .logo h3 {
font-size: 10px;
margin-top: 10px;
}
}

View File

@@ -1,198 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import {Button} from 'antd';
import React from 'react';
import Page from '../components/Page';
import Padded from '../components/Padded';
import Playground from '../components/Playground/src';
import {Row, Col} from 'antd';
import './index.css';
import ReactNativeLogo from './logos/reactnative.png';
import LithoLogo from './logos/litho.png';
import ComponentKitLogo from './logos/componentkit.png';
import ReactPDFLogo from './logos/reactpdf.png';
import Link from 'gatsby-link';
import Footer from '../components/Footer';
const playgroundInitialState = {
width: 500,
height: 500,
alignItems: 1,
padding: {
top: '20',
right: '20',
bottom: '20',
left: '20',
},
children: [
{
width: 100,
height: 100,
minWidth: null,
maxWidth: null,
minHeight: null,
maxHeight: null,
},
{
width: 100,
height: 100,
margin: {
right: '20',
left: '20',
},
flexGrow: '1',
minWidth: null,
maxWidth: null,
minHeight: null,
maxHeight: null,
},
{
width: 100,
height: 100,
minWidth: null,
maxWidth: null,
minHeight: null,
maxHeight: null,
},
],
minWidth: null,
maxWidth: null,
minHeight: null,
maxHeight: null,
};
const HeroSection = () => (
<Padded>
<Row className="hero">
<Col md={12} sm={24} xs={24}>
<h3>INTRODUCING</h3>
<h1>
Flexible Layouts <br /> with Yoga
</h1>
<p>
Build flexible layouts on any platform with a highly optimized open
source layout engine designed with speed, size, and ease of use in
mind.
</p>
<Link to="/docs">
<Button type="primary" className="button">
LEARN MORE
</Button>
</Link>
</Col>
<Col md={12} sm={0} xs={0}>
<div className="blueprint blueprint-container">
<div className="blueprint blueprint-avatar" />
<div className="blueprint blueprint-title" />
<div className="blueprint blueprint-subtitle" />
<div className="blueprint blueprint-content" />
</div>
</Col>
</Row>
</Padded>
);
const PlaygroundSection = () => (
<Row>
<Col lg={24} md={0} sm={0} xs={0}>
<Playground
selectedNodePath={[]}
showGuides={true}
height={601}
layoutDefinition={playgroundInitialState}
/>
</Col>
</Row>
);
const AboutSectionOne = () => (
<Padded className="about-section">
<Row>
<Col xl={16} lg={16} md={24} sm={24} xs={24}>
<h1>Open Source Adoption</h1>
<p>
Yoga already powers widely used open source frameworks. It enables
these frameworks to offer a simple and intuitive layout API that
allows for engineers to collaborate more easily across platforms. Yoga
has unlocked exciting features such as calculating layouts off of the
main thread to help ensure smooth UI performance.
</p>
</Col>
</Row>
<div className="logo-group">
<a href="https://fblitho.com" target="_blank" className="logo">
<img src={LithoLogo} />
<h3>Litho</h3>
</a>
<a href="https://componentkit.org" target="_blank" className="logo">
<img src={ComponentKitLogo} />
<h3>ComponentKit</h3>
</a>
<a href="https://reactnative.dev" target="_blank" className="logo">
<img src={ReactNativeLogo} />
<h3>React Native</h3>
</a>
<a href="https://react-pdf.org/" target="_blank" className="logo">
<img src={ReactPDFLogo} />
<h3>React-PDF</h3>
</a>
</div>
</Padded>
);
const AboutSectionTwo = () => (
<Padded className="about-section">
<Row>
<Col xl={16} lg={16} md={24} sm={24} xs={24}>
<h1>Why You May Consider Yoga</h1>
<h3>PERFORMANCE</h3>
<p>
Yoga was built to be fast and performance will always be one of Yoga's
primary goals. For a layout engine to be able to power any range of
applications, it needs to be fast and never stand in the way of a
fluid user experience.
</p>
<h3>CROSS PLATFORM</h3>
<p>
Yoga is built with cross platform in mind. To ensure Yoga can be used
anywhere, it was written in portable C/C++ and has a low number of
dependencies and small binary size. This means Yoga can be used on iOS
and Android, sharing knowledge, and potentially code, between
platforms.
</p>
<h3>EASY TO LEARN</h3>
<p>
Yoga is easy to pick up and learn. The interactive documentation pages
and a fully fledged layout editor makes it easy to play and learn all
the features. If used with any of the major UI frameworks the layout
editor even provides code generation.
</p>
</Col>
</Row>
</Padded>
);
export default () => (
<div>
<Page className="landing-page" title="A cross-platform layout engine">
<HeroSection />
<PlaygroundSection />
<AboutSectionOne />
<hr />
<AboutSectionTwo />
<Footer />
</Page>
</div>
);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 200 200" enable-background="new 0 0 200 200" xml:space="preserve">
<g>
<circle fill="#303846" cx="100" cy="100" r="74"/>
<g>
<path fill="none" stroke="#97DCCF" stroke-width="5" stroke-miterlimit="10" d="M100.6,130.6c5.9-10.3,6.3-23.3,0-34.3
c-6.3-11-17.9-17.1-29.7-17.1c-5.9,10.3-6.3,23.3,0,34.3C77.2,124.4,88.7,130.6,100.6,130.6z"/>
<path fill="none" stroke="#97DCCF" stroke-width="5" stroke-miterlimit="10" d="M99.4,130.6c11.8,0,23.3-6.1,29.7-17.1
c6.3-11,5.9-24,0-34.3c-11.8,0-23.3,6.1-29.7,17.1C93.1,107.3,93.5,120.3,99.4,130.6z"/>
</g>
<path fill="none" stroke="#97DCCF" stroke-width="5" stroke-miterlimit="10" d="M100,129.4c10.2-5.9,17.1-17,17.1-29.7
c0-12.7-6.9-23.8-17.1-29.7c-10.2,5.9-17.1,17-17.1,29.7C82.9,112.4,89.8,123.5,100,129.4z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

View File

@@ -1,28 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.playground-page {
display: flex;
flex: 1;
}
@media (max-width: 991px) {
.playground-page .error-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
}
.playground-page .error-text {
color: #444950;
line-height: 180%;
font-size: 16px;
font-weight: 400;
text-align: center;
}

View File

@@ -1,31 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React from 'react';
import Page from '../../components/Page';
import Playground from '../../components/Playground/src';
import {Row, Col} from 'antd';
import './index.css';
export default () => (
<Page title="Playground">
<Row className="playground-page">
<Col lg={24} md={0} sm={0} xs={0}>
<Playground height="100%" selectedNodePath={[]} persist />
</Col>
<Col lg={0} xs={24} className="error-container">
<p className="error-text">
Sorry! The playground only works on larger displays currently.
</p>
</Col>
</Row>
</Page>
);

View File

@@ -1,141 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.doc-block.playground {
height: 1vh;
}
.no-playground .markdown {
padding-top: 50px;
}
.doc-block .markdown {
padding-bottom: 20px;
}
.doc-block .overview {
font-size: 12px;
font-weight: 600;
padding-bottom: 30px;
}
.doc-block h1 {
color: #444950;
font-size: 48px;
font-weight: 300;
line-height: 110%;
}
.doc-block h2 {
color: #444950;
font-size: 32px;
font-weight: 400;
line-height: 120%;
margin-top: 30px;
}
.doc-block h3 {
line-height: 180%;
font-size: 14px;
font-weight: 700;
color: #444950;
text-transform: uppercase;
}
.doc-block p {
color: #444950;
line-height: 160%;
font-size: 14px;
font-weight: 400;
}
.doc-block li {
color: #444950;
line-height: 150%;
font-size: 14px;
font-weight: 400;
margin-bottom: 8px;
}
.doc-block .prop {
margin-bottom: 20px;
}
.doc-block pre {
background-color: #f5f5f5 !important;
border-radius: 3px;
padding: 10px !important;
}
.doc-block pre, .doc-block code {
background-color: #f5f5f5;
border-radius: 3px;
padding-left: 3px;
padding-right: 3px;
}
@media only screen and (max-width: 992px) {
.playground .Playground {
display: none;
}
.playground controls {
display: none;
}
}
@media only screen and (max-width: 576px) {
.no-playground .markdown {
padding-top: 15px;
}
.doc-block .markdown {
padding-bottom: 10px;
}
.doc-block .overview {
font-size: 12px;
font-weight: 600;
padding-bottom: 10px;
}
.doc-block h1 {
font-size: 32px;
font-weight: 400;
}
.doc-block h2 {
font-size: 24px;
margin-top: 20px;
}
.doc-block h3 {
font-size: 16px;
}
.doc-block p {
line-height: 160%;
font-size: 14px;
}
.doc-block li {
font-size: 14px;
margin-bottom: 5px;
}
.doc-block .prop {
margin-bottom: 10px;
}
.doc-block pre {
padding: 5px !important;
}
.doc-block code {
font-size: 12px;
}
}

View File

@@ -1,58 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React, {Component} from 'react';
import Page from '../components/Page';
import Playground from '../components/Playground/src';
import DocsSidebar from '../components/DocsSidebar';
import EditValue from '../components/Playground/src/EditValue';
import Link from 'gatsby-link';
import {Button, Icon, Row, Col} from 'antd';
import './index.css';
import atob from 'atob';
type Props = {
pathContext: {
html: string,
frontmatter: {
initialPlayground?: string,
},
},
};
const REGEX = /<controls prop="([A-Za-z]+)"\s?\/>/gi;
export default class withPlayground extends Component<Props> {
render() {
let layoutDefinition;
if (this.props.pathContext.frontmatter.initialPlayground) {
layoutDefinition = JSON.parse(
atob(this.props.pathContext.frontmatter.initialPlayground),
);
}
return (
<Page
className="doc-block playground"
title={this.props.pathContext.frontmatter.title}>
<Playground
layoutDefinition={layoutDefinition}
selectedNodePath={[]}
showGuides={false}
renderSidebar={(layout, onChange) => (
<DocsSidebar
layout={layout}
onChange={onChange}
markdown={this.props.pathContext.html}
/>
)}
/>
</Page>
);
}
}

View File

@@ -1,39 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import React from 'react';
import Page from '../components/Page';
import Padded from '../components/Padded';
import {Row, Col} from 'antd';
import Link from 'gatsby-link';
import './index.css';
export default ({pathContext}) => {
return (
<Page
className="doc-block no-playground"
shouldShowFooter
title={pathContext.frontmatter.title}>
<Padded>
<Row>
<Col xl={16} lg={16} md={24} sm={24} xs={24}>
<div
className="markdown"
dangerouslySetInnerHTML={{__html: pathContext.html}}
/>
</Col>
</Row>
<Link to="/docs" className="overview">
BACK TO OVERVIEW
</Link>
</Padded>
</Page>
);
};

File diff suppressed because it is too large Load Diff