Template for docs pages

Summary:
- Dynamic loading of documentation pages
- code highlighting for markdown files
- editing playground from sidebar

Reviewed By: emilsjolander

Differential Revision: D6964951

fbshipit-source-id: 1c7f36afa8d23215471d5b9a9c01bd2241c2008e
This commit is contained in:
Daniel Büchele
2018-02-12 10:25:02 -08:00
committed by Facebook Github Bot
parent e43bb9da19
commit 951a429ac5
20 changed files with 321 additions and 149 deletions

11
website/.flowconfig Normal file
View File

@@ -0,0 +1,11 @@
[ignore]
[include]
[libs]
[lints]
[options]
[strict]

View File

@@ -0,0 +1,24 @@
---
path: "getting-started/litho"
title: "Litho"
hasPlayground: false
---
## Litho
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec
sodales libero, sit amet tempus diam. Vivamus finibus vestibulum
est. Vestibulum feugiat pellentesque diam vel hendrerit. Nunc
pretium sollicitudin magna sed pharetra.
Duis bibendum dapibus quam ac rutrum. Suspendisse potenti. Aliquam
est sapien, gravida ac turpis iaculis, convallis rutrum justo. Sed
est augue, pellentesque eleifend mauris non, ultrices aliquam purus.
Duis sed lorem a lectus feugiat fringilla eu non elit.
```c
enum {
Test
Test2
}
```

View File

@@ -2,6 +2,7 @@
path: "docs/flexDirection"
title: "Flex Direction"
hasPlayground: true
editableProperties: ['flexDirection']
---
## Flex Direction
@@ -15,3 +16,10 @@ Duis bibendum dapibus quam ac rutrum. Suspendisse potenti. Aliquam
est sapien, gravida ac turpis iaculis, convallis rutrum justo. Sed
est augue, pellentesque eleifend mauris non, ultrices aliquam purus.
Duis sed lorem a lectus feugiat fringilla eu non elit.
```c
enum {
Test
Test2
}
```

View File

@@ -12,10 +12,12 @@
module.exports = {
siteMetadata: {
title: 'Gatsby Default Starter',
title: 'Yoga Layout',
},
plugins: [
// using latest react version
'gatsby-plugin-react-next',
// setting head data like title from within components
'gatsby-plugin-react-helmet',
{
resolve: `gatsby-plugin-less`,
@@ -25,19 +27,35 @@ module.exports = {
},
},
},
// plugin for importing antd components
{
resolve: 'gatsby-plugin-antd',
options: {
style: true,
},
},
// reading files from the file-system (used for markdown files)
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/docs`,
path: `${__dirname}/contents`,
name: 'markdown-pages',
},
},
'gatsby-transformer-remark',
// parse markdown files, used for content files
{
resolve: `gatsby-transformer-remark`,
options: {
// code-highlighting in markdown files
plugins: [
{
resolve: `gatsby-remark-prismjs`,
options: {
classPrefix: 'language-',
},
},
],
},
},
],
};

View File

@@ -25,6 +25,7 @@ exports.createPages = ({boundActionCreators, graphql}) => {
frontmatter {
path
hasPlayground
editableProperties
}
html
}

View File

@@ -11,6 +11,7 @@
"gatsby-plugin-less": "^1.1.4",
"gatsby-plugin-react-helmet": "^2.0.3",
"gatsby-plugin-react-next": "^1.0.8",
"gatsby-remark-prismjs": "^1.2.14",
"gatsby-source-filesystem": "^1.5.18",
"gatsby-transformer-remark": "^1.7.31",
"immutable": "^4.0.0-rc.9",
@@ -25,9 +26,7 @@
"main": "n/a",
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"format": "prettier --trailing-comma es5 --no-semi --single-quote --write \"src/**/*.js\"",
"test": "echo \"Error: no test specified\" && exit 1"
"develop": "gatsby develop"
},
"devDependencies": {
"prettier": "^1.10.2"

View File

@@ -1,4 +1,15 @@
.DocsSidebar {
height: 100%;
width: 350px;
padding: 20px;
border-right: 1px solid #dddfe2;
}
.DocsSidebar h3 {
margin-bottom: 0;
}
.DocsSidebar h4 {
margin-top: 10px;
margin-bottom: 5px;
}

View File

@@ -14,6 +14,13 @@ h2 {
font-weight: 500;
}
.gatsby-highlight pre[class*="language-"] {
background: none;
padding: 0;
font-size: 14px;
margin-bottom: 15px;
}
.Page {
display: flex;
flex-direction: column;
@@ -25,3 +32,7 @@ h2 {
flex-direction: column;
flex-grow: 1;
}
.PageContent.withSpacing {
padding-top: 35px;
}

View File

@@ -14,11 +14,13 @@ import React from 'react';
import Toolbar from './Toolbar';
import Footer from './Footer';
import './Page.css';
require('prismjs/themes/prism.css');
type Props = {|
children: any,
title?: string,
className?: string,
withSpacing?: boolean,
|};
export default (props: Props) => (
@@ -32,7 +34,9 @@ export default (props: Props) => (
<title>Yoga Layout{props.title ? ` | ${props.title}` : ''}</title>
</Head> */}
<Toolbar />
<div className="PageContent">{props.children}</div>
<div className={`PageContent ${props.withSpacing ? 'withSpacing' : ''}`}>
{props.children}
</div>
<Footer />
</div>
);

View File

@@ -0,0 +1,35 @@
/**
* Copyright (c) 2014-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.
*
* @flow
* @format
*/
import React, {Component} from 'react';
import YogaEnumSelect from './YogaEnumSelect';
import YogaPositionEditor from './YogaPositionEditor';
import {Input} from 'antd';
type Props<T, S> = {
property: string,
disabled?: boolean,
value: string | number,
onChange: (value: number) => void,
};
export default (props: Props<T, S>) => {
if (YogaEnumSelect.availableProperties.indexOf(props.property) > -1) {
return <YogaEnumSelect {...props} />;
} else if (
YogaPositionEditor.availableProperties.indexOf(props.property) > -1
) {
return <YogaPositionEditor {...props} />;
} else {
return <Input type="text" {...props} />;
}
};

View File

@@ -11,12 +11,11 @@
*/
import React, {Component} from 'react';
import {Row, Col, Button, Tabs, Input} from 'antd';
import YogaEnumSelect from './YogaEnumSelect';
import {Row, Col, Button, Tabs} from 'antd';
import EditValue from './EditValue';
import type {LayoutRecordT} from './LayoutRecord';
import type {Yoga$Direction} from 'yoga-layout';
import InfoText from './InfoText';
import YogaPositionEditor from './YogaPositionEditor';
import './Editor.css';
const TabPane = Tabs.TabPane;
@@ -64,8 +63,8 @@ export default class Editor extends Component<Props> {
direction
</InfoText>
</h2>
<YogaEnumSelect
property="DIRECTION"
<EditValue
property="direction"
value={this.props.direction}
onChange={e => this.props.onChangeSetting('direction', e)}
/>
@@ -73,9 +72,9 @@ export default class Editor extends Component<Props> {
Flex direction
<InfoText>Defining the direction of the main-axis</InfoText>
</h2>
<YogaEnumSelect
<EditValue
disabled={disabled}
property="FLEX_DIRECTION"
property="flexDirection"
value={node ? node.flexDirection : ''}
onChange={e => this.props.onChangeLayout('flexDirection', e)}
/>
@@ -89,7 +88,7 @@ export default class Editor extends Component<Props> {
up, relative to it's siblings
</InfoText>
</h2>
<Input
<EditValue
type="text"
disabled={disabled || selectedNodeIsRoot}
value={node ? node.flexGrow : ''}
@@ -106,7 +105,7 @@ export default class Editor extends Component<Props> {
anymore.
</InfoText>
</h2>
<Input
<EditValue
type="text"
disabled={disabled || selectedNodeIsRoot}
value={node ? node.flexShrink : ''}
@@ -123,9 +122,9 @@ export default class Editor extends Component<Props> {
Wrapping behaviour when child nodes don't fit into a single line
</InfoText>
</h2>
<YogaEnumSelect
<EditValue
disabled={disabled}
property="WRAP"
property="flexWrap"
value={node ? node.flexWrap : ''}
onChange={e => this.props.onChangeLayout('flexWrap', e)}
/>
@@ -135,9 +134,9 @@ export default class Editor extends Component<Props> {
Justify content
<InfoText>Aligns child nodes along the main-axis</InfoText>
</h2>
<YogaEnumSelect
<EditValue
disabled={disabled}
property="JUSTIFY"
property="justifyContent"
value={node ? node.justifyContent : ''}
onChange={e => this.props.onChangeLayout('justifyContent', e)}
/>
@@ -146,9 +145,9 @@ export default class Editor extends Component<Props> {
Align items
<InfoText>Aligns child nodes along the cross-axis</InfoText>
</h2>
<YogaEnumSelect
<EditValue
disabled={disabled}
property="ALIGN"
property="alignItems"
value={node ? node.alignItems : ''}
onChange={e => this.props.onChangeLayout('alignItems', e)}
/>
@@ -159,9 +158,9 @@ export default class Editor extends Component<Props> {
Specifies alignment on the cross-axis for the node itself
</InfoText>
</h2>
<YogaEnumSelect
<EditValue
disabled={disabled || selectedNodeIsRoot}
property="ALIGN"
property="alignSelf"
value={node ? node.alignSelf : ''}
onChange={e => this.props.onChangeLayout('alignSelf', e)}
/>
@@ -172,9 +171,9 @@ export default class Editor extends Component<Props> {
Alignment of lines along the cross-axis when wrapping
</InfoText>
</h2>
<YogaEnumSelect
<EditValue
disabled={disabled}
property="ALIGN"
property="alignContent"
value={node ? node.alignContent : ''}
onChange={e => this.props.onChangeLayout('alignContent', e)}
/>
@@ -186,7 +185,7 @@ export default class Editor extends Component<Props> {
</h2>
<Row gutter={15}>
<Col span={12}>
<Input
<EditValue
type="text"
placeholder="width"
disabled={disabled}
@@ -197,7 +196,7 @@ export default class Editor extends Component<Props> {
/>
</Col>
<Col span={12}>
<Input
<EditValue
type="text"
placeholder="height"
disabled={disabled}
@@ -216,7 +215,7 @@ export default class Editor extends Component<Props> {
displaying videos
</InfoText>
</h2>
<Input
<EditValue
type="text"
placeholder="Aspect ratio"
disabled={disabled}
@@ -228,7 +227,7 @@ export default class Editor extends Component<Props> {
<h2>Box model</h2>
{['padding', 'border', 'margin'].map(property => (
<YogaPositionEditor
<EditValue
property={property}
key={property}
value={node ? node[property] : undefined}
@@ -244,13 +243,13 @@ export default class Editor extends Component<Props> {
</InfoText>
</h2>
<YogaEnumSelect
<EditValue
disabled={disabled}
property="POSITION_TYPE"
property="positionType"
value={node ? node.positionType : ''}
onChange={e => this.props.onChangeLayout('positionType', e)}
/>
<YogaPositionEditor
<EditValue
property="position"
value={node ? node.position : undefined}
onChange={value => this.props.onChangeLayout('position', value)}

View File

@@ -1,4 +1,4 @@
.YogaEnumSelect.ant-radio-group {
.YogaEnumSelect {
display: flex;
}
@@ -7,3 +7,8 @@
flex-basis: 0;
text-align: center;
}
.YogaEnumSelect .ant-btn {
flex-grow: 1;
flex-basis: 0;
}

View File

@@ -17,18 +17,32 @@ import './YogaEnumSelect.css';
const RadioButton = Radio.Button;
const RadioGroup = Radio.Group;
const PROPERTY_LOOKUP = {
flexDirection: 'FLEX_DIRECTION',
direction: 'DIRECTION',
justifyContent: 'JUSTIFY',
alignSelf: 'ALIGN',
alignContent: 'ALIGN',
alignItems: 'ALIGN',
positionType: 'POSITION_TYPE',
flexWrap: 'WRAP',
};
type Props = {
property: string,
property: $Keys<typeof PROPERTY_LOOKUP>,
disabled?: boolean,
value: string | number,
onChange: (value: number) => void,
};
export default class YogaEnumSelect extends Component<Props> {
static availableProperties = Object.keys(PROPERTY_LOOKUP);
values: Array<{key: string, value: number}>;
constructor({property}: Props) {
super();
property = PROPERTY_LOOKUP[property];
// $FlowFixMe
this.values = Object.keys(yoga)
.map(key => ({key, value: yoga[key]}))
@@ -42,29 +56,32 @@ export default class YogaEnumSelect extends Component<Props> {
};
render() {
const {property, ...props} = this.props;
let {property, ...props} = this.props;
property = PROPERTY_LOOKUP[property];
const selected = this.values.find(
({key, value}) => value === this.props.value,
);
const replacer = new RegExp(`^${property}_`);
return this.values.length > 3 ? (
<Dropdown
disabled={props.disabled}
overlay={
<Menu onClick={this.handleMenuClick}>
{this.values.map(({key, value}) => (
<Menu.Item key={key} value={value}>
{key.replace(replacer, '')}
</Menu.Item>
))}
</Menu>
}>
<Button>
{selected ? selected.key.replace(replacer, '') : 'undefiend'}{' '}
<Icon type="down" />
</Button>
</Dropdown>
<div className="YogaEnumSelect">
<Dropdown
disabled={props.disabled}
overlay={
<Menu onClick={this.handleMenuClick}>
{this.values.map(({key, value}) => (
<Menu.Item key={key} value={value}>
{key.replace(replacer, '')}
</Menu.Item>
))}
</Menu>
}>
<Button>
{selected ? selected.key.replace(replacer, '') : ''}
<Icon type="down" />
</Button>
</Dropdown>
</div>
) : (
<RadioGroup
{...props}

View File

@@ -18,11 +18,13 @@ import './YogaPositionEditor.css';
type Props = {
value: PositionRecordT,
property: string,
property: 'position' | 'margin' | 'padding' | 'border',
onChange: (value: PositionRecordT) => void,
};
export default class YogaPositionEditor extends Component<Props> {
static availableProperties = ['position', 'margin', 'padding', 'border'];
static defaultProps = {
value: PositionRecord(),
};

View File

@@ -34,6 +34,7 @@ type Props = {
showGuides: boolean,
className?: string,
height?: string | number,
persist?: boolean,
renderSidebar?: (layoutDefinition: LayoutRecordT, onChange: Function) => any,
};
@@ -53,7 +54,7 @@ export default class Playground extends Component<Props, State> {
static defaultProps = {
layoutDefinition: LayoutRecord({
width: 800,
width: 700,
height: 400,
justifyContent: yoga.JUSTIFY_SPACE_BETWEEN,
alignItems: yoga.ALIGN_FLEX_START,
@@ -65,14 +66,15 @@ export default class Playground extends Component<Props, State> {
bottom: '10',
}),
margin: PositionRecord({
left: '20',
top: '70',
left: '30',
top: '30',
}),
}),
direction: yoga.DIRECTION_LTR,
maxDepth: 3,
showCode: false,
showGuides: true,
persist: false,
};
state = {
@@ -144,8 +146,9 @@ export default class Playground extends Component<Props, State> {
const {selectedNodePath, layoutDefinition} = this.state;
if (selectedNodePath) {
const index = selectedNodePath.pop();
const path = getPath(selectedNodePath).concat('children');
const updatedChildren = layoutDefinition.getIn(path).delete(index);
const updatedChildren = layoutDefinition
.getIn(getPath(selectedNodePath))
.delete(index);
this.modifyAtPath(path, updatedChildren);
this.setState({selectedNodePath: null});
}
@@ -154,8 +157,9 @@ export default class Playground extends Component<Props, State> {
onAdd = () => {
const {selectedNodePath, layoutDefinition} = this.state;
if (selectedNodePath) {
const path = getPath(selectedNodePath).concat('children');
const updatedChildren = layoutDefinition.getIn(path).push(LayoutRecord());
const updatedChildren = layoutDefinition
.getIn(getPath(selectedNodePath))
.push(LayoutRecord());
this.modifyAtPath(
path,
updatedChildren,
@@ -177,9 +181,11 @@ export default class Playground extends Component<Props, State> {
selectedNodePath,
});
window.location.hash = btoa(
JSON.stringify(this.removeUnchangedProperties(layoutDefinition)),
);
if (this.props.persist) {
window.location.hash = btoa(
JSON.stringify(this.removeUnchangedProperties(layoutDefinition)),
);
}
}
removeUnchangedProperties = (node: LayoutRecordT): Object => {
@@ -306,7 +312,7 @@ export default class Playground extends Component<Props, State> {
<div className={`PlaygroundContainer ${this.props.className || ''}`}>
<div>
{this.props.renderSidebar(
this.state.layoutDefinition,
layoutDefinition.getIn(getPath(selectedNodePath)),
this.onChangeLayout,
)}
</div>

View File

@@ -16,8 +16,15 @@ import Page from '../../components/Page';
import Padded from '../../components/Padded';
import {Row, Col} from 'antd';
export default () => (
<Page>
const CATEGORY_TITLE = {
'getting-started': 'Getting Started',
properties: 'Properties',
examples: 'Examples',
contributing: 'Contributing',
};
export default ({data}) => (
<Page withSpacing>
<Padded>
<h1>Documentation</h1>
<p>
@@ -29,65 +36,41 @@ export default () => (
nec leo pharetra fermentum.
</p>
<Row>
<Col md={6} sm={12} xs={24}>
<h2>Getting Started</h2>
<Link to="">Litho</Link>
<br />
<Link to="">ComponentKit</Link>
<br />
<Link to="">React Native</Link>
<br />
<Link to="">Addin Yoga to a project</Link>
</Col>
<Col md={6} sm={12} xs={24}>
<h2>Properties</h2>
<Link to="">Width and height</Link>
<br />
<Link to="">Max/min width and height</Link>
<br />
<Link to="docs/flexDirection">Flex direction</Link>
<br />
<Link to="">Justify content</Link>
<br />
<Link to="">Align items/self</Link>
<br />
<Link to="">Flex basis, grow and shrink</Link>
<br />
<Link to="">Margins, paddings, and borders</Link>
<br />
<Link to="">Flex wrap</Link>
<br />
<Link to="">Align content</Link>
<br />
<Link to="">Absolute layout</Link>
<br />
<Link to="">Aspect ratio</Link>
<br />
<Link to="">Layout direction</Link>
</Col>
<Col md={6} sm={12} xs={24}>
<h2>Examples</h2>
<Link to="">Overlays</Link>
<br />
<Link to="">Floating buttons</Link>
<br />
<Link to="">Flexible text</Link>
</Col>
<Col md={6} sm={12} xs={24}>
<h2>Contributing</h2>
<Link to="">Check out the code</Link>
<br />
<Link to="">Running the test suite</Link>
<br />
<Link to="">Making a change</Link>
<br />
<Link to="">Adding a test</Link>
<br />
<Link to="">Adding documentation</Link>
<br />
<Link to="">Opening a pull request</Link>
</Col>
{['getting-started', 'properties', 'examples', 'contributing'].map(
category => (
<Col md={6} sm={12} xs={24} key={category}>
<h2>{CATEGORY_TITLE[category]}</h2>
{data.allMarkdownRemark.edges
.filter(
({node}) =>
node.fileAbsolutePath.indexOf(`/${category}/`) > -1,
)
.map(({node}) => (
<Link key={node.id} to={node.frontmatter.path}>
{node.frontmatter.title}
</Link>
))}
</Col>
),
)}
</Row>
</Padded>
</Page>
);
export const query = graphql`
query IndexQuery {
allMarkdownRemark {
edges {
node {
id
frontmatter {
title
path
}
fileAbsolutePath
}
}
}
}
`;

View File

@@ -16,6 +16,6 @@ import Playground from '../components/Playground';
export default () => (
<Page title="Playground">
<Playground height="100%" />
<Playground height="100%" selectedNodePath={[]} persist />
</Page>
);

View File

@@ -14,25 +14,45 @@ import React from 'react';
import Page from '../components/Page';
import Playground from '../components/Playground';
import DocsSidebar from '../components/DocsSidebar';
import YogaEnumSelect from '../components/Playground/YogaEnumSelect';
import EditValue from '../components/Playground/EditValue';
import Link from 'gatsby-link';
import {Button, Icon, Row, Col} from 'antd';
export default ({pathContext}) => {
return (
<Page>
<Playground
selectedNodePath={[]}
showGuides={false}
renderSidebar={(layout, onChange) => (
<DocsSidebar>
<div dangerouslySetInnerHTML={{__html: pathContext.html}} />
<YogaEnumSelect
property="FLEX_DIRECTION"
value={layout.flexDirection}
onChange={e => onChange('flexDirection', e)}
/>
</DocsSidebar>
)}
/>
</Page>
);
};
export default ({pathContext}) => (
<Page>
<Playground
selectedNodePath={[]}
showGuides={false}
renderSidebar={(layout, onChange) => (
<DocsSidebar>
<Link to="/docs">
<Icon type="left-circle-o" /> back to overview
</Link>
<div dangerouslySetInnerHTML={{__html: pathContext.html}} />
{pathContext.frontmatter.editableProperties && (
<Row type="flex" align="bottom">
<Col span={12}>
<h3>Try it out</h3>
</Col>
<Col span={12}>
<Link to="/playground">
<Icon type="export" /> Open in playground
</Link>
</Col>
</Row>
)}
{(pathContext.frontmatter.editableProperties || []).map(prop => (
<div key={prop}>
<h4>{prop}</h4>
<EditValue
property={prop}
value={layout[prop]}
onChange={e => onChange(prop, e)}
/>
</div>
))}
</DocsSidebar>
)}
/>
</Page>
);

View File

@@ -13,11 +13,16 @@
import React from 'react';
import Page from '../components/Page';
import Padded from '../components/Padded';
import {Icon} from 'antd';
import Link from 'gatsby-link';
export default ({pathContext}) => {
return (
<Page>
<Page withSpacing>
<Padded>
<Link to="/docs">
<Icon type="left-circle-o" /> back to overview
</Link>
<div dangerouslySetInnerHTML={{__html: pathContext.html}} />
</Padded>
</Page>

View File

@@ -3423,6 +3423,15 @@ gatsby-react-router-scroll@^1.0.10:
scroll-behavior "^0.9.9"
warning "^3.0.0"
gatsby-remark-prismjs@^1.2.14:
version "1.2.14"
resolved "https://registry.yarnpkg.com/gatsby-remark-prismjs/-/gatsby-remark-prismjs-1.2.14.tgz#3f5fd2ac1d5a174673a6b6fa63b4e4fa526d36c0"
dependencies:
babel-runtime "^6.26.0"
parse-numeric-range "0.0.2"
prismjs "^1.11.0"
unist-util-visit "^1.3.0"
gatsby-source-filesystem@^1.5.18:
version "1.5.18"
resolved "https://registry.yarnpkg.com/gatsby-source-filesystem/-/gatsby-source-filesystem-1.5.18.tgz#e2cb96a2c248c304e58ba3d0142316a695d3ef35"
@@ -6144,6 +6153,10 @@ parse-latin@^4.0.0:
unist-util-modify-children "^1.0.0"
unist-util-visit-children "^1.0.0"
parse-numeric-range@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/parse-numeric-range/-/parse-numeric-range-0.0.2.tgz#b4f09d413c7adbcd987f6e9233c7b4b210c938e4"
parse-passwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
@@ -6858,7 +6871,7 @@ pretty-error@^2.1.1:
renderkid "^2.0.1"
utila "~0.4"
prismjs@^1.8.4:
prismjs@^1.11.0, prismjs@^1.8.4:
version "1.11.0"
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.11.0.tgz#297aef33eb79421bfdb19273a5092ca515970d29"
optionalDependencies:
@@ -9216,7 +9229,7 @@ unist-util-visit-children@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/unist-util-visit-children/-/unist-util-visit-children-1.1.1.tgz#eba63b371116231181068837118b6e6e10ec8844"
unist-util-visit@^1.0.0, unist-util-visit@^1.1.0, unist-util-visit@^1.1.1:
unist-util-visit@^1.0.0, unist-util-visit@^1.1.0, unist-util-visit@^1.1.1, unist-util-visit@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.3.0.tgz#41ca7c82981fd1ce6c762aac397fc24e35711444"
dependencies: