react-native/website/layout/AutodocsLayout.js

458 lines
12 KiB
JavaScript
Raw Normal View History

2015-03-05 02:10:12 +00:00
/**
2015-03-23 17:55:49 +00:00
* 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.
*
2015-03-05 02:10:12 +00:00
* @providesModule AutodocsLayout
*/
var DocsSidebar = require('DocsSidebar');
var H = require('Header');
2015-03-05 02:10:12 +00:00
var Header = require('Header');
var Marked = require('Marked');
var Prism = require('Prism');
2015-03-05 02:10:12 +00:00
var React = require('React');
var Site = require('Site');
var slugify = require('slugify');
2015-03-05 02:10:12 +00:00
2015-03-19 21:05:07 +00:00
var styleReferencePattern = /^[^.]+\.propTypes\.style$/;
2015-03-05 02:10:12 +00:00
function renderType(type) {
if (type.name === 'enum') {
if (typeof type.value === 'string') {
return type.value;
2015-03-09 20:25:01 +00:00
}
return 'enum(' + type.value.map((v) => v.value).join(', ') + ')';
}
2015-03-09 20:25:01 +00:00
if (type.name === 'shape') {
return '{' + Object.keys(type.value).map((key => key + ': ' + renderType(type.value[key]))).join(', ') + '}';
}
2015-03-09 20:25:01 +00:00
if (type.name == 'union') {
return type.value.map(renderType).join(', ');
}
if (type.name === 'arrayOf') {
return '[' + renderType(type.value) + ']';
}
2015-03-09 20:25:01 +00:00
if (type.name === 'instanceOf') {
return type.value;
}
2015-03-09 20:25:01 +00:00
if (type.name === 'custom') {
if (styleReferencePattern.test(type.raw)) {
var name = type.raw.substring(0, type.raw.indexOf('.'));
return <a href={slugify(name) + '.html#style'}>{name}#style</a>
2015-03-09 20:25:01 +00:00
}
if (type.raw === 'EdgeInsetsPropType') {
return '{top: number, left: number, bottom: number, right: number}';
2015-03-19 21:05:07 +00:00
}
return type.raw;
}
2015-03-19 21:05:07 +00:00
if (type.name === 'stylesheet') {
return 'style';
}
2015-03-19 20:55:42 +00:00
if (type.name === 'func') {
return 'function';
}
return type.name;
}
2015-03-12 18:03:32 +00:00
var ComponentDoc = React.createClass({
2015-03-05 02:10:12 +00:00
renderProp: function(name, prop) {
return (
<div className="prop" key={name}>
2015-03-05 02:10:12 +00:00
<Header level={4} className="propTitle" toSlug={name}>
{prop.platforms && prop.platforms.map(platform =>
<span className="platform">{platform}</span>
)}
2015-03-05 02:10:12 +00:00
{name}
{' '}
2015-03-09 20:25:01 +00:00
{prop.type && <span className="propType">
{renderType(prop.type)}
2015-03-09 20:25:01 +00:00
</span>}
</Header>
2015-03-19 21:05:07 +00:00
{prop.type && prop.type.name === 'stylesheet' &&
this.renderStylesheetProps(prop.type.value)}
{prop.description && <Marked>{prop.description}</Marked>}
2015-03-05 02:10:12 +00:00
</div>
);
},
2015-03-12 18:03:32 +00:00
renderCompose: function(name) {
return (
<div className="prop" key={name}>
<Header level={4} className="propTitle" toSlug={name}>
2015-05-10 00:05:33 +00:00
<a href={slugify(name) + '.html#props'}>{name} props...</a>
</Header>
</div>
);
},
2015-03-12 18:03:32 +00:00
2015-03-19 21:05:07 +00:00
renderStylesheetProps: function(stylesheetName) {
var style = this.props.content.styles[stylesheetName];
return (
<div className="compactProps">
{(style.composes || []).map((name) => {
var link;
2015-05-07 19:16:48 +00:00
if (name === 'LayoutPropTypes') {
2015-03-23 22:22:47 +00:00
name = 'Flexbox';
2015-03-19 21:05:07 +00:00
link =
<a href={slugify(name) + '.html#proptypes'}>{name}...</a>;
2015-05-07 19:16:48 +00:00
} else if (name === 'TransformPropTypes') {
name = 'Transforms';
link =
<a href={slugify(name) + '.html#proptypes'}>{name}...</a>;
} else {
name = name.replace('StylePropTypes', '');
link =
<a href={slugify(name) + '.html#style'}>{name}#style...</a>;
2015-03-19 21:05:07 +00:00
}
return (
<div className="prop" key={name}>
<h6 className="propTitle">{link}</h6>
</div>
);
})}
{Object.keys(style.props).map((name) =>
2015-03-19 21:05:07 +00:00
<div className="prop" key={name}>
<h6 className="propTitle">
{name}
{' '}
{style.props[name].type && <span className="propType">
{renderType(style.props[name].type)}
2015-03-19 21:05:07 +00:00
</span>}
</h6>
</div>
)}
</div>
);
},
renderProps: function(props, composes) {
return (
<div className="props">
{(composes || []).map((name) =>
this.renderCompose(name)
)}
{Object.keys(props)
2015-08-08 17:28:05 +00:00
.sort((nameA, nameB) => {
var a = props[nameA];
var b = props[nameB];
if (a.platforms && !b.platforms) {
return 1;
}
if (b.platforms && !a.platforms) {
return -1;
}
2015-08-08 17:28:05 +00:00
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
return 0;
})
.map((name) =>
this.renderProp(name, props[name])
)}
</div>
2015-03-05 02:10:12 +00:00
);
},
2015-03-12 18:03:32 +00:00
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;
}
},
2015-03-12 18:03:32 +00:00
render: function() {
var content = this.props.content;
this.extractPlatformFromProps(content.props);
2015-03-12 18:03:32 +00:00
return (
<div>
<Marked>
{content.description}
</Marked>
<HeaderWithGithub
title="Props"
path={content.filepath}
/>
2015-03-12 18:03:32 +00:00
{this.renderProps(content.props, content.composes)}
</div>
);
}
});
var APIDoc = React.createClass({
removeCommentsFromDocblock: function(docblock) {
return docblock
.trim('\n ')
.replace(/^\/\*+/, '')
.replace(/\*\/$/, '')
.split('\n')
.map(function(line) {
return line.trim().replace(/^\* ?/, '');
2015-03-12 18:03:32 +00:00
})
.join('\n');
},
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) {
try {
var typehint = JSON.parse(typehint);
} catch(e) {
return typehint;
}
return this.renderTypehintRec(typehint);
},
2015-03-12 18:03:32 +00:00
renderMethod: function(method) {
return (
<div className="prop" key={method.name}>
<Header level={4} className="propTitle" toSlug={method.name}>
{method.modifiers.length && <span className="propType">
{method.modifiers.join(' ') + ' '}
</span> || ''}
2015-03-19 20:55:42 +00:00
{method.name}
2015-03-12 18:03:32 +00:00
<span className="propType">
2015-03-19 20:55:42 +00:00
({method.params
.map((param) => {
2015-03-12 18:36:45 +00:00
var res = param.name;
if (param.typehint) {
res += ': ' + this.renderTypehint(param.typehint);
2015-03-12 18:36:45 +00:00
}
return res;
})
2015-03-19 20:55:42 +00:00
.join(', ')})
2015-03-12 18:03:32 +00:00
</span>
</Header>
{method.docblock && <Marked>
{this.removeCommentsFromDocblock(method.docblock)}
</Marked>}
2015-03-12 18:03:32 +00:00
</div>
);
},
renderMethods: function(methods) {
2015-03-25 21:26:46 +00:00
if (!methods.length) {
return null;
}
2015-03-12 18:03:32 +00:00
return (
2015-03-25 21:26:46 +00:00
<span>
<H level={3}>Methods</H>
<div className="props">
{methods.filter((method) => {
return method.name[0] !== '_';
}).map(this.renderMethod)}
</div>
</span>
2015-03-12 18:03:32 +00:00
);
},
renderProperty: function(property) {
return (
<div className="prop" key={property.name}>
<Header level={4} className="propTitle" toSlug={property.name}>
{property.name}
{property.type &&
<span className="propType">
{': ' + renderType(property.type)}
</span>
}
</Header>
{property.docblock && <Marked>
{this.removeCommentsFromDocblock(property.docblock)}
</Marked>}
</div>
);
},
renderProperties: function(properties) {
if (!properties || !properties.length) {
return null;
}
return (
<span>
<H level={3}>Properties</H>
<div className="props">
{properties.filter((property) => {
return property.name[0] !== '_';
}).map(this.renderProperty)}
</div>
</span>
);
},
renderClasses: function(classes) {
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>
{this.renderMethods(cls.methods)}
{this.renderProperties(cls.properties)}
</ul>
</span>
);
})}
</div>
</span>
);
},
2015-03-12 18:03:32 +00:00
render: function() {
var content = this.props.content;
if (!content.methods) {
throw new Error(
'No component methods found for ' + content.componentName
);
2015-03-12 18:03:32 +00:00
}
return (
<div>
<Marked>
{this.removeCommentsFromDocblock(content.docblock)}
</Marked>
{this.renderMethods(content.methods)}
{this.renderProperties(content.properties)}
{this.renderClasses(content.classes)}
2015-03-12 18:03:32 +00:00
</div>
);
}
});
var HeaderWithGithub = React.createClass({
renderRunnableLink: function() {
if (this.props.metadata && this.props.metadata.runnable) {
return (
<a
className="run-example"
target="_blank"
href={'https://rnplay.org/apps/l3Zi2g?route='+this.props.metadata.title+'&file=' + this.props.metadata.title+ "Example.js"}>
Run this example
</a>
);
}
},
render: function() {
return (
<H level={3} toSlug={this.props.title}>
<a
className="edit-github"
href={'https://github.com/facebook/react-native/blob/master/' + this.props.path}>
Edit on GitHub
</a>
{this.renderRunnableLink()}
{this.props.title}
</H>
);
}
});
2015-03-12 18:03:32 +00:00
var Autodocs = React.createClass({
renderFullDescription: function(docs) {
if (!docs.fullDescription) {
return;
}
return (
<div>
<HeaderWithGithub
title="Description"
path={'docs/' + docs.componentName + '.md'}
/>
<Marked>
{docs.fullDescription}
</Marked>
</div>
);
},
renderExample: function(docs, metadata) {
if (!docs.example) {
return;
}
return (
<div>
<HeaderWithGithub
title="Examples"
path={docs.example.path}
metadata={metadata}
/>
<Prism>
2015-04-01 15:53:49 +00:00
{docs.example.content.replace(/^[\s\S]*?\*\//, '').trim()}
</Prism>
</div>
);
},
2015-03-05 02:10:12 +00:00
render: function() {
var metadata = this.props.metadata;
2015-03-19 21:05:07 +00:00
var docs = JSON.parse(this.props.children);
var content = docs.type === 'component' || docs.type === 'style' ?
<ComponentDoc content={docs} /> :
<APIDoc content={docs} apiName={metadata.title} />;
2015-03-19 21:05:07 +00:00
2015-03-05 02:10:12 +00:00
return (
<Site section="docs" title={metadata.title}>
2015-03-05 02:10:12 +00:00
<section className="content wrap documentationContent">
<DocsSidebar metadata={metadata} />
<div className="inner-content">
<a id="content" />
<h1>{metadata.title}</h1>
2015-03-19 21:05:07 +00:00
{content}
{this.renderFullDescription(docs)}
{this.renderExample(docs, metadata)}
2015-03-05 02:10:12 +00:00
<div className="docs-prevnext">
{metadata.previous && <a className="docs-prev" href={metadata.previous + '.html#content'}>&larr; Prev</a>}
{metadata.next && <a className="docs-next" href={metadata.next + '.html#content'}>Next &rarr;</a>}
</div>
</div>
</section>
</Site>
);
}
});
module.exports = Autodocs;