Skip to content

Commit

Permalink
feat(wizard): adds the pf wizard and modal components
Browse files Browse the repository at this point in the history
  • Loading branch information
priley86 committed Dec 6, 2017
1 parent 908ca89 commit f3529f7
Show file tree
Hide file tree
Showing 28 changed files with 2,105 additions and 1 deletion.
28 changes: 28 additions & 0 deletions less/patternfly-react.less
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
/**
Patternfly React Specific Extensions
*/

.wizard-pf-header {
background-color: #f5f5f5;
border-bottom: none;
padding: 10px 18px;
}
.wizard-pf-title {
font-size: 13px;
font-weight: 700;
}
.wizard-pf-footer {
padding: 14px 15px 17px;
text-align: right;
& .btn + .btn {
margin-left: 5px;
margin-bottom: 0;
}
& > .btn {
padding-left: 10px;
padding-right: 10px;
& > .fa-angle-left {
margin-right: 5px;
}
& > .fa-angle-right {
margin-left: 5px;
}
}
}
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions src/components/Wizard/Wizard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import PropTypes from 'prop-types';
import WizardHeader from './WizardHeader';

/**
* Wizard - main Wizard component.
*/
const Wizard = ({ children, className, embedded, ...rest }) => {
const renderChildren = () => {
return React.Children.map(children, child => {
if (child && child.type === WizardHeader) {
return React.cloneElement(child, {
embedded: embedded,
});
} else {
return child;
}
});
};

return (
<div className={className} {...rest}>
{renderChildren()}
</div>
);
};
Wizard.propTypes = {
/** Children nodes */
children: PropTypes.node,
/** Additional css classes */
className: PropTypes.string,
/** Embedded wizard */
embedded: PropTypes.bool,
};
export default Wizard;
93 changes: 93 additions & 0 deletions src/components/Wizard/Wizard.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
import { withInfo } from '@storybook/addon-info';
import { Row, Col } from 'react-bootstrap';
import { withKnobs } from '@storybook/addon-knobs';
import { defaultTemplate } from '../../../storybook/decorators/storyTemplates';

import { mockWizardItems } from './__mocks__/mockWizardItems';

import {
MockLoadingWizardManager,
mockLoadingWizardSource,
} from './__mocks__/mockLoadingWizardManager';

import {
MockModalWizardManager,
mockModalWizardSource,
} from './__mocks__/mockModalWizardManager';

import {
MockEmbeddedWizardManager,
mockEmbeddedWizardSource,
} from './__mocks__/mockEmbeddedWizardManager';

const stories = storiesOf('Wizard', module);
stories.addDecorator(withKnobs);
stories.addDecorator(
defaultTemplate({
title: 'Wizard',
documentationLink:
'http://www.patternfly.org/pattern-library/communication/wizard/#/overview',
}),
);

stories.add(
'Loading wizard',
withInfo({
source: false,
propTablesExclude: [Row, Col, MockLoadingWizardManager],
text: (
<div>
<h1>Story Source</h1>
<pre>{mockLoadingWizardSource}</pre>
</div>
),
})(() => (
<Row>
<Col sm={12}>
<MockLoadingWizardManager steps={mockWizardItems} />
</Col>
</Row>
)),
);

stories.add(
'Modal wizard',
withInfo({
source: false,
propTablesExclude: [Row, Col, MockModalWizardManager],
text: (
<div>
<h1>Story Source</h1>
<pre>{mockModalWizardSource}</pre>
</div>
),
})(() => (
<Row>
<Col sm={12}>
<MockModalWizardManager steps={mockWizardItems} />
</Col>
</Row>
)),
);

stories.add(
'Embedded in page',
withInfo({
source: false,
propTablesExclude: [Row, Col, MockEmbeddedWizardManager],
text: (
<div>
<h1>Story Source</h1>
<pre>{mockEmbeddedWizardSource}</pre>
</div>
),
})(() => (
<Row>
<Col sm={12}>
<MockEmbeddedWizardManager steps={mockWizardItems} />
</Col>
</Row>
)),
);
99 changes: 99 additions & 0 deletions src/components/Wizard/Wizard.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import React from 'react';
import renderer from 'react-test-renderer';
import { Row, Col } from 'react-bootstrap';
import { Button } from '../Button';
import { Wizard } from './index';

import {
mockWizardItems,
mockLoadingContents,
} from './__mocks__/mockWizardItems';

import {
renderWizardSteps,
renderSidebarItems,
renderWizardContents,
} from './__mocks__/mockWizardRenderers';

test('Wizard loading renders properly', () => {
const component = renderer.create(
<Row>
<Col sm={12}>
<Wizard>
<Wizard.Header title="Wizard Title" />
<Wizard.Body>
<Wizard.Row>
<Wizard.Main>{mockLoadingContents()}</Wizard.Main>
</Wizard.Row>
</Wizard.Body>
<Wizard.Footer>
<Button bsStyle="default" className="btn-cancel">
Cancel
</Button>
<Button bsStyle="default" disabled>
<span className="i fa fa-angle-left" />Back
</Button>
<Button bsStyle="primary" disabled>
Next<span className="i fa fa-angle-right" />
</Button>
</Wizard.Footer>
</Wizard>
</Col>
</Row>,
);

const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});

test('Wizard embedded renders properly', () => {
const onStepClick = jest.fn();
const onSidebarItemClick = jest.fn();
const activeStepIndex = 0;
const activeSubStepIndex = 0;
const onNextButtonClick = jest.fn();
const onBackButtonClick = jest.fn();

const component = renderer.create(
<Wizard embedded>
<Wizard.Header title="Wizard Title" />
<Wizard.Body>
<Wizard.Steps
steps={renderWizardSteps(mockWizardItems, 0, 0, onStepClick)}
/>
<Wizard.Row>
<Wizard.Sidebar
items={renderSidebarItems(
mockWizardItems,
activeStepIndex,
activeSubStepIndex,
onSidebarItemClick,
)}
/>
<Wizard.Main>
{renderWizardContents(
mockWizardItems,
activeStepIndex,
activeSubStepIndex,
)}
</Wizard.Main>
</Wizard.Row>
</Wizard.Body>
<Wizard.Footer>
<Button bsStyle="default" className="btn-cancel">
Cancel
</Button>
<Button bsStyle="default" onClick={onBackButtonClick}>
<span className="i fa fa-angle-left" />Back
</Button>

<Button bsStyle="primary" onClick={onNextButtonClick}>
Next<span className="i fa fa-angle-right" />
</Button>
</Wizard.Footer>
</Wizard>,
);

const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
22 changes: 22 additions & 0 deletions src/components/Wizard/WizardBody.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';

/**
* WizardBody component for Patternfly React
*/
const WizardBody = ({ children, className, ...rest }) => {
const classes = cx('wizard-pf-body', className);
return (
<div className={classes} {...rest}>
{children}
</div>
);
};
WizardBody.propTypes = {
/** Children nodes */
children: PropTypes.node,
/** Additional css classes */
className: PropTypes.string,
};
export default WizardBody;
48 changes: 48 additions & 0 deletions src/components/Wizard/WizardContents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';

/**
* WizardContents component for Patternfly React
*/
const WizardContents = ({
children,
className,
stepIndex,
subStepIndex,
activeStepIndex,
activeSubStepIndex,
...rest
}) => {
const classes = cx(
'wizard-pf-contents',
{
// hide contents if the step is not active
// OR if we have sub steps and this sub step is not active
hidden:
activeStepIndex !== stepIndex ||
(activeSubStepIndex !== null && activeSubStepIndex !== subStepIndex),
},
className,
);
return (
<div className={classes} {...rest}>
{children}
</div>
);
};
WizardContents.propTypes = {
/** WizardStep nodes */
children: PropTypes.node,
/** Additional css classes */
className: PropTypes.string,
/** The wizard step index for these contents */
stepIndex: PropTypes.number,
/** The wizard sub step index for these contents */
subStepIndex: PropTypes.number,
/** The active wizard step index */
activeStepIndex: PropTypes.number,
/** The active wizard sub step index */
activeSubStepIndex: PropTypes.number,
};
export default WizardContents;
22 changes: 22 additions & 0 deletions src/components/Wizard/WizardFooter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';

/**
* WizardFooter component for Patternfly React
*/
const WizardFooter = ({ children, className, ...rest }) => {
const classes = cx('wizard-pf-footer', className);
return (
<div className={classes} {...rest}>
{children}
</div>
);
};
WizardFooter.propTypes = {
/** Children nodes */
children: PropTypes.node,
/** Additional css classes */
className: PropTypes.string,
};
export default WizardFooter;
35 changes: 35 additions & 0 deletions src/components/Wizard/WizardHeader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';

/**
* WizardHeader component for Patternfly React
*/
const WizardHeader = ({ children, className, embedded, title, ...rest }) => {
const classes = cx({ 'wizard-pf-header': !embedded }, className);

if (embedded) {
return (
<h2 className={classes} {...rest}>
{title}
</h2>
);
} else {
return (
<div className={classes} {...rest}>
<h4 className="wizard-pf-title">{title}</h4>
</div>
);
}
};
WizardHeader.propTypes = {
/** Children nodes */
children: PropTypes.node,
/** Additional css classes */
className: PropTypes.string,
/** Embedded wizard */
embedded: PropTypes.bool,
/** The wizard title */
title: PropTypes.string,
};
export default WizardHeader;
Loading

0 comments on commit f3529f7

Please sign in to comment.