diff --git a/CHANGELOG.md b/CHANGELOG.md index 755629de..7231a182 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Breaking - [Core] [Form] [ImageEditor] Peer dependency changes: * Change from `@babel/runtime-corejs2` to `@babel/runtime-corejs3`. +- [Core] ``: + * The `bottomPadding` prop is removed. Please use `bodyPadding` prop and pass an object instead. +- [Core] ``: + * `` is refactored to render a `` as its inner layout. + * `` no longer takes `size` and `bodyClassName` props. + * The `bodyPadding` prop now takes an object and is passed to ``. - [Form] ``: - Rename prop `values` to `value`, and it receive a single value directly when is not `multiple`, and receive an array when `multiple` is true. - Rename prop `defaultValues` to `defaultValue`, and it receive a single value directly when is not `multiple`, and receive an array when `multiple` is true. @@ -24,6 +30,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added - [Core] [Form] [ImageEditor] setup `warning@4.0.3`. - [Core] Add the `inline-info` icon to the selections of ``. +- [Core] Add `flexBody` prop for `` (and also ``) to render its body as a Flexbox. ### Changed - [Build] Upgrade to Babel v7.4.4 + `core-js` v3 to provide better polyfilling. @@ -31,6 +38,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - [Core] Update `
` title style and increase bottom margin. - [Form] Update `` and `` to adpat vertically-reversed appearance as `` in v3.0. - [Form] Add `desc` prop to `` +- [Storybook] Update examples for refactord `` and ``. ## [3.0.0] ### Breaking diff --git a/packages/core/src/ColumnView.js b/packages/core/src/ColumnView.js index 898fb75d..6bb07b6c 100644 --- a/packages/core/src/ColumnView.js +++ b/packages/core/src/ColumnView.js @@ -15,43 +15,43 @@ export const BEM = { footer: ROOT_BEM.element('footer'), }; -export function ColumnPart({ children, ...otherProps }) { - if (!children) { - return null; - } - - return
{children}
; -} - function ColumnView({ header, footer, - bottomPadding, + flexBody, + bodyPadding, // React props className, children, ...wrapperProps }) { - const rootClassName = classNames(BEM.root.toString(), className); - const bodyStyle = {}; + const rootClassName = classNames(`${BEM.root}`, className); + const bodyClassName = BEM.body.modifier('flex', flexBody); - if (bottomPadding) { - bodyStyle.paddingBottom = bottomPadding; - } + const bodyStyle = { + paddingTop: bodyPadding.top, + paddingBottom: bodyPadding.bottom, + paddingLeft: bodyPadding.left, + paddingRight: bodyPadding.right, + }; return (
- - {header} - + {header && ( +
+ {header} +
+ )} -
+
{children}
- - {footer} - + {footer && ( +
+ {footer} +
+ )}
); } @@ -59,13 +59,20 @@ function ColumnView({ ColumnView.propTypes = { header: PropTypes.node, footer: PropTypes.node, - bottomPadding: PropTypes.string, + flexBody: PropTypes.bool, + bodyPadding: PropTypes.shape({ + top: PropTypes.number, + bottom: PropTypes.number, + left: PropTypes.number, + right: PropTypes.number, + }), }; ColumnView.defaultProps = { header: undefined, footer: undefined, - bottomPadding: undefined, + flexBody: false, + bodyPadding: { bottom: 24 }, }; export default ColumnView; diff --git a/packages/core/src/Modal.js b/packages/core/src/Modal.js index 22c04fd0..f6e39785 100644 --- a/packages/core/src/Modal.js +++ b/packages/core/src/Modal.js @@ -1,16 +1,16 @@ -import React, { - cloneElement, - isValidElement, - PureComponent -} from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; +import memoize from 'memoize-one'; -import Overlay from './Overlay'; +import ColumnView from './ColumnView'; import HeaderRow from './HeaderRow'; +import Overlay from './Overlay'; import TextLabel from './TextLabel'; + import icBEM from './utils/icBEM'; import prefixClass from './utils/prefixClass'; +import wrapIfNotElement from './utils/wrapIfNotElement'; import renderToLayer from './mixins/renderToLayer'; import './styles/_animations.scss'; @@ -21,126 +21,97 @@ export const MODAL_SIZE = ['small', 'large', 'full']; export const COMPONENT_NAME = prefixClass('modal'); const ROOT_BEM = icBEM(COMPONENT_NAME); export const BEM = { - root: ROOT_BEM.modifier('active'), - closable: ROOT_BEM.element('closable'), + root: ROOT_BEM, container: ROOT_BEM.element('container'), - header: ROOT_BEM.element('header'), - body: ROOT_BEM.element('body') }; -/** - * Render Modal Header - * If string, render with label - * If element, render element with headerClassName - * - * @param {String|Node|Any} header - Title string or - * @param {String} headerClassName - Header className - * @return {Node|Any} - Header Node or any - */ -function renderHeader(header, headerClassName) { - if (isValidElement(header)) { - return cloneElement(header, { - className: headerClassName - }); - } - if (typeof header === 'string') { - const label = ; - return ; +// ----------------- +// Helpers +// ----------------- + +const createHandleOverlayClick = memoize( + onClose => (event) => { + // Prevent onClick events being propagated to outer modals + event.stopPropagation(); + onClose(); } +); + +// ----------------- +// Sub-component +// ----------------- + +export function DefaultHeader({ title }) { + const label = ; - return header; + return ; } -export const ModalContent = ({ +DefaultHeader.propTypes = { + title: PropTypes.string.isRequired, +}; + +// ----------------- +// Main Component +// ----------------- + +function Modal({ header, - bodyClassName, + centered, + onClose, + // props + flexBody, bodyPadding, // React props + className, children, -}) => { - const cNames = classNames( - bodyClassName, - `${BEM.body.modifier('padding', bodyPadding)}` - ); - return ( -
- {renderHeader(header, `${BEM.header}`)} -
- {children} -
-
- ); -}; +}) { + const rootBem = BEM.root + .modifier('centered', centered) + .toString(); -ModalContent.propTypes = { - header: PropTypes.node, - bodyClassName: PropTypes.string, - bodyPadding: PropTypes.bool, -}; + const rootClassName = classNames(rootBem, className); -ModalContent.defaultProps = { - header: undefined, - bodyClassName: '', - bodyPadding: false, -}; + const headerRow = header && wrapIfNotElement(header, { + with: DefaultHeader, + via: 'title', + }); -class Modal extends PureComponent { - handleOverlayClick = (event) => { - const { onClose } = this.props; - // Prevent onClick events being propagated to outer modals - event.stopPropagation(); - onClose(); - } + const handleOverlayClick = createHandleOverlayClick(onClose); - render() { - const { - size, - header, - bodyClassName, - bodyPadding, - onClose, - centered, - // React props - className, - children, - } = this.props; - const bemClass = BEM.root.modifier('center', centered).modifier(size); - const rootClassName = classNames(bemClass.toString(), className); - - return ( -
- - - {children} - -
- ); - } + return ( +
+ + + + {children} + +
+ ); } Modal.propTypes = { - size: PropTypes.oneOf(MODAL_SIZE), - onClose: PropTypes.func, - header: ModalContent.propTypes.header, - bodyClassName: ModalContent.propTypes.bodyClassName, - bodyPadding: ModalContent.propTypes.bodyPadding, + header: PropTypes.node, centered: PropTypes.bool, + onClose: PropTypes.func, + // props + flexBody: ColumnView.propTypes.flexBody, + bodyPadding: ColumnView.propTypes.bodyPadding, }; Modal.defaultProps = { - size: undefined, - onClose: () => {}, - header: ModalContent.defaultProps.header, - bodyClassName: ModalContent.defaultProps.bodyClassName, - bodyPadding: ModalContent.defaultProps.bodyPadding, + header: undefined, centered: false, + onClose: () => {}, + // props + flexBody: ColumnView.defaultProps.flexBody, + bodyPadding: ColumnView.defaultProps.bodyPadding, }; export { Modal as PureModal }; - export default renderToLayer(Modal); diff --git a/packages/core/src/__tests__/ColumnView.test.js b/packages/core/src/__tests__/ColumnView.test.js index b0579108..306234b5 100644 --- a/packages/core/src/__tests__/ColumnView.test.js +++ b/packages/core/src/__tests__/ColumnView.test.js @@ -2,27 +2,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { shallow } from 'enzyme'; -import ColumnView, { ColumnPart, BEM as COLUMN_BEM } from '../ColumnView'; - -describe('', () => { - it('passes every prop to wrapper when children exists', () => { - const handleClick = jest.fn(); - const wrapper = shallow( - - Foo Bar - - ); - - expect(wrapper.text()).toBe('Foo Bar'); - expect(wrapper.find('div').prop('className')).toBe('bar'); - expect(wrapper.find('div').prop('onClick')).toBe(handleClick); - }); - - it('renders null when children does not exist', () => { - const wrapper = shallow(); - expect(wrapper.type()).toBeNull(); - }); -}); +import ColumnView, { BEM as COLUMN_BEM } from '../ColumnView'; describe('', () => { it('renders without crashing', () => { @@ -39,23 +19,41 @@ describe('', () => { expect(wrapper.find(`.${COLUMN_BEM.body}`).text()).toBe('Foo bar'); }); - it('can override bottom padding on body wrapper', () => { + it('can make body a Flexbox', () => { + const wrapper = shallow(Foo bar); + + expect( + wrapper.find(`.${COLUMN_BEM.body}`).hasClass( + COLUMN_BEM.body.modifier('flex').toString({ stripBlock: true }) + ) + ).toBeTruthy(); + }); + + it('can override padding on body wrapper', () => { + const padding = { + top: 1, + bottom: 2, + left: 3, + right: 4, + }; const wrapper = shallow( - + Foo bar ); expect(wrapper.find(`.${COLUMN_BEM.body}`).prop('style')).toEqual({ - paddingBottom: '0', + paddingTop: 1, + paddingBottom: 2, + paddingLeft: 3, + paddingRight: 4, }); }); - it('renders header in a header ', () => { + it('renders header area if "header" prop is given', () => { const wrapper = shallow( } /> ); expect(wrapper.find(`.${COLUMN_BEM.header}`)).toHaveLength(1); - expect(wrapper.find(`.${COLUMN_BEM.header}`).type()).toBe(ColumnPart); expect( wrapper .find(`.${COLUMN_BEM.header}`) @@ -63,12 +61,11 @@ describe('', () => { ).toBeTruthy(); }); - it('renders footer in a footer ', () => { + it('renders footer area if "footer" prop is given', () => { const wrapper = shallow( } /> ); expect(wrapper.find(`.${COLUMN_BEM.footer}`)).toHaveLength(1); - expect(wrapper.find(`.${COLUMN_BEM.footer}`).type()).toBe(ColumnPart); expect( wrapper .find(`.${COLUMN_BEM.footer}`) diff --git a/packages/core/src/__tests__/Modal.test.js b/packages/core/src/__tests__/Modal.test.js index 6fd85b70..efc282c2 100644 --- a/packages/core/src/__tests__/Modal.test.js +++ b/packages/core/src/__tests__/Modal.test.js @@ -1,118 +1,91 @@ import React from 'react'; -import ReactDOM from 'react-dom'; -import { mount, shallow } from 'enzyme'; +import { shallow } from 'enzyme'; -import { BEM, PureModal, ModalContent } from '../Modal'; +import { BEM, PureModal, DefaultHeader } from '../Modal'; +import ColumnView from '../ColumnView'; import HeaderRow from '../HeaderRow'; import Overlay from '../Overlay'; +import TextLabel from '../TextLabel'; -describe(' with mixins', () => { - it('should render without crashing', () => { - const div = document.createElement('div'); - const element = ; +describe('', () => { + it('renders a center-aligned inside a ', () => { + const wrapper = shallow(); - ReactDOM.render(element, div); + expect(wrapper.is(HeaderRow)).toBeTruthy(); + expect(wrapper.prop('center')).toMatchObject( + + ); }); }); -describe('Pure ', () => { +describe('Overlay', () => { it('contains an ', () => { const wrapper = shallow(); expect(wrapper.find(Overlay).exists()).toBeTruthy(); }); - it('renders class names in response to the size prop', () => { - const wrapper = shallow(); - const testSizeProp = (size) => { - wrapper.setProps({ size }); - expect(wrapper.hasClass( - BEM.root - .modifier(size) - .toString({ stripBlock: true }) - )).toBeTruthy(); - }; - - testSizeProp('small'); - testSizeProp('large'); - testSizeProp('full'); - }); - - it('renders class names in response to the centered prop', () => { - const wrapper = shallow(); - expect(wrapper.hasClass(BEM.root.modifier('center').toString({ stripBlock: true }))).toBeTruthy(); - }); + it("calls 'onClose' on click, and blocks event bubble", () => { + const mockedHandleClose = jest.fn(); + const wrapper = shallow(); - it('renders class names in response to the bodyPadding prop', () => { - const wrapper = mount(); - const paddingClass = BEM.body - .modifier('padding', true) - .toString({ stripBlock: true }); - expect(wrapper.find(`.${paddingClass}`).exists()).toBeTruthy(); - }); + const mockedStopPropagation = jest.fn(); + wrapper.find(Overlay).simulate('click', { + stopPropagation: mockedStopPropagation, + }); - it('renders content of the modal', () => { - const content =
TestContent
; - const wrapper = shallow({content}); - expect(wrapper.contains([content])).toBeTruthy(); + expect(mockedStopPropagation).toHaveBeenCalled(); + expect(mockedHandleClose).toHaveBeenCalled(); }); +}); - it('calls handleOverlayClick on Overlay click', () => { - const wrapper = mount(); - const spy = jest.spyOn(wrapper.instance(), 'handleOverlayClick'); - wrapper.instance().forceUpdate(); - wrapper.find(Overlay).simulate('click'); - expect(spy).toHaveBeenCalled(); - }); +describe('Rendering', () => { + it('renders class names in response to the centered prop', () => { + const wrapper = shallow(); + const expectedClassName = BEM.root.modifier('centered').toString({ stripBlock: true }); - it('calls onClick on Overlay click if the onClose prop is not null', () => { - const mockOnClick = jest.fn(); - const wrapper = mount(); - wrapper.instance().forceUpdate(); - wrapper.find(Overlay).simulate('click'); - expect(mockOnClick).toHaveBeenCalled(); + expect(wrapper.hasClass(expectedClassName)).toBeTruthy(); }); -}); -describe(' with a header row', () => { - it('renders a header in response to the header element', () => { + it('renders header and children inside a ', () => { const header = ; - const wrapper = mount(); - const headerClass = `${BEM.header}`; - wrapper.setProps({ header }); - expect(wrapper.find(`.${headerClass}`).exists()).toBeTruthy(); - }); - - it('renders a header with label if the type of header is string', () => { - const header = 'foo'; - const wrapper = mount(); - const headerClass = `${BEM.header}`; - wrapper.setProps({ header }); - expect(wrapper.find(`.${headerClass}`).exists()).toBeTruthy(); + const children =
; + + const wrapper = shallow( + + {children} + + ); + const columnViewWrapper = wrapper.find(ColumnView); + + expect(columnViewWrapper.exists()).toBeTruthy(); + expect(columnViewWrapper.props()).toMatchObject({ + header, + children, + className: `${BEM.container}`, + }); }); -}); -describe('Pure ', () => { - it('renders the modal container class name', () => { - const wrapper = shallow(); - const containerClass = `${BEM.container}`; - - expect(wrapper.hasClass(containerClass)).toBeTruthy(); - }); + it('renders a basic if only given String', () => { + const wrapper = shallow( + Bar + ); - it('should render a padding if the prop bodyPadding is true', () => { - const wrapper = shallow(); - const paddingClass = BEM.body - .modifier('padding', true) - .toString({ stripBlock: true }); - expect(wrapper.find(`.${paddingClass}`).exists()).toBeTruthy(); + expect(wrapper.find(ColumnView).prop('header')).toMatchObject( + + ); }); - it('should not render a padding if the prop bodyPadding is null', () => { - const wrapper = shallow(); - const paddingClass = BEM.body - .modifier('padding', true) - .toString({ stripBlock: true }); - expect(wrapper.find(`.${paddingClass}`).exists()).toBeFalsy(); + it("passes 'flexBody' and 'bodyPadding' props to ", () => { + const wrapper = shallow( + +
Foo
+
+ ); + + expect(wrapper.find(ColumnView).props()).toMatchObject({ + flexBody: true, + bodyPadding: { bottom: 0 }, + }); }); }); diff --git a/packages/core/src/styles/ColumnView.scss b/packages/core/src/styles/ColumnView.scss index fe1b5324..d94092db 100644 --- a/packages/core/src/styles/ColumnView.scss +++ b/packages/core/src/styles/ColumnView.scss @@ -7,25 +7,32 @@ $component: #{$prefix}-column-view; background-color: $c-column-bg; display: flex; flex-direction: column; - // when nested under another column view + // when placed in another Flexbox flex: 1 1 100%; // -------------------- // Elements // -------------------- + &__header, &__footer { flex: 0 0 auto; } &__header { - z-index: 1; + z-index: 2; } &__body { - flex: 1 1 100%; + flex: 1 1 auto; overflow-y: scroll; -webkit-overflow-scrolling: touch; + z-index: 1; + + &--flex { + display: flex; + flex-direction: column; + } } &__footer { diff --git a/packages/core/src/styles/Modal.scss b/packages/core/src/styles/Modal.scss index bf85e4b4..fe50fea0 100644 --- a/packages/core/src/styles/Modal.scss +++ b/packages/core/src/styles/Modal.scss @@ -10,10 +10,8 @@ $component: #{$prefix}-modal; // ------------------------------------- // Modal Block // ------------------------------------- + .#{$prefix}-modal { - display: flex; - justify-content: center; - align-items: top; position: fixed; top: 0; bottom: 0; @@ -21,74 +19,24 @@ $component: #{$prefix}-modal; right: 0; padding: 10px; padding-top: 0; - text-align: center; - z-index: z("modal"); } // ------------------------------------- // Modal Elements // ------------------------------------- .#{$prefix}-modal { - // Container &__container { - width: $modal-width-full; - height: $modal-height; - max-width: $modal-width-base; + width: $modal-width; + max-width: $modal-max-width; + height: auto; + min-height: $modal-height; max-height: $modal-max-height; - margin: 0 auto; background-color: $c-bg-light; - display: flex; - flex-direction: column; - position: relative; border-radius: 0 0 $modal-border-radius $modal-border-radius; - box-shadow: $modal-box-shadow; - overflow: hidden; - text-align: left; - z-index: z("front"); - transition: width .15s; - } // Body - &__body { - flex: 1 1 auto; + margin: 0 auto; position: relative; - overflow: auto; - display: flex; - flex-direction: column; - padding-bottom: 24px; - - &--padding { - padding: 24px; - } - } // Header - &__header { - flex: 0 0 auto; - } // Footer - &__footer { - flex: 0 0 auto; - padding: 0 24px; - text-align: right; - border-top: 1px solid $c-modal-border; - } -} - -// ------------------------------------- -// Modal Sizes -// ------------------------------------- -.#{$prefix}-modal { - // Small - &--small { - .#{$prefix}-modal__container { - max-width: $modal-width-small; - } - } // Large - &--large { - .#{$prefix}-modal__container { - max-width: $modal-width-large; - } - } // Full - &--full { - .#{$prefix}-modal__container { - max-width: $modal-width-full; - } + overflow: hidden; + animation: anim-slide-down .4s forwards; } } @@ -96,9 +44,9 @@ $component: #{$prefix}-modal; // Modal Position // ------------------------------------- .#{$prefix}-modal { - &--center { + &--centered { + display: flex; align-items: center; - padding-top: 10px; .#{$prefix}-modal__container { border-radius: $modal-border-radius; @@ -106,24 +54,6 @@ $component: #{$prefix}-modal; } } -// ------------------------------------- -// Modal Modifies -// ------------------------------------- -.#{$prefix}-modal { - // Active State - &--active { - // Backdrop - .#{$prefix}-modal__backdrop { - opacity: 0; - animation: anim-fade-in .3s forwards; - } // Container - .#{$prefix}-modal__container { - opacity: 0; - animation: anim-slide-down .4s forwards; - } - } -} - // ------------------------------------- // width indent for multiple modal // ------------------------------------- @@ -139,21 +69,8 @@ $component: #{$prefix}-modal; #{repeat-str('.#{$prefix}-base-layer ~', $i)} .#{$prefix}-base-layer { .#{$prefix}-modal { &__container { - width: calc(#{$modal-width-full} - #{$i * 16}px); - max-width: $modal-width-base - $i * 16px; - height: $modal-height - $i * 8px; - } - - &--large { - > .#{$prefix}-modal__container { - max-width: $modal-width-large - $i * 16px; - } - } - - &--small { - > .#{$prefix}-modal__container { - max-width: $modal-width-small - $i * 16px; - } + width: $modal-width - $i * 64px; + height: $modal-height - $i * 32px; } } } diff --git a/packages/core/src/styles/_variables.scss b/packages/core/src/styles/_variables.scss index a550340f..4b38ba6a 100644 --- a/packages/core/src/styles/_variables.scss +++ b/packages/core/src/styles/_variables.scss @@ -101,12 +101,10 @@ $popover-bottom-padding: 16px; $popover-border-radius: 8px; $popover-drop-shadow: 0 2px 3px hsba(0, 0, 0, 40); -$modal-width-small: 320px; -$modal-width-base: 640px; -$modal-width-large: 960px; -$modal-width-full: 90%; -$modal-height: 480px; -$modal-max-height: 80vh; +$modal-width: 720px; +$modal-max-width: 90%; +$modal-height: 480px; +$modal-max-height: 90%; $modal-border-radius: $popover-border-radius; $modal-box-shadow: $poup-box-shadow; $modal-indent-layer-max: 7; diff --git a/packages/core/src/utils/wrapIfNotElement.js b/packages/core/src/utils/wrapIfNotElement.js index 6f48bdf6..560e1bfb 100644 --- a/packages/core/src/utils/wrapIfNotElement.js +++ b/packages/core/src/utils/wrapIfNotElement.js @@ -3,12 +3,6 @@ import React from 'react'; /** * Wrap the passed-in `content` with a component if it's not a React element, * to make sure the result will always be a HTML tag. - * - * @param {ReactChildren} content - * @param {Component} Wrapper - * @param {String} prop - pass `content` into specified `prop`. Default via 'children'. - * - * @return {Element} */ function wrapIfNotElement(content, { with: Wrapper, diff --git a/packages/storybook/examples/core/Modal/BasicModal.js b/packages/storybook/examples/core/Modal/ClosableModalExample.js similarity index 62% rename from packages/storybook/examples/core/Modal/BasicModal.js rename to packages/storybook/examples/core/Modal/ClosableModalExample.js index 7b5234bb..da4d8a7c 100644 --- a/packages/storybook/examples/core/Modal/BasicModal.js +++ b/packages/storybook/examples/core/Modal/ClosableModalExample.js @@ -1,20 +1,12 @@ import React, { PureComponent } from 'react'; import { action } from '@storybook/addon-actions'; -import Modal from '@ichef/gypcrete/src/Modal'; -import ModalHeader from './ModalHeader'; +import Button from '@ichef/gypcrete/src/Button'; +import Modal from '@ichef/gypcrete/src/Modal'; -function BasicModalExample({ children, ...props }) { - return ( - -
- {children} -
-
- ); -} +import ModalHeader from './ModalHeader'; -class ClosableModalExample extends PureComponent { +export default class ClosableModalExample extends PureComponent { state ={ modalOpen: true }; @@ -36,20 +28,32 @@ class ClosableModalExample extends PureComponent { ); if (!modalOpen) { - return null; + return ( +
+ +
+ ); } return ( - + > + Modal content + ); } } -const MulitpleClosableModalExample = (props) => { +export const MulitpleClosableModalExample = (props) => { const { depth, modalProp } = props; if (depth === 0) { return false; @@ -61,6 +65,3 @@ const MulitpleClosableModalExample = (props) => { ); }; - -export { ClosableModalExample, MulitpleClosableModalExample }; -export default BasicModalExample; diff --git a/packages/storybook/examples/core/Modal/index.js b/packages/storybook/examples/core/Modal/index.js index 5c9f1222..a155da7a 100644 --- a/packages/storybook/examples/core/Modal/index.js +++ b/packages/storybook/examples/core/Modal/index.js @@ -3,65 +3,51 @@ import { storiesOf } from '@storybook/react'; import { withInfo } from '@storybook/addon-info'; import Modal, { PureModal } from '@ichef/gypcrete/src/Modal'; -import getPropTables from 'utils/getPropTables'; +import { getAddonOptions } from 'utils/getPropTables'; -import BasicModalExample, { ClosableModalExample, MulitpleClosableModalExample } from './BasicModal'; +import ContainsColumnView from '../SplitView/ContainsColumnView'; +import ClosableModalExample, { MulitpleClosableModalExample } from './ClosableModalExample'; storiesOf('@ichef/gypcrete|Modal', module) + .addDecorator(withInfo) .add( - 'basic usage', - withInfo()(() => ( - - Modal Content - - )) + 'basic modal', + () => ( + + Hello World! + + ) ) .add( - 'small modal', - withInfo()(() => ( - - Modal Content - - )) + 'closable modal', + () => ) .add( - 'large modal', - withInfo()(() => ( - - Modal Content - - )) + 'with ', + () => ( + + + + ) ) .add( - 'full modal', - withInfo()(() => ( - - Modal Content - - )) + 'centered modal', + () => ( + + Hello World! + + ) ) - .add('closable modal', withInfo()(() => )) - .add( - 'closable overlaying modals', - withInfo()(() => ( - -
Outer Modal
- -
Inner Modal
-
-
- )) - ) - .add('centered modal', withInfo()(() => ( - - Modal Content - - ))) .add( 'multiple layer modals', - withInfo('Indented with 8px from each side for each layer. When number of layer > 7 we won\'t indent it')(() => ( - - )) + () => , + { + info: 'Indented with 32px from each side for each layer. When number of layer > 7 we won\'t indent it', + } ) // Props table - .add('props', getPropTables([PureModal, Modal])); + .add( + 'props', + () =>
, + { info: getAddonOptions([PureModal, Modal]) } + ); diff --git a/packages/storybook/examples/core/SplitView/BasicUsage.js b/packages/storybook/examples/core/SplitView/BasicUsage.js index 207e6f79..67ce80a6 100644 --- a/packages/storybook/examples/core/SplitView/BasicUsage.js +++ b/packages/storybook/examples/core/SplitView/BasicUsage.js @@ -3,32 +3,29 @@ import React from 'react'; import SplitView from '@ichef/gypcrete/src/SplitView'; import SplitViewColumn from '@ichef/gypcrete/src/SplitViewColumn'; -import DebugBox from 'utils/DebugBox'; import ColoredBox from 'utils/ColoredBox'; function BasicUsage() { return ( - - - - - Narrow Column - - + + + + Narrow Column + + - - - Narrow Column - - - - + + + Narrow Column + + + ); } diff --git a/packages/storybook/examples/core/SplitView/ContainsColumnView.js b/packages/storybook/examples/core/SplitView/ContainsColumnView.js index 322d89f8..6f168f61 100644 --- a/packages/storybook/examples/core/SplitView/ContainsColumnView.js +++ b/packages/storybook/examples/core/SplitView/ContainsColumnView.js @@ -3,38 +3,35 @@ import React from 'react'; import SplitView from '@ichef/gypcrete/src/SplitView'; import SplitViewColumn from '@ichef/gypcrete/src/SplitViewColumn'; -import DebugBox from 'utils/DebugBox'; import ColoredBox from 'utils/ColoredBox'; import DemoColumnView from './DemoColumnView'; function ContainsColumnView() { return ( - - - - - - Narrow Column - - - + + + + + Narrow Column + + + - - - - Narrow Column - - - - - + + + + Narrow Column + + + + ); } diff --git a/packages/storybook/examples/core/SplitView/InsideColumnView.js b/packages/storybook/examples/core/SplitView/InsideColumnView.js index 7670dd51..44083d36 100644 --- a/packages/storybook/examples/core/SplitView/InsideColumnView.js +++ b/packages/storybook/examples/core/SplitView/InsideColumnView.js @@ -3,36 +3,33 @@ import React from 'react'; import SplitView from '@ichef/gypcrete/src/SplitView'; import SplitViewColumn from '@ichef/gypcrete/src/SplitViewColumn'; -import DebugBox from 'utils/DebugBox'; import ColoredBox from 'utils/ColoredBox'; import DemoColumnView from './DemoColumnView'; function InsideColumnView() { return ( - - - - - - Narrow Column - - + + + + + Narrow Column + + - - - Narrow Column - - - - - + + + Narrow Column + + + + ); } diff --git a/packages/storybook/examples/core/SplitView/index.js b/packages/storybook/examples/core/SplitView/index.js index 937a7349..b6041fff 100644 --- a/packages/storybook/examples/core/SplitView/index.js +++ b/packages/storybook/examples/core/SplitView/index.js @@ -1,16 +1,38 @@ +import React from 'react'; import { storiesOf } from '@storybook/react'; import { withInfo } from '@storybook/addon-info'; import SplitView from '@ichef/gypcrete/src/SplitView'; import SplitViewColumn from '@ichef/gypcrete/src/SplitViewColumn'; -import getPropTables from 'utils/getPropTables'; + +import DebugBox from 'utils/DebugBox'; +import { getAddonOptions } from 'utils/getPropTables'; import BasicUsage from './BasicUsage'; import ContainsColumnView from './ContainsColumnView'; import InsideColumnView from './InsideColumnView'; storiesOf('@ichef/gypcrete|SplitView', module) - .add('basic usage', withInfo()(BasicUsage)) - .add('contains ', withInfo()(ContainsColumnView)) - .add('inside ', withInfo()(InsideColumnView)) - .add('props', getPropTables([SplitView, SplitViewColumn])); + .addDecorator((storyFn, { parameters = {} }) => { + if (parameters.debugBox === false) { + return storyFn(); + } + return ( + + {storyFn()} + + ); + }) + .addDecorator(withInfo) + + .add('basic usage', BasicUsage) + .add('contains ', ContainsColumnView) + .add('inside ', InsideColumnView) + .add( + 'props', + () =>
, + { + info: getAddonOptions([SplitView, SplitViewColumn]), + debugBox: false, + } + ); diff --git a/packages/storybook/utils/getPropTables.js b/packages/storybook/utils/getPropTables.js index e2744269..9eb104ae 100644 --- a/packages/storybook/utils/getPropTables.js +++ b/packages/storybook/utils/getPropTables.js @@ -6,11 +6,17 @@ const DEFAULT_OPTIONS = { }; const EMPTY_COMPONENT = () =>
; -function getPropTables(components = [], options = {}) { - return withInfo({ +export function getAddonOptions(components = []) { + return { ...DEFAULT_OPTIONS, - ...options, propTables: components, + }; +} + +function getPropTables(components, options = {}) { + return withInfo({ + ...getAddonOptions(components), + ...options, })(EMPTY_COMPONENT); }