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,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>
);
};