Display component methods on the website and tweak the documentation

Summary:The website now displays public methods on components. This was implemented mostly in react-docgen via #66. This adds a <Method> component that is used by the component and API doc pages to display documentation for a method.

It also adds some missing documentation and tweak some existing one to integrate with this feature. I also prefixed some component methods with an '_' so they don't show up in the doc.

**Test plan (required)**

Tested every component page locally to make sure the methods doc was displayed properly.
Tested an API page to make sure it still worked properly.
Closes https://github.com/facebook/react-native/pull/6890

Differential Revision: D3159911

Pulled By: vjeux

fb-gh-sync-id: 1e6a4640cda6794496d9844c1af6a1451c017dcc
fbshipit-source-id: 1e6a4640cda6794496d9844c1af6a1451c017dcc
This commit is contained in:
Janic Duplessis 2016-04-09 11:12:46 -07:00 committed by Facebook Github Bot 1
parent 2eafcd45db
commit 49fdd99633
14 changed files with 297 additions and 152 deletions

View File

@ -223,7 +223,10 @@ var DrawerLayoutAndroid = React.createClass({
}
},
openDrawer: function() {
/**
* Opens the drawer.
*/
openDrawer: function(test: number) {
UIManager.dispatchViewManagerCommand(
this._getDrawerLayoutHandle(),
UIManager.AndroidDrawerLayout.Commands.openDrawer,
@ -231,6 +234,9 @@ var DrawerLayoutAndroid = React.createClass({
);
},
/**
* Closes the drawer.
*/
closeDrawer: function() {
UIManager.dispatchViewManagerCommand(
this._getDrawerLayoutHandle(),

View File

@ -143,20 +143,6 @@ type Event = Object;
* });
* ```
*
* A navigation object contains the following functions:
*
* - `push(route)` - Navigate forward to a new route
* - `pop()` - Go back one page
* - `popN(n)` - Go back N pages at once. When N=1, behavior matches `pop()`
* - `replace(route)` - Replace the route for the current page and immediately
* load the view for the new route
* - `replacePrevious(route)` - Replace the route/view for the previous page
* - `replacePreviousAndPop(route)` - Replaces the previous route/view and
* transitions back to it
* - `resetTo(route)` - Replaces the top item and popToTop
* - `popToRoute(route)` - Go back to the item for a particular route object
* - `popToTop()` - Go back to the top item
*
* Navigator functions are also available on the NavigatorIOS component:
*
* ```
@ -492,6 +478,9 @@ var NavigatorIOS = React.createClass({
this.navigationContext.emit('willfocus', {route: route});
},
/**
* Navigate forward to a new route
*/
push: function(route: Route) {
invariant(!!route, 'Must supply route to push');
// Make sure all previous requests are caught up first. Otherwise reject.
@ -514,6 +503,9 @@ var NavigatorIOS = React.createClass({
}
},
/**
* Go back N pages at once. When N=1, behavior matches `pop()`
*/
popN: function(n: number) {
if (n === 0) {
return;
@ -535,6 +527,9 @@ var NavigatorIOS = React.createClass({
}
},
/**
* Go back one page
*/
pop: function() {
this.popN(1);
},
@ -574,23 +569,30 @@ var NavigatorIOS = React.createClass({
},
/**
* Replaces the top of the navigation stack.
* Replace the route for the current page and immediately
* load the view for the new route.
*/
replace: function(route: Route) {
this.replaceAtIndex(route, -1);
},
/**
* Replace the current route's parent.
* Replace the route/view for the previous page.
*/
replacePrevious: function(route: Route) {
this.replaceAtIndex(route, -2);
},
/**
* Go back to the top item
*/
popToTop: function() {
this.popToRoute(this.state.routeStack[0]);
},
/**
* Go back to the item for a particular route object
*/
popToRoute: function(route: Route) {
var indexOfRoute = this.state.routeStack.indexOf(route);
invariant(
@ -601,6 +603,9 @@ var NavigatorIOS = React.createClass({
this.popN(numToPop);
},
/**
* Replaces the previous route/view and transitions back to it.
*/
replacePreviousAndPop: function(route: Route) {
// Make sure all previous requests are caught up first. Otherwise reject.
if (this.state.requestedTopOfStack !== this.state.observedTopOfStack) {
@ -618,6 +623,9 @@ var NavigatorIOS = React.createClass({
});
},
/**
* Replaces the top item and popToTop
*/
resetTo: function(route: Route) {
invariant(!!route, 'Must supply route to push');
// Make sure all previous requests are caught up first. Otherwise reject.
@ -628,7 +636,7 @@ var NavigatorIOS = React.createClass({
this.popToRoute(route);
},
handleNavigationComplete: function(e: Event) {
_handleNavigationComplete: function(e: Event) {
if (this._toFocusOnNavigationComplete) {
this._getFocusEmitter().emit('focus', this._toFocusOnNavigationComplete);
this._toFocusOnNavigationComplete = null;
@ -663,7 +671,7 @@ var NavigatorIOS = React.createClass({
);
},
renderNavigationStackItems: function() {
_renderNavigationStackItems: function() {
var shouldRecurseToNavigator =
this.state.makingNavigatorRequest ||
this.state.updatingAllIndicesAtOrBeyond !== null;
@ -678,7 +686,7 @@ var NavigatorIOS = React.createClass({
style={styles.transitioner}
vertical={this.props.vertical}
requestedTopOfStack={this.state.requestedTopOfStack}
onNavigationComplete={this.handleNavigationComplete}>
onNavigationComplete={this._handleNavigationComplete}>
{items}
</NavigatorTransitionerIOS>
</StaticContainer>
@ -688,7 +696,7 @@ var NavigatorIOS = React.createClass({
render: function() {
return (
<View style={this.props.style}>
{this.renderNavigationStackItems()}
{this._renderNavigationStackItems()}
</View>
);
},

View File

@ -341,6 +341,9 @@ var ScrollView = React.createClass({
this.refs[SCROLLVIEW].setNativeProps(props);
},
/**
* Deprecated. Use `RefreshControl` instead.
*/
endRefreshing: function() {
RCTScrollViewManager.endRefreshing(
ReactNative.findNodeHandle(this)
@ -367,9 +370,10 @@ var ScrollView = React.createClass({
/**
* Scrolls to a given x, y offset, either immediately or with a smooth animation.
*
* Syntax:
*
* scrollTo(options: {x: number = 0; y: number = 0; animated: boolean = true})
* `scrollTo(options: {x: number = 0; y: number = 0; animated: boolean = true})`
*
* Note: The weird argument signature is due to the fact that, for historical reasons,
* the function also accepts separate arguments as as alternative to the options object.
@ -397,7 +401,7 @@ var ScrollView = React.createClass({
this.scrollTo({x, y, animated: false});
},
handleScroll: function(e: Object) {
_handleScroll: function(e: Object) {
if (__DEV__) {
if (this.props.onScroll && !this.props.scrollEventThrottle && Platform.OS === 'ios') {
console.log(
@ -480,7 +484,7 @@ var ScrollView = React.createClass({
onStartShouldSetResponder: this.scrollResponderHandleStartShouldSetResponder,
onStartShouldSetResponderCapture: this.scrollResponderHandleStartShouldSetResponderCapture,
onScrollShouldSetResponder: this.scrollResponderHandleScrollShouldSetResponder,
onScroll: this.handleScroll,
onScroll: this._handleScroll,
onResponderGrant: this.scrollResponderHandleResponderGrant,
onResponderTerminationRequest: this.scrollResponderHandleTerminationRequest,
onResponderTerminate: this.scrollResponderHandleTerminate,

View File

@ -164,7 +164,7 @@ const StatusBar = React.createClass({
StatusBarManager.setNetworkActivityIndicatorVisible(visible);
},
setBackgroundColor(color, animated?: boolean) {
setBackgroundColor(color: string, animated?: boolean) {
if (Platform.OS !== 'android') {
console.warn('`setBackgroundColor` is only available on Android');
return;

View File

@ -319,6 +319,9 @@ var TextInput = React.createClass({
AndroidTextInput.viewConfig :
{})) : Object),
/**
* Returns if the input is currently focused.
*/
isFocused: function(): boolean {
return TextInputState.currentlyFocusedField() ===
ReactNative.findNodeHandle(this.refs.input);
@ -368,6 +371,9 @@ var TextInput = React.createClass({
isInAParentText: React.PropTypes.bool
},
/**
* Removes all text from the input.
*/
clear: function() {
this.setNativeProps({text: ''});
},

View File

@ -94,7 +94,7 @@ var TouchableHighlight = React.createClass({
getDefaultProps: () => DEFAULT_PROPS,
// Performance optimization to avoid constantly re-generating these objects.
computeSyntheticState: function(props) {
_computeSyntheticState: function(props) {
return {
activeProps: {
style: {
@ -115,7 +115,7 @@ var TouchableHighlight = React.createClass({
getInitialState: function() {
return merge(
this.touchableGetInitialState(), this.computeSyntheticState(this.props)
this.touchableGetInitialState(), this._computeSyntheticState(this.props)
);
},
@ -133,7 +133,7 @@ var TouchableHighlight = React.createClass({
if (nextProps.activeOpacity !== this.props.activeOpacity ||
nextProps.underlayColor !== this.props.underlayColor ||
nextProps.style !== this.props.style) {
this.setState(this.computeSyntheticState(nextProps));
this.setState(this._computeSyntheticState(nextProps));
}
},

View File

@ -83,36 +83,39 @@ var TouchableNativeFeedback = React.createClass({
/**
* Determines the type of background drawable that's going to be used to
* display feedback. It takes an object with `type` property and extra data
* depending on the `type`. It's recommended to use one of the following
* static methods to generate that dictionary:
*
* 1) TouchableNativeFeedback.SelectableBackground() - will create object
* that represents android theme's default background for selectable
* elements (?android:attr/selectableItemBackground)
*
* 2) TouchableNativeFeedback.SelectableBackgroundBorderless() - will create
* object that represent android theme's default background for borderless
* selectable elements (?android:attr/selectableItemBackgroundBorderless).
* Available on android API level 21+
*
* 3) TouchableNativeFeedback.Ripple(color, borderless) - will create
* object that represents ripple drawable with specified color (as a
* string). If property `borderless` evaluates to true the ripple will
* render outside of the view bounds (see native actionbar buttons as an
* example of that behavior). This background type is available on Android
* API level 21+
* depending on the `type`. It's recommended to use one of the static
* methods to generate that dictionary.
*/
background: backgroundPropType,
},
statics: {
/**
* Creates an object that represents android theme's default background for
* selectable elements (?android:attr/selectableItemBackground).
*/
SelectableBackground: function() {
return {type: 'ThemeAttrAndroid', attribute: 'selectableItemBackground'};
},
/**
* Creates an object that represent android theme's default background for borderless
* selectable elements (?android:attr/selectableItemBackgroundBorderless).
* Available on android API level 21+.
*/
SelectableBackgroundBorderless: function() {
return {type: 'ThemeAttrAndroid', attribute: 'selectableItemBackgroundBorderless'};
},
Ripple: function(color, borderless) {
/**
* Creates an object that represents ripple drawable with specified color (as a
* string). If property `borderless` evaluates to true the ripple will
* render outside of the view bounds (see native actionbar buttons as an
* example of that behavior). This background type is available on Android
* API level 21+.
*
* @param color The ripple color
* @param borderless If the ripple can render outside it's bounds
*/
Ripple: function(color: string, borderless: boolean) {
return {type: 'RippleAndroid', color: processColor(color), borderless: borderless};
},
},

View File

@ -81,7 +81,10 @@ var TouchableOpacity = React.createClass({
ensurePositiveDelayProps(nextProps);
},
setOpacityTo: function(value) {
/**
* Animate the touchable to a new opacity.
*/
setOpacityTo: function(value: number) {
Animated.timing(
this.state.anim,
{toValue: value, duration: 150}

View File

@ -312,9 +312,9 @@ var WebView = React.createClass({
decelerationRate={decelerationRate}
contentInset={this.props.contentInset}
automaticallyAdjustContentInsets={this.props.automaticallyAdjustContentInsets}
onLoadingStart={this.onLoadingStart}
onLoadingFinish={this.onLoadingFinish}
onLoadingError={this.onLoadingError}
onLoadingStart={this._onLoadingStart}
onLoadingFinish={this._onLoadingFinish}
onLoadingError={this._onLoadingError}
onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
scalesPageToFit={this.props.scalesPageToFit}
allowsInlineMediaPlayback={this.props.allowsInlineMediaPlayback}
@ -329,6 +329,9 @@ var WebView = React.createClass({
);
},
/**
* Go forward one page in the webview's history.
*/
goForward: function() {
UIManager.dispatchViewManagerCommand(
this.getWebViewHandle(),
@ -337,6 +340,9 @@ var WebView = React.createClass({
);
},
/**
* Go back one page in the webview's history.
*/
goBack: function() {
UIManager.dispatchViewManagerCommand(
this.getWebViewHandle(),
@ -345,6 +351,9 @@ var WebView = React.createClass({
);
},
/**
* Reloads the current page.
*/
reload: function() {
UIManager.dispatchViewManagerCommand(
this.getWebViewHandle(),
@ -357,23 +366,26 @@ var WebView = React.createClass({
* We return an event with a bunch of fields including:
* url, title, loading, canGoBack, canGoForward
*/
updateNavigationState: function(event: Event) {
_updateNavigationState: function(event: Event) {
if (this.props.onNavigationStateChange) {
this.props.onNavigationStateChange(event.nativeEvent);
}
},
/**
* Returns the native webview node.
*/
getWebViewHandle: function(): any {
return ReactNative.findNodeHandle(this.refs[RCT_WEBVIEW_REF]);
},
onLoadingStart: function(event: Event) {
_onLoadingStart: function(event: Event) {
var onLoadStart = this.props.onLoadStart;
onLoadStart && onLoadStart(event);
this.updateNavigationState(event);
this._updateNavigationState(event);
},
onLoadingError: function(event: Event) {
_onLoadingError: function(event: Event) {
event.persist(); // persist this event because we need to store it
var {onError, onLoadEnd} = this.props;
onError && onError(event);
@ -386,14 +398,14 @@ var WebView = React.createClass({
});
},
onLoadingFinish: function(event: Event) {
_onLoadingFinish: function(event: Event) {
var {onLoad, onLoadEnd} = this.props;
onLoad && onLoad(event);
onLoadEnd && onLoadEnd(event);
this.setState({
viewState: WebViewState.IDLE,
});
this.updateNavigationState(event);
this._updateNavigationState(event);
},
});

View File

@ -252,6 +252,11 @@ var ListView = React.createClass({
this.refs[SCROLLVIEW_REF].getScrollResponder();
},
/**
* Scrolls to a given x, y offset, either immediately or with a smooth animation.
*
* See `ScrollView#scrollTo`.
*/
scrollTo: function(...args) {
this.refs[SCROLLVIEW_REF] &&
this.refs[SCROLLVIEW_REF].scrollTo &&
@ -334,7 +339,7 @@ var ListView = React.createClass({
});
},
onRowHighlighted: function(sectionID, rowID) {
_onRowHighlighted: function(sectionID, rowID) {
this.setState({highlightedRow: {sectionID, rowID}});
},
@ -400,7 +405,7 @@ var ListView = React.createClass({
dataSource.getRowData(sectionIdx, rowIdx),
sectionID,
rowID,
this.onRowHighlighted
this._onRowHighlighted
)}
/>;
bodyComponents.push(row);

View File

@ -42,7 +42,6 @@ var TimerMixin = require('react-timer-mixin');
var View = require('View');
var clamp = require('clamp');
var deprecatedPropType = require('deprecatedPropType');
var flattenStyle = require('flattenStyle');
var invariant = require('fbjs/lib/invariant');
var rebound = require('rebound');
@ -159,30 +158,6 @@ var GESTURE_ACTIONS = [
* }
* />
* ```
*
* ### Navigator Methods
*
* If you have a ref to the Navigator element, you can invoke several methods
* on it to trigger navigation:
*
* - `getCurrentRoutes()` - returns the current list of routes
* - `jumpBack()` - Jump backward without unmounting the current scene
* - `jumpForward()` - Jump forward to the next scene in the route stack
* - `jumpTo(route)` - Transition to an existing scene without unmounting
* - `push(route)` - Navigate forward to a new scene, squashing any scenes
* that you could `jumpForward` to
* - `pop()` - Transition back and unmount the current scene
* - `replace(route)` - Replace the current scene with a new route
* - `replaceAtIndex(route, index)` - Replace a scene as specified by an index
* - `replacePrevious(route)` - Replace the previous scene
* - `resetTo(route)` - Navigate to a new scene and reset route stack
* - `immediatelyResetRouteStack(routeStack)` - Reset every scene with an
* array of routes
* - `popToRoute(route)` - Pop to a particular scene, as specified by its
* route. All scenes after it will be unmounted
* - `popToTop()` - Pop to the first scene in the stack, unmounting every
* other scene
*
*/
var Navigator = React.createClass({
@ -366,6 +341,8 @@ var Navigator = React.createClass({
},
/**
* Reset every scene with an array of routes.
*
* @param {RouteStack} nextRouteStack Next route stack to reinitialize. This
* doesn't accept stack item `id`s, which implies that all existing items are
* destroyed, and then potentially recreated according to `routeStack`. Does
@ -898,6 +875,9 @@ var Navigator = React.createClass({
this._transitionTo(destIndex);
},
/**
* Transition to an existing scene without unmounting
*/
jumpTo: function(route) {
var destIndex = this.state.routeStack.indexOf(route);
invariant(
@ -907,14 +887,24 @@ var Navigator = React.createClass({
this._jumpN(destIndex - this.state.presentedIndex);
},
/**
* Jump forward to the next scene in the route stack.
*/
jumpForward: function() {
this._jumpN(1);
},
/**
* Jump backward without unmounting the current scene.
*/
jumpBack: function() {
this._jumpN(-1);
},
/**
* Navigate forward to a new scene, squashing any scenes that you could
* `jumpForward` to.
*/
push: function(route) {
invariant(!!route, 'Must supply route to push');
var activeLength = this.state.presentedIndex + 1;
@ -956,6 +946,9 @@ var Navigator = React.createClass({
);
},
/**
* Transition back and unmount the current scene.
*/
pop: function() {
if (this.state.transitionQueue.length) {
// This is the workaround to prevent user from firing multiple `pop()`
@ -973,7 +966,7 @@ var Navigator = React.createClass({
},
/**
* Replace a route in the navigation stack.
* Replace a scene as specified by an index
*
* `index` specifies the route in the stack that should be replaced.
* If it's negative, it counts from the back.
@ -1008,23 +1001,30 @@ var Navigator = React.createClass({
},
/**
* Replaces the current scene in the stack.
* Replace the current scene with a new route.
*/
replace: function(route) {
this.replaceAtIndex(route, this.state.presentedIndex);
},
/**
* Replace the current route's parent.
* Replace the previous scene.
*/
replacePrevious: function(route) {
this.replaceAtIndex(route, this.state.presentedIndex - 1);
},
/**
* Pop to the first scene in the stack, unmounting every other scene.
*/
popToTop: function() {
this.popToRoute(this.state.routeStack[0]);
},
/**
* Pop to a particular scene, as specified by its route.
* All scenes after it will be unmounted.
*/
popToRoute: function(route) {
var indexOfRoute = this.state.routeStack.indexOf(route);
invariant(
@ -1035,6 +1035,9 @@ var Navigator = React.createClass({
this._popN(numToPop);
},
/**
* Replace the previous scene and pop to it.
*/
replacePreviousAndPop: function(route) {
if (this.state.routeStack.length < 2) {
return;
@ -1043,6 +1046,9 @@ var Navigator = React.createClass({
this.pop();
},
/**
* Navigate to a new scene and reset route stack.
*/
resetTo: function(route) {
invariant(!!route, 'Must supply route to push');
this.replaceAtIndex(route, 0, () => {
@ -1054,6 +1060,9 @@ var Navigator = React.createClass({
});
},
/**
* Returns the current list of routes.
*/
getCurrentRoutes: function() {
// Clone before returning to avoid caller mutating the stack
return this.state.routeStack.slice();

View File

@ -37,12 +37,22 @@ function renderType(type) {
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 '{' + Object.keys(type.value).map((key => key + ': ' + renderType(type.value[key]))).join(', ') + '}';
}
if (type.name === 'union') {
return type.value.map(renderType).join(', ');
if (type.value) {
return type.value.map(renderType).join(', ');
}
return type.elements.map(renderType).join(' | ');
}
if (type.name === 'arrayOf') {
@ -74,6 +84,11 @@ function renderType(type) {
if (type.name === 'func') {
return 'function';
}
if (type.name === 'signature') {
return type.raw;
}
return type.name;
}
@ -106,6 +121,18 @@ function sortByPlatform(props, nameA, nameB) {
return 0;
}
function removeCommentsFromDocblock(docblock) {
return docblock
.trim('\n ')
.replace(/^\/\*+/, '')
.replace(/\*\/$/, '')
.split('\n')
.map(function(line) {
return line.trim().replace(/^\* ?/, '');
})
.join('\n');
}
var ComponentDoc = React.createClass({
renderProp: function(name, prop) {
return (
@ -226,6 +253,35 @@ var ComponentDoc = React.createClass({
}
},
renderMethod: function(method) {
return (
<Method
key={method.name}
name={method.name}
description={method.description}
params={method.params}
modifiers={method.modifiers}
returns={method.returns}
/>
);
},
renderMethods: function(methods) {
if (!methods || !methods.length) {
return null;
}
return (
<span>
<H level={3}>Methods</H>
<div className="props">
{methods.filter((method) => {
return method.name[0] !== '_';
}).map(this.renderMethod)}
</div>
</span>
);
},
render: function() {
var content = this.props.content;
this.extractPlatformFromProps(content.props);
@ -236,71 +292,23 @@ var ComponentDoc = React.createClass({
</Marked>
<H level={3}>Props</H>
{this.renderProps(content.props, content.composes)}
{this.renderMethods(content.methods)}
</div>
);
}
});
var APIDoc = React.createClass({
removeCommentsFromDocblock: function(docblock) {
return docblock
.trim('\n ')
.replace(/^\/\*+/, '')
.replace(/\*\/$/, '')
.split('\n')
.map(function(line) {
return line.trim().replace(/^\* ?/, '');
})
.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);
},
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> || ''}
{method.name}
<span className="propType">
({method.params
.map((param) => {
var res = param.name;
if (param.typehint) {
res += ': ' + this.renderTypehint(param.typehint);
}
return res;
})
.join(', ')})
</span>
</Header>
{method.docblock && <Marked>
{this.removeCommentsFromDocblock(method.docblock)}
</Marked>}
</div>
<Method
key={method.name}
name={method.name}
description={method.docblock && removeCommentsFromDocblock(method.docblock)}
params={method.params}
modifiers={method.modifiers}
/>
);
},
@ -332,7 +340,7 @@ var APIDoc = React.createClass({
}
</Header>
{property.docblock && <Marked>
{this.removeCommentsFromDocblock(property.docblock)}
{removeCommentsFromDocblock(property.docblock)}
</Marked>}
</div>
);
@ -371,7 +379,7 @@ var APIDoc = React.createClass({
</Header>
<ul>
{cls.docblock && <Marked>
{this.removeCommentsFromDocblock(cls.docblock)}
{removeCommentsFromDocblock(cls.docblock)}
</Marked>}
{this.renderMethods(cls.methods)}
{this.renderProperties(cls.properties)}
@ -394,7 +402,7 @@ var APIDoc = React.createClass({
return (
<div>
<Marked>
{this.removeCommentsFromDocblock(content.docblock)}
{removeCommentsFromDocblock(content.docblock)}
</Marked>
{this.renderMethods(content.methods)}
{this.renderProperties(content.properties)}
@ -404,6 +412,62 @@ var APIDoc = React.createClass({
}
});
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);
},
render: function() {
return (
<div className="prop">
<Header level={4} className="propTitle" toSlug={this.props.name}>
{this.props.modifiers.length && <span className="propType">
{this.props.modifiers.join(' ') + ' '}
</span> || ''}
{this.props.name}
<span className="propType">
({this.props.params
.map((param) => {
var res = param.name;
if (param.type) {
res += ': ' + this.renderTypehint(param.type);
}
return res;
})
.join(', ')})
{this.props.returns && ': ' + this.renderTypehint(this.props.returns.type)}
</span>
</Header>
{this.props.description && <Marked>
{this.props.description}
</Marked>}
</div>
);
},
});
var EmbeddedSimulator = React.createClass({
render: function() {
if (!this.props.shouldRender) {

View File

@ -13,7 +13,7 @@
"mkdirp": "^0.5.1",
"optimist": "0.6.0",
"react": "~0.13.0",
"react-docgen": "^2.0.1",
"react-docgen": "^2.8.0",
"react-page-middleware": "git://github.com/facebook/react-page-middleware.git",
"request": "^2.69.0",
"semver-compare": "^1.0.0"

View File

@ -68,12 +68,36 @@ function getExample(componentName, componentPlatform) {
};
}
// Add methods that should not appear in the components documentation.
var methodsBlacklist = [
// Native methods mixin.
'getInnerViewNode',
'setNativeProps',
// Touchable mixin.
'touchableHandlePress' ,
'touchableHandleActivePressIn',
'touchableHandleActivePressOut',
'touchableHandleLongPress',
'touchableGetPressRectOffset',
'touchableGetHitSlop',
'touchableGetHighlightDelayMS',
'touchableGetLongPressDelayMS',
'touchableGetPressOutDelayMS',
// Scrollable mixin.
'getScrollableNode',
'getScrollResponder',
];
function filterMethods(method) {
return method.name[0] !== '_' && methodsBlacklist.indexOf(method.name) === -1;
}
// Determines whether a component should have a link to a runnable example
function isRunnable(componentName, componentPlatform) {
var path = '../Examples/UIExplorer/' + componentName + 'Example.js';
if (!fs.existsSync(path)) {
path = '../Examples/UIExplorer/' + componentName + 'Example.'+ componentPlatform +'.js';
path = '../Examples/UIExplorer/' + componentName + 'Example.' + componentPlatform + '.js';
if (!fs.existsSync(path)) {
return false;
}
@ -92,9 +116,6 @@ function shouldDisplayInSidebar(componentName) {
}
function getNextComponent(i) {
var next;
var filepath = all[i];
if (all[i + 1]) {
var nextComponentName = getNameFromPath(all[i + 1]);
@ -125,6 +146,10 @@ function componentsToMarkdown(type, json, filepath, i, styles) {
}
json.example = getExample(componentName, componentPlatform);
if (json.methods) {
json.methods = json.methods.filter(filterMethods);
}
// Put Flexbox into the Polyfills category
var category = (type === 'style' ? 'Polyfills' : type + 's');
var next = getNextComponent(i);