933 lines
25 KiB
JavaScript
933 lines
25 KiB
JavaScript
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*
|
|
* @providesModule AutodocsLayout
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
var DocsSidebar = require('DocsSidebar');
|
|
var Footer = require('Footer');
|
|
var Header = require('Header');
|
|
var HeaderWithGithub = require('HeaderWithGithub');
|
|
var Marked = require('Marked');
|
|
var Metadata = require('Metadata');
|
|
var Prism = require('Prism');
|
|
var React = require('React');
|
|
var Site = require('Site');
|
|
|
|
var slugify = require('slugify');
|
|
|
|
var styleReferencePattern = /^[^.]+\.propTypes\.style$/;
|
|
|
|
function renderEnumValue(value) {
|
|
// Use single quote strings even when we are given double quotes
|
|
if (value.match(/^"(.+)"$/)) {
|
|
return "'" + value.slice(1, -1) + "'";
|
|
}
|
|
return value;
|
|
}
|
|
|
|
function renderType(type) {
|
|
const baseType = renderBaseType(type);
|
|
return type.nullable ? <span>?{baseType}</span> : baseType;
|
|
}
|
|
|
|
function spanJoinMapper(elements, callback, separator) {
|
|
return <span>{elements.map((rawElement, ii) => {
|
|
const el = callback(rawElement);
|
|
return (ii + 1 < elements.length) ? <span>{el}{separator}</span> : el;
|
|
})}</span>;
|
|
}
|
|
|
|
function renderBaseType(type) {
|
|
if (type.name === 'enum') {
|
|
if (typeof type.value === 'string') {
|
|
return type.value;
|
|
}
|
|
return 'enum(' + type.value.map((v) => renderEnumValue(v.value)).join(', ') + ')';
|
|
}
|
|
|
|
if (type.name === '$Enum') {
|
|
if (type.elements[0].signature.properties) {
|
|
return type.elements[0].signature.properties.map(p => `'${p.key}'`).join(' | ');
|
|
}
|
|
return type.name;
|
|
}
|
|
|
|
if (type.name === 'shape') {
|
|
return <span>{'{'}{spanJoinMapper(
|
|
Object.keys(type.value),
|
|
(key) => <span>{key + ': '}{renderType(type.value[key])}</span>,
|
|
', '
|
|
)}{'}'}</span>;
|
|
}
|
|
|
|
if (type.name === 'union') {
|
|
if (type.value) {
|
|
return spanJoinMapper(type.value, renderType, ', ');
|
|
}
|
|
return spanJoinMapper(type.elements, renderType, ' | ');
|
|
}
|
|
|
|
if (type.name === 'arrayOf') {
|
|
return <span>[{renderType(type.value)}]</span>;
|
|
}
|
|
|
|
if (type.name === 'instanceOf') {
|
|
return type.value;
|
|
}
|
|
|
|
if (type.name === 'custom') {
|
|
if (styleReferencePattern.test(type.raw)) {
|
|
var name = type.raw.substring(0, type.raw.indexOf('.'));
|
|
return <a href={'docs/' + slugify(name) + '.html#style'}>{name}#style</a>;
|
|
}
|
|
if (type.raw === 'ColorPropType') {
|
|
return <a href={'docs/colors.html'}>color</a>;
|
|
}
|
|
if (type.raw === 'EdgeInsetsPropType') {
|
|
return '{top: number, left: number, bottom: number, right: number}';
|
|
}
|
|
return type.raw;
|
|
}
|
|
|
|
if (type.name === 'stylesheet') {
|
|
return 'style';
|
|
}
|
|
|
|
if (type.name === 'func') {
|
|
return 'function';
|
|
}
|
|
|
|
if (type.name === 'signature') {
|
|
return type.raw;
|
|
}
|
|
|
|
return type.raw || type.name;
|
|
}
|
|
|
|
function renderTypeNameLink(typeName, docPath, namedTypes) {
|
|
const ignoreTypes = [
|
|
'string',
|
|
'number',
|
|
'boolean',
|
|
'object',
|
|
'function',
|
|
'array',
|
|
];
|
|
const typeNameLower = typeName.toLowerCase();
|
|
if (ignoreTypes.indexOf(typeNameLower) !== -1 || !namedTypes[typeNameLower]) {
|
|
return typeName;
|
|
}
|
|
return <a href={docPath + '#' + typeNameLower}>{typeName}</a>;
|
|
}
|
|
|
|
function renderTypeWithLinks(type, docTitle, namedTypes) {
|
|
if (!type || !type.names) {
|
|
return null;
|
|
}
|
|
|
|
const docPath = docTitle ? 'docs/' + docTitle.toLowerCase() + '.html' : 'docs/';
|
|
return (
|
|
<div>
|
|
{
|
|
type.names.map((typeName, index, array) => {
|
|
const separator = index < array.length - 1 && ' | ';
|
|
return (
|
|
<span key={index}>
|
|
{renderTypeNameLink(typeName, docPath, namedTypes)}
|
|
{separator}
|
|
</span>
|
|
);
|
|
})
|
|
}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function sortByPlatform(props, nameA, nameB) {
|
|
var a = props[nameA];
|
|
var b = props[nameB];
|
|
|
|
if (a.platforms && !b.platforms) {
|
|
return 1;
|
|
}
|
|
if (b.platforms && !a.platforms) {
|
|
return -1;
|
|
}
|
|
|
|
// Cheap hack: use < on arrays of strings to compare the two platforms
|
|
if (a.platforms < b.platforms) {
|
|
return -1;
|
|
}
|
|
if (a.platforms > b.platforms) {
|
|
return 1;
|
|
}
|
|
|
|
if (nameA < nameB) {
|
|
return -1;
|
|
}
|
|
if (nameA > nameB) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
function removeCommentsFromDocblock(docblock) {
|
|
return docblock
|
|
.trim('\n ')
|
|
.replace(/^\/\*+/, '')
|
|
.replace(/\*\/$/, '')
|
|
.split('\n')
|
|
.map(function(line) {
|
|
return line.trim().replace(/^\* ?/, '');
|
|
})
|
|
.join('\n');
|
|
}
|
|
|
|
function getNamedTypes(typedefs) {
|
|
const namedTypes = {};
|
|
typedefs && typedefs.forEach(typedef => {
|
|
if (typedef.name) {
|
|
const type = typedef.name.toLowerCase();
|
|
namedTypes[type] = 1;
|
|
}
|
|
});
|
|
return namedTypes;
|
|
}
|
|
|
|
var ComponentDoc = React.createClass({
|
|
renderProp: function(name, prop) {
|
|
return (
|
|
<div className="prop" key={name}>
|
|
<Header level={4} className="propTitle" toSlug={name}>
|
|
{prop.platforms && prop.platforms.map(platform =>
|
|
<span className="platform">{platform}</span>
|
|
)}
|
|
{name}
|
|
{prop.required ? ': ' : '?: '}
|
|
{(prop.type || prop.flowType) && <span className="propType">
|
|
{renderType(prop.flowType || prop.type)}
|
|
</span>}
|
|
</Header>
|
|
{prop.deprecationMessage && <div className="deprecated">
|
|
<div className="deprecatedTitle">
|
|
<img className="deprecatedIcon" src="img/Warning.png" />
|
|
<span>Deprecated</span>
|
|
</div>
|
|
<div className="deprecatedMessage">
|
|
<Marked>{prop.deprecationMessage}</Marked>
|
|
</div>
|
|
</div>}
|
|
{prop.type && prop.type.name === 'stylesheet' &&
|
|
this.renderStylesheetProps(prop.type.value)}
|
|
{prop.description && <Marked>{prop.description}</Marked>}
|
|
</div>
|
|
);
|
|
},
|
|
|
|
renderCompose: function(name) {
|
|
return (
|
|
<div className="prop" key={name}>
|
|
<Header level={4} className="propTitle" toSlug={name}>
|
|
<a href={'docs/' + slugify(name) + '.html#props'}>{name} props...</a>
|
|
</Header>
|
|
</div>
|
|
);
|
|
},
|
|
|
|
renderStylesheetProp: function(name, prop) {
|
|
return (
|
|
<div className="prop" key={name}>
|
|
<h6 className="propTitle">
|
|
{prop.platforms && prop.platforms.map(platform =>
|
|
<span className="platform">{platform}</span>
|
|
)}
|
|
{name}
|
|
{' '}
|
|
{prop.type && <span className="propType">
|
|
{renderType(prop.type)}
|
|
</span>}
|
|
{' '}
|
|
{prop.description && <Marked>{prop.description}</Marked>}
|
|
</h6>
|
|
</div>
|
|
);
|
|
},
|
|
|
|
renderStylesheetProps: function(stylesheetName) {
|
|
var style = this.props.content.styles[stylesheetName];
|
|
this.extractPlatformFromProps(style.props);
|
|
return (
|
|
<div className="compactProps">
|
|
{(style.composes || []).map((name) => {
|
|
var link;
|
|
if (name === 'LayoutPropTypes') {
|
|
name = 'Layout Props';
|
|
link =
|
|
<a href={'docs/' + slugify(name) + '.html#props'}>{name}...</a>;
|
|
} else if (name === 'ShadowPropTypesIOS') {
|
|
name = 'Shadow Props';
|
|
link =
|
|
<a href={'docs/' + slugify(name) + '.html#props'}>{name}...</a>;
|
|
} else if (name === 'TransformPropTypes') {
|
|
name = 'Transforms';
|
|
link =
|
|
<a href={'docs/' + slugify(name) + '.html#props'}>{name}...</a>;
|
|
} else {
|
|
name = name.replace('StylePropTypes', '');
|
|
link =
|
|
<a href={'docs/' + slugify(name) + '.html#style'}>{name}#style...</a>;
|
|
}
|
|
return (
|
|
<div className="prop" key={name}>
|
|
<h6 className="propTitle">{link}</h6>
|
|
</div>
|
|
);
|
|
})}
|
|
{Object.keys(style.props)
|
|
.sort(sortByPlatform.bind(null, style.props))
|
|
.map((name) => this.renderStylesheetProp(name, style.props[name]))
|
|
}
|
|
</div>
|
|
);
|
|
},
|
|
|
|
renderProps: function(props, composes) {
|
|
return (
|
|
<div className="props">
|
|
{(composes || []).map((name) =>
|
|
this.renderCompose(name)
|
|
)}
|
|
{Object.keys(props)
|
|
.sort(sortByPlatform.bind(null, props))
|
|
.map((name) => this.renderProp(name, props[name]))
|
|
}
|
|
</div>
|
|
);
|
|
},
|
|
|
|
extractPlatformFromProps: function(props) {
|
|
for (var key in props) {
|
|
var prop = props[key];
|
|
var description = prop.description || '';
|
|
var platforms = description.match(/\@platform (.+)/);
|
|
platforms = platforms && platforms[1].replace(/ /g, '').split(',');
|
|
description = description.replace(/\@platform (.+)/, '');
|
|
|
|
prop.description = description;
|
|
prop.platforms = platforms;
|
|
}
|
|
},
|
|
|
|
renderMethod: function(method, namedTypes) {
|
|
return (
|
|
<Method
|
|
key={method.name}
|
|
name={method.name}
|
|
description={method.description}
|
|
params={method.params}
|
|
modifiers={method.scope ? [method.scope] : method.modifiers}
|
|
examples={method.examples}
|
|
returns={method.returns}
|
|
namedTypes={namedTypes}
|
|
/>
|
|
);
|
|
},
|
|
|
|
renderMethods: function(methods, namedTypes) {
|
|
if (!methods || !methods.length) {
|
|
return null;
|
|
}
|
|
return (
|
|
<span>
|
|
<Header level={3}>Methods</Header>
|
|
<div className="props">
|
|
{methods.filter((method) => {
|
|
return method.name[0] !== '_';
|
|
}).map(method => this.renderMethod(method, namedTypes))}
|
|
</div>
|
|
</span>
|
|
);
|
|
},
|
|
|
|
renderTypeDef: function(typedef, namedTypes) {
|
|
return (
|
|
<TypeDef
|
|
key={typedef.name}
|
|
name={typedef.name}
|
|
description={typedef.description}
|
|
type={typedef.type}
|
|
properties={typedef.properties}
|
|
values={typedef.values}
|
|
apiName={this.props.apiName}
|
|
namedTypes={namedTypes}
|
|
/>
|
|
);
|
|
},
|
|
|
|
renderTypeDefs: function(typedefs, namedTypes) {
|
|
if (!typedefs || !typedefs.length) {
|
|
return null;
|
|
}
|
|
return (
|
|
<span>
|
|
<Header level={3}>Type Definitions</Header>
|
|
<div className="props">
|
|
{typedefs.map((typedef) => {
|
|
return this.renderTypeDef(typedef, namedTypes);
|
|
})}
|
|
</div>
|
|
</span>
|
|
);
|
|
},
|
|
|
|
render: function() {
|
|
var content = this.props.content;
|
|
this.extractPlatformFromProps(content.props);
|
|
const namedTypes = getNamedTypes(content.typedef);
|
|
return (
|
|
<div>
|
|
<Marked>
|
|
{content.description}
|
|
</Marked>
|
|
<Header level={3}>Props</Header>
|
|
{this.renderProps(content.props, content.composes)}
|
|
{this.renderMethods(content.methods, namedTypes)}
|
|
{this.renderTypeDefs(content.typedef, namedTypes)}
|
|
</div>
|
|
);
|
|
}
|
|
});
|
|
|
|
var APIDoc = React.createClass({
|
|
|
|
renderMethod: function(method, namedTypes) {
|
|
return (
|
|
<Method
|
|
key={method.name}
|
|
name={method.name}
|
|
description={method.description || method.docblock && removeCommentsFromDocblock(method.docblock)}
|
|
params={method.params}
|
|
modifiers={method.scope ? [method.scope] : method.modifiers}
|
|
examples={method.examples}
|
|
apiName={this.props.apiName}
|
|
namedTypes={namedTypes}
|
|
/>
|
|
);
|
|
},
|
|
|
|
renderMethods: function(methods, namedTypes) {
|
|
if (!methods.length) {
|
|
return null;
|
|
}
|
|
return (
|
|
<span>
|
|
<Header level={3}>Methods</Header>
|
|
<div className="props">
|
|
{methods.filter((method) => {
|
|
return method.name[0] !== '_';
|
|
}).map(method => this.renderMethod(method, namedTypes))}
|
|
</div>
|
|
</span>
|
|
);
|
|
},
|
|
|
|
renderProperty: function(property) {
|
|
return (
|
|
<div className="prop" key={property.name}>
|
|
<Header level={4} className="propTitle" toSlug={property.name}>
|
|
{property.name}
|
|
{(property.type || property.flowType) &&
|
|
<span className="propType">
|
|
{': ' + renderType(property.flowType || property.type)}
|
|
</span>
|
|
}
|
|
</Header>
|
|
{property.docblock && <Marked>
|
|
{removeCommentsFromDocblock(property.docblock)}
|
|
</Marked>}
|
|
</div>
|
|
);
|
|
},
|
|
|
|
renderProperties: function(properties) {
|
|
if (!properties || !properties.length) {
|
|
return null;
|
|
}
|
|
return (
|
|
<span>
|
|
<Header level={3}>Properties</Header>
|
|
<div className="props">
|
|
{properties.filter((property) => {
|
|
return property.name[0] !== '_';
|
|
}).map(this.renderProperty)}
|
|
</div>
|
|
</span>
|
|
);
|
|
},
|
|
|
|
renderClasses: function(classes, namedTypes) {
|
|
if (!classes || !classes.length) {
|
|
return null;
|
|
}
|
|
return (
|
|
<span>
|
|
<div>
|
|
{classes.filter((cls) => {
|
|
return cls.name[0] !== '_' && cls.ownerProperty[0] !== '_';
|
|
}).map((cls) => {
|
|
return (
|
|
<span key={cls.name}>
|
|
<Header level={2} toSlug={cls.name}>
|
|
class {cls.name}
|
|
</Header>
|
|
<ul>
|
|
{cls.docblock && <Marked>
|
|
{removeCommentsFromDocblock(cls.docblock)}
|
|
</Marked>}
|
|
{this.renderMethods(cls.methods, namedTypes)}
|
|
{this.renderProperties(cls.properties)}
|
|
</ul>
|
|
</span>
|
|
);
|
|
})}
|
|
</div>
|
|
</span>
|
|
);
|
|
},
|
|
|
|
renderTypeDef: function(typedef, namedTypes) {
|
|
return (
|
|
<TypeDef
|
|
key={typedef.name}
|
|
name={typedef.name}
|
|
description={typedef.description}
|
|
type={typedef.type}
|
|
properties={typedef.properties}
|
|
values={typedef.values}
|
|
apiName={this.props.apiName}
|
|
namedTypes={namedTypes}
|
|
/>
|
|
);
|
|
},
|
|
|
|
renderTypeDefs: function(typedefs, namedTypes) {
|
|
if (!typedefs || !typedefs.length) {
|
|
return null;
|
|
}
|
|
return (
|
|
<span>
|
|
<Header level={3}>Type Definitions</Header>
|
|
<div className="props">
|
|
{typedefs.map((typedef) => {
|
|
return this.renderTypeDef(typedef, namedTypes);
|
|
})}
|
|
</div>
|
|
</span>
|
|
);
|
|
},
|
|
|
|
renderMainDescription: function(content) {
|
|
if (content.docblock) {
|
|
return (
|
|
<Marked>
|
|
{removeCommentsFromDocblock(content.docblock)}
|
|
</Marked>
|
|
);
|
|
}
|
|
if (content.class && content.class.length && content.class[0].description) {
|
|
return (
|
|
<Marked>
|
|
{content.class[0].description}
|
|
</Marked>
|
|
);
|
|
}
|
|
return null;
|
|
},
|
|
|
|
render: function() {
|
|
var content = this.props.content;
|
|
if (!content.methods) {
|
|
throw new Error(
|
|
'No component methods found for ' + content.componentName
|
|
);
|
|
}
|
|
const namedTypes = getNamedTypes(content.typedef);
|
|
return (
|
|
<div>
|
|
{this.renderMainDescription(content)}
|
|
{this.renderMethods(content.methods, namedTypes)}
|
|
{this.renderProperties(content.properties)}
|
|
{this.renderClasses(content.classes, namedTypes)}
|
|
{this.renderTypeDefs(content.typedef, namedTypes)}
|
|
</div>
|
|
);
|
|
}
|
|
});
|
|
|
|
var Method = React.createClass({
|
|
renderTypehintRec: function(typehint) {
|
|
if (typehint.type === 'simple') {
|
|
return typehint.value;
|
|
}
|
|
|
|
if (typehint.type === 'generic') {
|
|
return this.renderTypehintRec(typehint.value[0]) + '<' + this.renderTypehintRec(typehint.value[1]) + '>';
|
|
}
|
|
|
|
return JSON.stringify(typehint);
|
|
|
|
},
|
|
|
|
renderTypehint: function(typehint) {
|
|
if (typeof typehint === 'object' && typehint.name) {
|
|
return renderType(typehint);
|
|
}
|
|
try {
|
|
var typehint = JSON.parse(typehint);
|
|
} catch (e) {
|
|
return typehint;
|
|
}
|
|
|
|
return this.renderTypehintRec(typehint);
|
|
},
|
|
|
|
renderMethodExamples: function(examples) {
|
|
if (!examples || !examples.length) {
|
|
return null;
|
|
}
|
|
return examples.map((example) => {
|
|
const re = /<caption>(.*?)<\/caption>/ig;
|
|
const result = re.exec(example);
|
|
const caption = result ? result[1] + ':' : 'Example:';
|
|
const code = example.replace(/<caption>.*?<\/caption>/ig, '')
|
|
.replace(/^\n\n/, '');
|
|
return (
|
|
<div>
|
|
<br/>
|
|
{caption}
|
|
<Prism>
|
|
{code}
|
|
</Prism>
|
|
</div>
|
|
);
|
|
});
|
|
},
|
|
|
|
renderMethodParameters: function(params) {
|
|
if (!params || !params.length) {
|
|
return null;
|
|
}
|
|
if (!params[0].type || !params[0].type.names) {
|
|
return null;
|
|
}
|
|
const foundDescription = params.find(p => p.description);
|
|
if (!foundDescription) {
|
|
return null;
|
|
}
|
|
return (
|
|
<div>
|
|
<strong>Parameters:</strong>
|
|
<table className="params">
|
|
<thead>
|
|
<tr>
|
|
<th>Name and Type</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{params.map((param) => {
|
|
return (
|
|
<tr>
|
|
<td>
|
|
{param.optional ? '[' + param.name + ']' : param.name}
|
|
<br/><br/>
|
|
{renderTypeWithLinks(param.type, this.props.apiName, this.props.namedTypes)}
|
|
</td>
|
|
<td className="description"><Marked>{param.description}</Marked></td>
|
|
</tr>
|
|
);
|
|
})}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
);
|
|
},
|
|
|
|
render: function() {
|
|
return (
|
|
<div className="prop">
|
|
<Header level={4} className="methodTitle" toSlug={this.props.name}>
|
|
{this.props.modifiers && this.props.modifiers.length && <span className="methodType">
|
|
{this.props.modifiers.join(' ') + ' '}
|
|
</span> || ''}
|
|
{this.props.name}
|
|
<span className="methodType">
|
|
({(this.props.params && this.props.params.length && this.props.params
|
|
.map((param) => {
|
|
var res = param.name;
|
|
res += param.optional ? '?' : '';
|
|
param.type && param.type.names && (res += ': ' + param.type.names.join(', '));
|
|
return res;
|
|
})
|
|
.join(', ')) || ''})
|
|
{this.props.returns && ': ' + this.renderTypehint(this.props.returns.type)}
|
|
</span>
|
|
</Header>
|
|
{this.props.description && <Marked>
|
|
{this.props.description}
|
|
</Marked>}
|
|
{this.renderMethodParameters(this.props.params)}
|
|
{this.renderMethodExamples(this.props.examples)}
|
|
</div>
|
|
);
|
|
},
|
|
});
|
|
|
|
var TypeDef = React.createClass({
|
|
renderProperties: function(properties) {
|
|
if (!properties || !properties.length) {
|
|
return null;
|
|
}
|
|
if (!properties[0].type || !properties[0].type.names) {
|
|
return null;
|
|
}
|
|
return (
|
|
<div>
|
|
<br/>
|
|
<strong>Properties:</strong>
|
|
<table className="params">
|
|
<thead>
|
|
<tr>
|
|
<th>Name and Type</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{properties.map((property) => {
|
|
return (
|
|
<tr>
|
|
<td>
|
|
{property.optional ? '[' + property.name + ']' : property.name}
|
|
<br/><br/>
|
|
{renderTypeWithLinks(property.type, this.props.apiName, this.props.namedTypes)}
|
|
</td>
|
|
<td className="description"><Marked>{property.description}</Marked></td>
|
|
</tr>
|
|
);
|
|
})}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
);
|
|
},
|
|
|
|
renderValues: function(values) {
|
|
if (!values || !values.length) {
|
|
return null;
|
|
}
|
|
if (!values[0].type || !values[0].type.names) {
|
|
return null;
|
|
}
|
|
return (
|
|
<div>
|
|
<br/>
|
|
<strong>Constants:</strong>
|
|
<table className="params">
|
|
<thead>
|
|
<tr>
|
|
<th>Value</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{values.map((value) => {
|
|
return (
|
|
<tr>
|
|
<td>
|
|
{value.name}
|
|
</td>
|
|
<td className="description"><Marked>{value.description}</Marked></td>
|
|
</tr>
|
|
);
|
|
})}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
);
|
|
},
|
|
|
|
render: function() {
|
|
return (
|
|
<div className="prop">
|
|
<Header level={4} className="propTitle" toSlug={this.props.name}>
|
|
{this.props.name}
|
|
</Header>
|
|
{this.props.description && <Marked>
|
|
{this.props.description}
|
|
</Marked>}
|
|
<strong>Type:</strong>
|
|
<br/>
|
|
{this.props.type.names.join(' | ')}
|
|
{this.renderProperties(this.props.properties)}
|
|
{this.renderValues(this.props.values)}
|
|
</div>
|
|
);
|
|
},
|
|
});
|
|
|
|
var EmbeddedSimulator = React.createClass({
|
|
render: function() {
|
|
if (!this.props.shouldRender) {
|
|
return null;
|
|
}
|
|
|
|
var metadata = this.props.metadata;
|
|
|
|
var imagePreview = metadata.platform === 'android'
|
|
? <img alt="Run example in simulator" width="170" height="338" src="img/uiexplorer_main_android.png" />
|
|
: <img alt="Run example in simulator" width="170" height="356" src="img/uiexplorer_main_ios.png" />;
|
|
|
|
return (
|
|
<div className="embedded-simulator">
|
|
<p><a className="modal-button-open"><strong>Run this example</strong></a></p>
|
|
<div className="modal-button-open modal-button-open-img">
|
|
{imagePreview}
|
|
</div>
|
|
<Modal metadata={metadata} />
|
|
</div>
|
|
);
|
|
}
|
|
});
|
|
|
|
var Modal = React.createClass({
|
|
render: function() {
|
|
var metadata = this.props.metadata;
|
|
var appParams = {route: metadata.title};
|
|
var encodedParams = encodeURIComponent(JSON.stringify(appParams));
|
|
var url = metadata.platform === 'android'
|
|
? `https://appetize.io/embed/q7wkvt42v6bkr0pzt1n0gmbwfr?device=nexus5&scale=65&autoplay=false&orientation=portrait&deviceColor=white¶ms=${encodedParams}`
|
|
: `https://appetize.io/embed/7vdfm9h3e6vuf4gfdm7r5rgc48?device=iphone6s&scale=60&autoplay=false&orientation=portrait&deviceColor=white¶ms=${encodedParams}`;
|
|
|
|
return (
|
|
<div>
|
|
<div className="modal">
|
|
<div className="modal-content">
|
|
<button className="modal-button-close">×</button>
|
|
<div className="center">
|
|
<iframe className="simulator" src={url} width="256" height="550" frameborder="0" scrolling="no" />
|
|
<p>Powered by <a target="_blank" href="https://appetize.io">appetize.io</a></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="modal-backdrop" />
|
|
</div>
|
|
);
|
|
}
|
|
});
|
|
|
|
var Autodocs = React.createClass({
|
|
childContextTypes: {
|
|
permalink: React.PropTypes.string,
|
|
version: React.PropTypes.string
|
|
},
|
|
|
|
getChildContext: function() {
|
|
return {
|
|
permalink: this.props.metadata.permalink,
|
|
version: Metadata.config.RN_VERSION || 'next'
|
|
};
|
|
},
|
|
|
|
renderFullDescription: function(docs) {
|
|
if (!docs.fullDescription) {
|
|
return;
|
|
}
|
|
return (
|
|
<div>
|
|
<Header level={1}>Description</Header>
|
|
<Marked>
|
|
{docs.fullDescription}
|
|
</Marked>
|
|
<Footer path={'docs/' + docs.componentName + '.md'} />
|
|
</div>
|
|
);
|
|
},
|
|
|
|
renderExample: function(example, metadata) {
|
|
if (!example) {
|
|
return;
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<HeaderWithGithub
|
|
title={example.title || 'Examples'}
|
|
level={example.title ? 4 : 3}
|
|
path={example.path}
|
|
metadata={metadata}
|
|
/>
|
|
<div className="example-container">
|
|
<Prism>
|
|
{example.content.replace(/^[\s\S]*?\*\//, '').trim()}
|
|
</Prism>
|
|
<EmbeddedSimulator shouldRender={metadata.runnable} metadata={metadata} />
|
|
</div>
|
|
</div>
|
|
);
|
|
},
|
|
|
|
renderExamples: function(docs, metadata) {
|
|
if (!docs.examples || !docs.examples.length) {
|
|
return;
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
{(docs.examples.length > 1) ? <Header level={3}>Examples</Header> : null}
|
|
{docs.examples.map(example => this.renderExample(example, metadata))}
|
|
</div>
|
|
);
|
|
},
|
|
|
|
render: function() {
|
|
var metadata = this.props.metadata;
|
|
var docs = JSON.parse(this.props.children);
|
|
var content = docs.type === 'component' || docs.type === 'style' ?
|
|
<ComponentDoc content={docs} /> :
|
|
<APIDoc content={docs} apiName={metadata.title} />;
|
|
|
|
return (
|
|
<Site
|
|
section="docs"
|
|
title={metadata.title} >
|
|
<section className="content wrap documentationContent">
|
|
<DocsSidebar metadata={metadata} />
|
|
<div className="inner-content">
|
|
<a id="content" />
|
|
<Header level={1}>{metadata.title}</Header>
|
|
{content}
|
|
<Footer path={metadata.path} />
|
|
{this.renderFullDescription(docs)}
|
|
{this.renderExamples(docs, metadata)}
|
|
<div className="docs-prevnext">
|
|
{metadata.previous && <a className="docs-prev" href={'docs/' + metadata.previous + '.html#content'}>← Prev</a>}
|
|
{metadata.next && <a className="docs-next" href={'docs/' + metadata.next + '.html#content'}>Next →</a>}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</Site>
|
|
);
|
|
}
|
|
});
|
|
|
|
module.exports = Autodocs;
|