/** * 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 ? ?{baseType} : baseType; } function spanJoinMapper(elements, callback, separator) { return {elements.map((rawElement, ii) => { const el = callback(rawElement); return (ii + 1 < elements.length) ? {el}{separator} : el; })}; } 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 {'{'}{spanJoinMapper( Object.keys(type.value), (key) => {key + ': '}{renderType(type.value[key])}, ', ' )}{'}'}; } if (type.name === 'union') { if (type.value) { return spanJoinMapper(type.value, renderType, ', '); } return spanJoinMapper(type.elements, renderType, ' | '); } if (type.name === 'arrayOf') { return [{renderType(type.value)}]; } 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 {name}#style; } if (type.raw === 'ColorPropType') { return color; } 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 {typeName}; } function renderTypeWithLinks(type, docTitle, namedTypes) { if (!type || !type.names) { return null; } const docPath = docTitle ? 'docs/' + docTitle.toLowerCase() + '.html' : 'docs/'; return (
{ type.names.map((typeName, index, array) => { const separator = index < array.length - 1 && ' | '; return ( {renderTypeNameLink(typeName, docPath, namedTypes)} {separator} ); }) }
); } 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 (
{prop.platforms && prop.platforms.map(platform => {platform} )} {name} {prop.required ? ': ' : '?: '} {(prop.type || prop.flowType) && {renderType(prop.flowType || prop.type)} }
{prop.deprecationMessage &&
Deprecated
{prop.deprecationMessage}
} {prop.type && prop.type.name === 'stylesheet' && this.renderStylesheetProps(prop.type.value)} {prop.description && {prop.description}}
); }, renderCompose: function(name) { return (
{name} props...
); }, renderStylesheetProp: function(name, prop) { return (
{prop.platforms && prop.platforms.map(platform => {platform} )} {name} {' '} {prop.type && {renderType(prop.type)} } {' '} {prop.description && {prop.description}}
); }, renderStylesheetProps: function(stylesheetName) { var style = this.props.content.styles[stylesheetName]; this.extractPlatformFromProps(style.props); return (
{(style.composes || []).map((name) => { var link; if (name === 'LayoutPropTypes') { name = 'Layout Props'; link = {name}...; } else if (name === 'ShadowPropTypesIOS') { name = 'Shadow Props'; link = {name}...; } else if (name === 'TransformPropTypes') { name = 'Transforms'; link = {name}...; } else { name = name.replace('StylePropTypes', ''); link = {name}#style...; } return (
{link}
); })} {Object.keys(style.props) .sort(sortByPlatform.bind(null, style.props)) .map((name) => this.renderStylesheetProp(name, style.props[name])) }
); }, renderProps: function(props, composes) { return (
{(composes || []).map((name) => this.renderCompose(name) )} {Object.keys(props) .sort(sortByPlatform.bind(null, props)) .map((name) => this.renderProp(name, props[name])) }
); }, 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 ( ); }, renderMethods: function(methods, namedTypes) { if (!methods || !methods.length) { return null; } return (
Methods
{methods.filter((method) => { return method.name[0] !== '_'; }).map(method => this.renderMethod(method, namedTypes))}
); }, renderTypeDef: function(typedef, namedTypes) { return ( ); }, renderTypeDefs: function(typedefs, namedTypes) { if (!typedefs || !typedefs.length) { return null; } return (
Type Definitions
{typedefs.map((typedef) => { return this.renderTypeDef(typedef, namedTypes); })}
); }, render: function() { var content = this.props.content; this.extractPlatformFromProps(content.props); const namedTypes = getNamedTypes(content.typedef); return (
{content.description}
Props
{this.renderProps(content.props, content.composes)} {this.renderMethods(content.methods, namedTypes)} {this.renderTypeDefs(content.typedef, namedTypes)}
); } }); var APIDoc = React.createClass({ renderMethod: function(method, namedTypes) { return ( ); }, renderMethods: function(methods, namedTypes) { if (!methods.length) { return null; } return (
Methods
{methods.filter((method) => { return method.name[0] !== '_'; }).map(method => this.renderMethod(method, namedTypes))}
); }, renderProperty: function(property) { return (
{property.name} {(property.type || property.flowType) && {': ' + renderType(property.flowType || property.type)} }
{property.docblock && {removeCommentsFromDocblock(property.docblock)} }
); }, renderProperties: function(properties) { if (!properties || !properties.length) { return null; } return (
Properties
{properties.filter((property) => { return property.name[0] !== '_'; }).map(this.renderProperty)}
); }, renderClasses: function(classes, namedTypes) { if (!classes || !classes.length) { return null; } return (
{classes.filter((cls) => { return cls.name[0] !== '_' && cls.ownerProperty[0] !== '_'; }).map((cls) => { return (
class {cls.name}
    {cls.docblock && {removeCommentsFromDocblock(cls.docblock)} } {this.renderMethods(cls.methods, namedTypes)} {this.renderProperties(cls.properties)}
); })}
); }, renderTypeDef: function(typedef, namedTypes) { return ( ); }, renderTypeDefs: function(typedefs, namedTypes) { if (!typedefs || !typedefs.length) { return null; } return (
Type Definitions
{typedefs.map((typedef) => { return this.renderTypeDef(typedef, namedTypes); })}
); }, renderMainDescription: function(content) { if (content.docblock) { return ( {removeCommentsFromDocblock(content.docblock)} ); } if (content.class && content.class.length && content.class[0].description) { return ( {content.class[0].description} ); } 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 (
{this.renderMainDescription(content)} {this.renderMethods(content.methods, namedTypes)} {this.renderProperties(content.properties)} {this.renderClasses(content.classes, namedTypes)} {this.renderTypeDefs(content.typedef, namedTypes)}
); } }); 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>/ig; const result = re.exec(example); const caption = result ? result[1] + ':' : 'Example:'; const code = example.replace(/.*?<\/caption>/ig, '') .replace(/^\n\n/, ''); return (

{caption} {code}
); }); }, 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 (
Parameters: {params.map((param) => { return ( ); })}
Name and Type Description
{param.optional ? '[' + param.name + ']' : param.name}

{renderTypeWithLinks(param.type, this.props.apiName, this.props.namedTypes)}
{param.description}
); }, render: function() { return (
{this.props.modifiers && this.props.modifiers.length && {this.props.modifiers.join(' ') + ' '} || ''} {this.props.name} ({(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)}
{this.props.description && {this.props.description} } {this.renderMethodParameters(this.props.params)} {this.renderMethodExamples(this.props.examples)}
); }, }); var TypeDef = React.createClass({ renderProperties: function(properties) { if (!properties || !properties.length) { return null; } if (!properties[0].type || !properties[0].type.names) { return null; } return (

Properties: {properties.map((property) => { return ( ); })}
Name and Type Description
{property.optional ? '[' + property.name + ']' : property.name}

{renderTypeWithLinks(property.type, this.props.apiName, this.props.namedTypes)}
{property.description}
); }, renderValues: function(values) { if (!values || !values.length) { return null; } if (!values[0].type || !values[0].type.names) { return null; } return (

Constants: {values.map((value) => { return ( ); })}
Value Description
{value.name} {value.description}
); }, render: function() { return (
{this.props.name}
{this.props.description && {this.props.description} } Type:
{this.props.type.names.join(' | ')} {this.renderProperties(this.props.properties)} {this.renderValues(this.props.values)}
); }, }); var EmbeddedSimulator = React.createClass({ render: function() { if (!this.props.shouldRender) { return null; } var metadata = this.props.metadata; var imagePreview = metadata.platform === 'android' ? Run example in simulator : Run example in simulator; return (

Run this example

{imagePreview}
); } }); 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 (