-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Split DocExplorer into smaller files (#243)
* Extract TypeLink out of DocExplorer * Extract SearchBox out of DocExplorer * Extract SearchDoc out of DocExplorer, renaming it to SearchResults Changed the name to obviate the need for the comment describing what th component is for. * Extract SchemaDoc from DocExplorer * Extract MarkdownContent from DocExplorer * Extract TypeDoc from DocExplorer * Extract FieldDoc from DocExplorer
- Loading branch information
1 parent
e005447
commit f45fbde
Showing
8 changed files
with
584 additions
and
511 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/** | ||
* Copyright (c) 2015, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the | ||
* LICENSE-examples file in the root directory of this source tree. | ||
*/ | ||
|
||
import React, { PropTypes } from 'react'; | ||
|
||
import MarkdownContent from './MarkdownContent'; | ||
import TypeLink from './TypeLink'; | ||
|
||
export default class FieldDoc extends React.Component { | ||
static propTypes = { | ||
field: PropTypes.object, | ||
onClickType: PropTypes.func, | ||
} | ||
|
||
shouldComponentUpdate(nextProps) { | ||
return this.props.field !== nextProps.field; | ||
} | ||
|
||
render() { | ||
const field = this.props.field; | ||
|
||
let argsDef; | ||
if (field.args && field.args.length > 0) { | ||
argsDef = ( | ||
<div className="doc-category"> | ||
<div className="doc-category-title"> | ||
{'arguments'} | ||
</div> | ||
{field.args.map(arg => | ||
<div key={arg.name} className="doc-category-item"> | ||
<div> | ||
<span className="arg-name">{arg.name}</span> | ||
{': '} | ||
<TypeLink type={arg.type} onClick={this.props.onClickType} /> | ||
</div> | ||
<MarkdownContent | ||
className="doc-value-description" | ||
markdown={arg.description} | ||
/> | ||
</div> | ||
)} | ||
</div> | ||
); | ||
} | ||
|
||
return ( | ||
<div> | ||
<MarkdownContent | ||
className="doc-type-description" | ||
markdown={field.description || 'No Description'} | ||
/> | ||
{ | ||
field.deprecationReason && | ||
<MarkdownContent | ||
className="doc-alert-text" | ||
markdown={field.deprecationReason} | ||
/> | ||
} | ||
<div className="doc-category"> | ||
<div className="doc-category-title"> | ||
{'type'} | ||
</div> | ||
<TypeLink type={field.type} onClick={this.props.onClickType} /> | ||
</div> | ||
{argsDef} | ||
</div> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/** | ||
* Copyright (c) 2015, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the | ||
* LICENSE-examples file in the root directory of this source tree. | ||
*/ | ||
|
||
import React, { PropTypes } from 'react'; | ||
import Marked from 'marked'; | ||
|
||
export default class MarkdownContent extends React.Component { | ||
static propTypes = { | ||
markdown: PropTypes.string, | ||
className: PropTypes.string, | ||
} | ||
|
||
shouldComponentUpdate(nextProps) { | ||
return this.props.markdown !== nextProps.markdown; | ||
} | ||
|
||
render() { | ||
const markdown = this.props.markdown; | ||
if (!markdown) { | ||
return <div />; | ||
} | ||
|
||
const html = Marked(markdown, { sanitize: true }); | ||
return ( | ||
<div | ||
className={this.props.className} | ||
dangerouslySetInnerHTML={{ __html: html }} | ||
/> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
/** | ||
* Copyright (c) 2015, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the | ||
* LICENSE-examples file in the root directory of this source tree. | ||
*/ | ||
|
||
import React, { PropTypes } from 'react'; | ||
|
||
import TypeLink from './TypeLink'; | ||
import MarkdownContent from './MarkdownContent'; | ||
|
||
// Render the top level Schema | ||
export default class SchemaDoc extends React.Component { | ||
static propTypes = { | ||
schema: PropTypes.object, | ||
onClickType: PropTypes.func, | ||
} | ||
|
||
shouldComponentUpdate(nextProps) { | ||
return this.props.schema !== nextProps.schema; | ||
} | ||
|
||
render() { | ||
const schema = this.props.schema; | ||
const queryType = schema.getQueryType(); | ||
const mutationType = schema.getMutationType && schema.getMutationType(); | ||
const subscriptionType = | ||
schema.getSubscriptionType && schema.getSubscriptionType(); | ||
|
||
return ( | ||
<div> | ||
<MarkdownContent | ||
className="doc-type-description" | ||
markdown={ | ||
'A GraphQL schema provides a root type for each kind of operation.' | ||
} | ||
/> | ||
<div className="doc-category"> | ||
<div className="doc-category-title"> | ||
{'root types'} | ||
</div> | ||
<div className="doc-category-item"> | ||
<span className="keyword">{'query'}</span> | ||
{': '} | ||
<TypeLink type={queryType} onClick={this.props.onClickType} /> | ||
</div> | ||
{ | ||
mutationType && | ||
<div className="doc-category-item"> | ||
<span className="keyword">{'mutation'}</span> | ||
{': '} | ||
<TypeLink type={mutationType} onClick={this.props.onClickType} /> | ||
</div> | ||
} | ||
{ | ||
subscriptionType && | ||
<div className="doc-category-item"> | ||
<span className="keyword">{'subscription'}</span> | ||
{': '} | ||
<TypeLink | ||
type={subscriptionType} | ||
onClick={this.props.onClickType} | ||
/> | ||
</div> | ||
} | ||
</div> | ||
</div> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/** | ||
* Copyright (c) 2015, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the | ||
* LICENSE-examples file in the root directory of this source tree. | ||
*/ | ||
|
||
import React, { PropTypes } from 'react'; | ||
|
||
import debounce from '../../utility/debounce'; | ||
|
||
export default class SearchBox extends React.Component { | ||
static propTypes = { | ||
isShown: PropTypes.bool, | ||
onSearch: PropTypes.func, | ||
} | ||
|
||
constructor(props) { | ||
super(props); | ||
|
||
this.state = { value: '' }; | ||
|
||
this._debouncedOnSearch = debounce(200, () => { | ||
this.props.onSearch(this.state.value); | ||
}); | ||
} | ||
|
||
shouldComponentUpdate(nextProps, nextState) { | ||
return nextProps.isShown !== this.props.isShown || | ||
nextState.value !== this.state.value; | ||
} | ||
|
||
render() { | ||
return ( | ||
<div> | ||
{ | ||
this.props.isShown && | ||
<label className="search-box-outer"> | ||
<input className="search-box-input" | ||
onChange={this.handleChange} | ||
type="text" | ||
value={this.state.value} | ||
placeholder="Search the schema ..." | ||
/> | ||
</label> | ||
} | ||
</div> | ||
); | ||
} | ||
|
||
handleChange = event => { | ||
this.setState({ value: event.target.value }); | ||
this._debouncedOnSearch(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
/** | ||
* Copyright (c) 2015, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the | ||
* LICENSE-examples file in the root directory of this source tree. | ||
*/ | ||
|
||
import React, { PropTypes } from 'react'; | ||
|
||
import TypeLink from './TypeLink'; | ||
|
||
export default class SearchResults extends React.Component { | ||
static propTypes = { | ||
schema: PropTypes.object, | ||
searchValue: PropTypes.string, | ||
onClickType: PropTypes.func, | ||
onClickField: PropTypes.func, | ||
} | ||
|
||
shouldComponentUpdate(nextProps) { | ||
return this.props.schema !== nextProps.schema || | ||
this.props.searchValue !== nextProps.searchValue; | ||
} | ||
|
||
render() { | ||
const searchValue = this.props.searchValue; | ||
const schema = this.props.schema; | ||
const onClickType = this.props.onClickType; | ||
const onClickField = this.props.onClickField; | ||
|
||
const typeMap = schema.getTypeMap(); | ||
|
||
const matchedTypes = []; | ||
const matchedFields = []; | ||
|
||
const typeNames = Object.keys(typeMap); | ||
for (const typeName of typeNames) { | ||
if (matchedTypes.length + matchedFields.length >= 100) { | ||
break; | ||
} | ||
|
||
const type = typeMap[typeName]; | ||
const matchedOn = []; | ||
if (this._isMatch(typeName, searchValue)) { | ||
matchedOn.push('Type Name'); | ||
} | ||
|
||
if (matchedOn.length) { | ||
matchedTypes.push( | ||
<div className="doc-category-item"> | ||
<TypeLink type={type} onClick={onClickType} /> | ||
</div> | ||
); | ||
} | ||
|
||
if (type.getFields) { | ||
const fields = type.getFields(); | ||
Object.keys(fields).forEach(fieldName => { | ||
const field = fields[fieldName]; | ||
if (this._isMatch(fieldName, searchValue)) { | ||
matchedFields.push( | ||
<div className="doc-category-item"> | ||
<a className="field-name" | ||
onClick={event => onClickField(field, type, event)}> | ||
{field.name} | ||
</a> | ||
{' on '} | ||
<TypeLink type={type} onClick={onClickType} /> | ||
</div> | ||
); | ||
} else if (field.args && field.args.length) { | ||
const matches = | ||
field.args.filter(arg => this._isMatch(arg.name, searchValue)); | ||
if (matches.length > 0) { | ||
matchedFields.push( | ||
<div className="doc-category-item"> | ||
<a className="field-name" | ||
onClick={event => onClickField(field, type, event)}> | ||
{field.name} | ||
</a> | ||
{'('} | ||
<span> | ||
{matches.map(arg => | ||
<span className="arg" key={arg.name}> | ||
<span className="arg-name">{arg.name}</span> | ||
{': '} | ||
<TypeLink type={arg.type} onClick={onClickType} /> | ||
</span> | ||
)} | ||
</span> | ||
{')'} | ||
{' on '} | ||
<TypeLink type={type} onClick={onClickType} /> | ||
</div> | ||
); | ||
} | ||
} | ||
}); | ||
} | ||
} | ||
|
||
if (matchedTypes.length === 0 && matchedFields.length === 0) { | ||
return ( | ||
<span className="doc-alert-text"> | ||
{'No results found.'} | ||
</span> | ||
); | ||
} | ||
|
||
return ( | ||
<div> | ||
<div className="doc-category"> | ||
{ | ||
(matchedTypes.length > 0 || matchedFields.length > 0) && | ||
<div className="doc-category-title"> | ||
{'search results'} | ||
</div> | ||
} | ||
{matchedTypes} | ||
{matchedFields} | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
_isMatch(sourceText, searchValue) { | ||
try { | ||
const escaped = searchValue.replace(/[^_0-9A-Za-z]/g, ch => '\\' + ch); | ||
return sourceText.search(new RegExp(escaped, 'i')) !== -1; | ||
} catch (e) { | ||
return sourceText.toLowerCase().indexOf(searchValue.toLowerCase()) !== -1; | ||
} | ||
} | ||
} |
Oops, something went wrong.