diff --git a/README.md b/README.md index bf21f72ccf..27a4d2b81c 100644 --- a/README.md +++ b/README.md @@ -140,7 +140,7 @@ Any other issue labeled [`help wanted`][4] is ready for a PR. |-----------------|-----------------|-----------------|-----------------|--------------------| | ✓ Button | ✓ Breadcrumb | Advertisement | ✓ Accordion | ✓ Form Validation | | ✓ Container | ✓ Form | ✓ Card | ✓ Checkbox | *API (NA)* | -| ✓ Divider | ✓ Grid | ✓ Comment | Dimmer | *Visibility (NA)* | +| ✓ Divider | ✓ Grid | ✓ Comment | ✓ Dimmer | *Visibility (NA)* | | ✓ Flag | ✓ Menu | ✓ Feed | ✓ Dropdown | | | ✓ Header | ✓ Message | ✓ Item | Embed | | | ✓ Icon | ✓ Table | ✓ Statistic | ✓ Modal | | diff --git a/docs/app/Examples/elements/Loader/States/LoaderExampleIndeterminate.js b/docs/app/Examples/elements/Loader/States/LoaderExampleIndeterminate.js index 5fd2b1fd5a..885fd5a713 100644 --- a/docs/app/Examples/elements/Loader/States/LoaderExampleIndeterminate.js +++ b/docs/app/Examples/elements/Loader/States/LoaderExampleIndeterminate.js @@ -1,14 +1,12 @@ import React from 'react' -import { Loader, Image, Segment } from 'semantic-ui-react' - -// TODO: Update usage after its update to v1 API +import { Dimmer, Loader, Image, Segment } from 'semantic-ui-react' const LoaderExampleIndeterminate = () => (
-
+ Preparing Files -
+
diff --git a/docs/app/Examples/elements/Loader/Types/LoaderExampleLoader.js b/docs/app/Examples/elements/Loader/Types/LoaderExampleLoader.js index f40f4b8afe..3ebd85a631 100644 --- a/docs/app/Examples/elements/Loader/Types/LoaderExampleLoader.js +++ b/docs/app/Examples/elements/Loader/Types/LoaderExampleLoader.js @@ -1,13 +1,11 @@ import React from 'react' -import { Loader, Image, Segment } from 'semantic-ui-react' - -// TODO: Update usage after its update to v1 API +import { Dimmer, Loader, Image, Segment } from 'semantic-ui-react' const LoaderExampleLoader = () => ( -
+ -
+
diff --git a/docs/app/Examples/elements/Loader/Types/LoaderExampleText.js b/docs/app/Examples/elements/Loader/Types/LoaderExampleText.js index 36b266ad56..561079407c 100644 --- a/docs/app/Examples/elements/Loader/Types/LoaderExampleText.js +++ b/docs/app/Examples/elements/Loader/Types/LoaderExampleText.js @@ -1,22 +1,20 @@ import React from 'react' -import { Loader, Image, Segment } from 'semantic-ui-react' - -// TODO: Update usage after its update to v1 API +import { Dimmer, Loader, Image, Segment } from 'semantic-ui-react' const LoaderExampleText = () => (
-
+ Loading -
+
-
+ Loading -
+
diff --git a/docs/app/Examples/elements/Loader/Types/LoaderExampleTextShorthand.js b/docs/app/Examples/elements/Loader/Types/LoaderExampleTextShorthand.js index e690b28211..9e05c2c7a6 100644 --- a/docs/app/Examples/elements/Loader/Types/LoaderExampleTextShorthand.js +++ b/docs/app/Examples/elements/Loader/Types/LoaderExampleTextShorthand.js @@ -1,22 +1,20 @@ import React from 'react' -import { Loader, Image, Segment } from 'semantic-ui-react' - -// TODO: Update usage after its update to v1 API +import { Dimmer, Loader, Image, Segment } from 'semantic-ui-react' const LoaderExampleTextShorthand = () => (
-
+ -
+
-
+ -
+
diff --git a/docs/app/Examples/elements/Loader/Types/index.js b/docs/app/Examples/elements/Loader/Types/index.js index 5ffcf9dfe9..ea360941ef 100644 --- a/docs/app/Examples/elements/Loader/Types/index.js +++ b/docs/app/Examples/elements/Loader/Types/index.js @@ -12,7 +12,7 @@ const LoaderTypesExamples = () => ( examplePath='elements/Loader/Types/LoaderExampleLoader' > - Loaders are hidden unless has prop "active" or inside an "active dimmer". + Loaders are hidden unless has prop active or inside an Dimmer active. diff --git a/docs/app/Examples/elements/Loader/Variations/LoaderExampleSizes.js b/docs/app/Examples/elements/Loader/Variations/LoaderExampleSizes.js index e58aa27f3f..64c63b7586 100644 --- a/docs/app/Examples/elements/Loader/Variations/LoaderExampleSizes.js +++ b/docs/app/Examples/elements/Loader/Variations/LoaderExampleSizes.js @@ -1,47 +1,45 @@ import React from 'react' -import { Loader, Image, Segment } from 'semantic-ui-react' - -// TODO: Update usage after its update to v1 API +import { Dimmer, Loader, Image, Segment } from 'semantic-ui-react' const LoaderExampleSizes = () => (
-
+ Loading -
+
-
+ Loading -
+
-
+ Loading -
+
-
+ Loading -
+
-
+ Loading -
+ @@ -49,9 +47,9 @@ const LoaderExampleSizes = () => (
-
+ Loading -
+ @@ -59,9 +57,9 @@ const LoaderExampleSizes = () => (
-
+ Loading -
+ @@ -69,9 +67,9 @@ const LoaderExampleSizes = () => (
-
+ Loading -
+ diff --git a/docs/app/Examples/elements/Loader/Variations/LoaderExampleSizesInverted.js b/docs/app/Examples/elements/Loader/Variations/LoaderExampleSizesInverted.js index 7f2978f242..c223110663 100644 --- a/docs/app/Examples/elements/Loader/Variations/LoaderExampleSizesInverted.js +++ b/docs/app/Examples/elements/Loader/Variations/LoaderExampleSizesInverted.js @@ -1,38 +1,36 @@ import React from 'react' -import { Loader, Image, Segment } from 'semantic-ui-react' - -// TODO: Update usage after its update to v1 API +import { Dimmer, Loader, Image, Segment } from 'semantic-ui-react' const LoaderExampleSizesInverted = () => (
-
+ Loading -
+
-
+ Loading -
+
-
+ Loading -
+
-
+ Loading -
+
diff --git a/docs/app/Examples/modules/Dimmer/States/DimmerExampleActive.js b/docs/app/Examples/modules/Dimmer/States/DimmerExampleActive.js new file mode 100644 index 0000000000..1aeebd8c04 --- /dev/null +++ b/docs/app/Examples/modules/Dimmer/States/DimmerExampleActive.js @@ -0,0 +1,17 @@ +import React from 'react' +import { Dimmer, Segment } from 'semantic-ui-react' + +const DimmerExampleActive = () => ( + + + +

+ +

+

+ +

+
+) + +export default DimmerExampleActive diff --git a/docs/app/Examples/modules/Dimmer/States/index.js b/docs/app/Examples/modules/Dimmer/States/index.js new file mode 100644 index 0000000000..8015c1d0a4 --- /dev/null +++ b/docs/app/Examples/modules/Dimmer/States/index.js @@ -0,0 +1,16 @@ +import React from 'react' + +import ComponentExample from 'docs/app/Components/ComponentDoc/ComponentExample' +import ExampleSection from 'docs/app/Components/ComponentDoc/ExampleSection' + +const DimmerStatesExamples = () => ( + + + +) + +export default DimmerStatesExamples diff --git a/docs/app/Examples/modules/Dimmer/Types/DimmerExampleContent.js b/docs/app/Examples/modules/Dimmer/Types/DimmerExampleContent.js new file mode 100644 index 0000000000..da03fa34cd --- /dev/null +++ b/docs/app/Examples/modules/Dimmer/Types/DimmerExampleContent.js @@ -0,0 +1,41 @@ +import React, { Component } from 'react' +import { Button, Dimmer, Header, Icon, Image, Segment } from 'semantic-ui-react' + +export default class DimmerExampleDimmer extends Component { + state = {} + + handleShow = () => this.setState({ active: true }) + handleHide = () => this.setState({ active: false }) + + render() { + const { active } = this.state + + return ( +
+ + +
+ + Dimmed Message! +
+
+ +
Overlayable Section
+ + + + + + + + +
+ + +
+ ) + } +} diff --git a/docs/app/Examples/modules/Dimmer/Types/DimmerExampleDimmer.js b/docs/app/Examples/modules/Dimmer/Types/DimmerExampleDimmer.js new file mode 100644 index 0000000000..3d25dc85ce --- /dev/null +++ b/docs/app/Examples/modules/Dimmer/Types/DimmerExampleDimmer.js @@ -0,0 +1,36 @@ +import React, { Component } from 'react' +import { Button, Dimmer, Header, Image, Segment } from 'semantic-ui-react' + +export default class DimmerExampleDimmer extends Component { + state = {} + + handleShow = () => this.setState({ active: true }) + handleHide = () => this.setState({ active: false }) + + render() { + const { active } = this.state + + return ( +
+ + + +
Overlayable Section
+ + + + + + + + +
+ + +
+ ) + } +} diff --git a/docs/app/Examples/modules/Dimmer/Types/DimmerExamplePage.js b/docs/app/Examples/modules/Dimmer/Types/DimmerExamplePage.js new file mode 100644 index 0000000000..7cad633d02 --- /dev/null +++ b/docs/app/Examples/modules/Dimmer/Types/DimmerExamplePage.js @@ -0,0 +1,36 @@ +import React, { Component } from 'react' +import { Button, Dimmer, Header, Icon } from 'semantic-ui-react' + +export default class DimmerExamplePage extends Component { + state = {} + + handleOpen = () => this.setState({ active: true }) + handleClose = () => this.setState({ active: false }) + + render() { + const { active } = this.state + + return ( +
+
+ ) + } +} diff --git a/docs/app/Examples/modules/Dimmer/Types/index.js b/docs/app/Examples/modules/Dimmer/Types/index.js new file mode 100644 index 0000000000..45be2bf773 --- /dev/null +++ b/docs/app/Examples/modules/Dimmer/Types/index.js @@ -0,0 +1,26 @@ +import React from 'react' + +import ComponentExample from 'docs/app/Components/ComponentDoc/ComponentExample' +import ExampleSection from 'docs/app/Components/ComponentDoc/ExampleSection' + +const DimmerTypesExamples = () => ( + + + + + +) + +export default DimmerTypesExamples diff --git a/docs/app/Examples/modules/Dimmer/Usage/DimmerExampleEvents.js b/docs/app/Examples/modules/Dimmer/Usage/DimmerExampleEvents.js new file mode 100644 index 0000000000..baf8a9a4d9 --- /dev/null +++ b/docs/app/Examples/modules/Dimmer/Usage/DimmerExampleEvents.js @@ -0,0 +1,33 @@ +import React, { Component } from 'react' +import { Button, Dimmer, Header, Image } from 'semantic-ui-react' + +export default class DimmerExampleEvents extends Component { + state = {} + + handleShow = () => this.setState({ active: true }) + handleHide = () => this.setState({ active: false }) + + render() { + const { active } = this.state + const content = ( +
+
Title
+ + + +
+ ) + + return ( + + ) + } +} diff --git a/docs/app/Examples/modules/Dimmer/Usage/DimmerExampleLoader.js b/docs/app/Examples/modules/Dimmer/Usage/DimmerExampleLoader.js new file mode 100644 index 0000000000..6782b95725 --- /dev/null +++ b/docs/app/Examples/modules/Dimmer/Usage/DimmerExampleLoader.js @@ -0,0 +1,35 @@ +import React, { Component } from 'react' +import { Button, Dimmer, Loader, Segment } from 'semantic-ui-react' + +export default class DimmerExampleLoader extends Component { + state = {} + + handleShow = () => this.setState({ active: true }) + handleHide = () => this.setState({ active: false }) + + render() { + const { active } = this.state + + return ( +
+ + + Loading + + +

+ +

+

+ +

+
+ + +
+ ) + } +} diff --git a/docs/app/Examples/modules/Dimmer/Usage/index.js b/docs/app/Examples/modules/Dimmer/Usage/index.js new file mode 100644 index 0000000000..da5865372d --- /dev/null +++ b/docs/app/Examples/modules/Dimmer/Usage/index.js @@ -0,0 +1,21 @@ +import React from 'react' + +import ComponentExample from 'docs/app/Components/ComponentDoc/ComponentExample' +import ExampleSection from 'docs/app/Components/ComponentDoc/ExampleSection' + +const DimmerStatesExamples = () => ( + + + + +) + +export default DimmerStatesExamples diff --git a/docs/app/Examples/modules/Dimmer/Variations/DimmerExampleBlurring.js b/docs/app/Examples/modules/Dimmer/Variations/DimmerExampleBlurring.js new file mode 100644 index 0000000000..b192753179 --- /dev/null +++ b/docs/app/Examples/modules/Dimmer/Variations/DimmerExampleBlurring.js @@ -0,0 +1,33 @@ +import React, { Component } from 'react' +import { Button, Dimmer, Segment } from 'semantic-ui-react' + +export default class DimmerExampleBlurring extends Component { + state = {} + + handleShow = () => this.setState({ active: true }) + handleHide = () => this.setState({ active: false }) + + render() { + const { active } = this.state + + return ( +
+ + + +

+ +

+

+ +

+
+ + +
+ ) + } +} diff --git a/docs/app/Examples/modules/Dimmer/Variations/DimmerExampleBlurringInverted.js b/docs/app/Examples/modules/Dimmer/Variations/DimmerExampleBlurringInverted.js new file mode 100644 index 0000000000..abaead6455 --- /dev/null +++ b/docs/app/Examples/modules/Dimmer/Variations/DimmerExampleBlurringInverted.js @@ -0,0 +1,33 @@ +import React, { Component } from 'react' +import { Button, Dimmer, Segment } from 'semantic-ui-react' + +export default class DimmerExampleBlurringInverted extends Component { + state = {} + + handleShow = () => this.setState({ active: true }) + handleHide = () => this.setState({ active: false }) + + render() { + const { active } = this.state + + return ( +
+ + + +

+ +

+

+ +

+
+ + +
+ ) + } +} diff --git a/docs/app/Examples/modules/Dimmer/Variations/DimmerExampleInverted.js b/docs/app/Examples/modules/Dimmer/Variations/DimmerExampleInverted.js new file mode 100644 index 0000000000..dc1fd14629 --- /dev/null +++ b/docs/app/Examples/modules/Dimmer/Variations/DimmerExampleInverted.js @@ -0,0 +1,33 @@ +import React, { Component } from 'react' +import { Button, Dimmer, Segment } from 'semantic-ui-react' + +export default class DimmerExampleInverted extends Component { + state = {} + + handleShow = () => this.setState({ active: true }) + handleHide = () => this.setState({ active: false }) + + render() { + const { active } = this.state + + return ( +
+ + + +

+ +

+

+ +

+
+ + +
+ ) + } +} diff --git a/docs/app/Examples/modules/Dimmer/Variations/DimmerExampleSimple.js b/docs/app/Examples/modules/Dimmer/Variations/DimmerExampleSimple.js new file mode 100644 index 0000000000..c151a7a870 --- /dev/null +++ b/docs/app/Examples/modules/Dimmer/Variations/DimmerExampleSimple.js @@ -0,0 +1,17 @@ +import React from 'react' +import { Dimmer, Segment } from 'semantic-ui-react' + +const DimmerExampleSimple = () => ( + + + +

+ +

+

+ +

+
+) + +export default DimmerExampleSimple diff --git a/docs/app/Examples/modules/Dimmer/Variations/index.js b/docs/app/Examples/modules/Dimmer/Variations/index.js new file mode 100644 index 0000000000..6b1be0ba9f --- /dev/null +++ b/docs/app/Examples/modules/Dimmer/Variations/index.js @@ -0,0 +1,29 @@ +import React from 'react' + +import ComponentExample from 'docs/app/Components/ComponentDoc/ComponentExample' +import ExampleSection from 'docs/app/Components/ComponentDoc/ExampleSection' + +const DimmerVariationsExamples = () => ( + + + + + + + + +) + +export default DimmerVariationsExamples diff --git a/docs/app/Examples/modules/Dimmer/index.js b/docs/app/Examples/modules/Dimmer/index.js new file mode 100644 index 0000000000..70d708eef3 --- /dev/null +++ b/docs/app/Examples/modules/Dimmer/index.js @@ -0,0 +1,17 @@ +import React from 'react' + +import States from './States' +import Types from './Types' +import Variations from './Variations' +import Usage from './Usage' + +const DimmerExamples = () => ( +
+ + + + +
+) + +export default DimmerExamples diff --git a/src/elements/Image/Image.js b/src/elements/Image/Image.js index 85c2a0ed18..94f56cfe31 100644 --- a/src/elements/Image/Image.js +++ b/src/elements/Image/Image.js @@ -2,23 +2,24 @@ import cx from 'classnames' import React, { PropTypes } from 'react' import { - getElementType, createShorthandFactory, customPropTypes, + getElementType, getUnhandledProps, META, SUI, - useVerticalAlignProp, + useKeyOnly, useKeyOrValueAndKey, useValueAndKey, - useKeyOnly, + useVerticalAlignProp, } from '../../lib' +import Dimmer from '../../modules/Dimmer' import Label from '../Label/Label' import ImageGroup from './ImageGroup' /** - * An image is a graphic representation of something + * An image is a graphic representation of something. * @see Icon */ function Image(props) { @@ -28,6 +29,7 @@ function Image(props) { bordered, centered, className, + dimmer, disabled, floated, fluid, @@ -49,33 +51,33 @@ function Image(props) { const classes = cx( useKeyOnly(ui, 'ui'), size, - useVerticalAlignProp(verticalAlign, 'aligned'), + shape, useKeyOnly(avatar, 'avatar'), useKeyOnly(bordered, 'bordered'), useKeyOnly(centered, 'centered'), useKeyOnly(disabled, 'disabled'), - useValueAndKey(floated, 'floated'), useKeyOnly(fluid, 'fluid'), useKeyOnly(hidden, 'hidden'), useKeyOnly(inline, 'inline'), useKeyOrValueAndKey(spaced, 'spaced'), - shape, + useValueAndKey(floated, 'floated'), + useVerticalAlignProp(verticalAlign, 'aligned'), + 'image', className, - 'image' ) const rest = getUnhandledProps(Image, props) - const rootProps = { className: classes, ...rest } - const imgTagProps = { src, alt, width, height } const ElementType = getElementType(Image, props, () => { - if (label || wrapped) return 'div' + if (dimmer || label || wrapped) return 'div' }) - if (ElementType === 'img') { - return - } + const rootProps = { className: classes, ...rest } + const imgTagProps = { alt, src, height, width } + + if (ElementType === 'img') return return ( + {Dimmer.create(dimmer)} {Label.create(label)} @@ -100,72 +102,75 @@ Image.propTypes = { /** An element type to render as (string or function). */ as: customPropTypes.as, - /** An image can specify its vertical alignment */ - verticalAlign: PropTypes.oneOf(Image._meta.props.verticalAlign), - - /** Alternate text for the image specified */ + /** Alternate text for the image specified. */ alt: PropTypes.string, - /** An image may be formatted to appear inline with text as an avatar */ + /** An image may be formatted to appear inline with text as an avatar. */ avatar: PropTypes.bool, - /** An image may include a border to emphasize the edges of white or transparent content */ + /** An image may include a border to emphasize the edges of white or transparent content. */ bordered: PropTypes.bool, - /** An image can appear centered in a content block */ + /** An image can appear centered in a content block. */ centered: PropTypes.bool, /** Additional classes. */ className: PropTypes.string, - /** An image can show that it is disabled and cannot be selected */ + /** An image can show that it is disabled and cannot be selected. */ disabled: PropTypes.bool, - /** An image can sit to the left or right of other content */ + /** Shorthand for Dimmer. */ + dimmer: customPropTypes.itemShorthand, + + /** An image can sit to the left or right of other content. */ floated: PropTypes.oneOf(Image._meta.props.floated), - /** An image can take up the width of its container */ + /** An image can take up the width of its container. */ fluid: customPropTypes.every([ PropTypes.bool, customPropTypes.disallow(['size']), ]), - /** An image can be hidden */ - hidden: PropTypes.bool, - - /** The img element height attribute */ + /** The img element height attribute. */ height: PropTypes.oneOfType([ PropTypes.string, PropTypes.number, ]), - /** Renders the Image as an tag with this href */ + /** An image can be hidden. */ + hidden: PropTypes.bool, + + /** Renders the Image as an tag with this href. */ href: PropTypes.string, - /** An image may appear inline */ + /** An image may appear inline. */ inline: PropTypes.bool, /** Shorthand for Label. */ label: customPropTypes.itemShorthand, - /** An image may appear rounded or circular */ + /** An image may appear rounded or circular. */ shape: PropTypes.oneOf(Image._meta.props.shape), - /** An image may appear at different sizes */ + /** An image may appear at different sizes. */ size: PropTypes.oneOf(Image._meta.props.size), - /** An image can specify that it needs an additional spacing to separate it from nearby content */ + /** An image can specify that it needs an additional spacing to separate it from nearby content. */ spaced: PropTypes.oneOfType([ PropTypes.bool, PropTypes.oneOf(Image._meta.props.spaced), ]), - /** Specifies the URL of the image */ + /** Specifies the URL of the image. */ src: PropTypes.string, - /** Whether or not to add the ui className */ + /** Whether or not to add the ui className. */ ui: PropTypes.bool, + /** An image can specify its vertical alignment */ + verticalAlign: PropTypes.oneOf(Image._meta.props.verticalAlign), + /** The img element width attribute */ width: PropTypes.oneOfType([ PropTypes.string, diff --git a/src/elements/Loader/Loader.js b/src/elements/Loader/Loader.js index f0956fe32b..4dd73c6e29 100644 --- a/src/elements/Loader/Loader.js +++ b/src/elements/Loader/Loader.js @@ -11,6 +11,10 @@ import { useKeyOrValueAndKey, } from '../../lib' +/** + * A loader alerts a user to wait for an activity to complete. + * @see Dimmer + */ function Loader(props) { const { active, diff --git a/src/index.js b/src/index.js index 70198d069d..a23e34676c 100644 --- a/src/index.js +++ b/src/index.js @@ -100,6 +100,9 @@ export { default as AccordionTitle } from './modules/Accordion/AccordionTitle' export { default as Checkbox } from './modules/Checkbox' +export { default as Dimmer } from './modules/Dimmer' +export { default as DimmerDimmable } from './modules/Dimmer/DimmerDimmable' + export { default as Dropdown } from './modules/Dropdown' export { default as DropdownDivider } from './modules/Dropdown/DropdownDivider' export { default as DropdownHeader } from './modules/Dropdown/DropdownHeader' diff --git a/src/modules/Dimmer/Dimmer.js b/src/modules/Dimmer/Dimmer.js new file mode 100644 index 0000000000..78d91437a2 --- /dev/null +++ b/src/modules/Dimmer/Dimmer.js @@ -0,0 +1,124 @@ +import cx from 'classnames' +import React, { Component, PropTypes } from 'react' + +import { + createShorthandFactory, + customPropTypes, + getElementType, + getUnhandledProps, + META, + useKeyOnly, +} from '../../lib' +import Portal from '../../addons/Portal' +import DimmerDimmable from './DimmerDimmable' + +const _meta = { + name: 'Dimmer', + type: META.TYPES.MODULE, +} + +/** + * A dimmer hides distractions to focus attention on particular content. + */ +export default class Dimmer extends Component { + static propTypes = { + /** An element type to render as (string or function). */ + as: customPropTypes.as, + + /** An active dimmer will dim its parent container. */ + active: PropTypes.bool, + + /** Primary content. */ + children: PropTypes.node, + + /** Additional classes. */ + className: PropTypes.string, + + /** Shorthand for primary content. */ + content: customPropTypes.contentShorthand, + + /** Called with (event, props) after user's click. */ + onClick: PropTypes.func, + + /** Handles click outside Dimmer's content, but inside Dimmer area. */ + onClickOutside: PropTypes.func, + + /** A dimmer can be formatted to have its colors inverted. */ + inverted: PropTypes.bool, + + /** A dimmer can be formatted to be fixed to the page. */ + page: PropTypes.bool, + + /** A dimmer can be controlled with simple prop. */ + simple: PropTypes.bool, + } + + static _meta = _meta + + static Dimmable = DimmerDimmable + + handlePortalMount = () => document.body.classList.add('dimmed', 'dimmable') + + handlePortalUnmount = () => document.body.classList.remove('dimmed', 'dimmable') + + handleClick = (e) => { + const { onClick, onClickOutside } = this.props + + if (onClick) onClick(e, this.props) + if (this.center && (this.center !== e.target && this.center.contains(e.target))) return + if (onClickOutside) onClickOutside(e, this.props) + } + + render() { + const { + active, + children, + className, + content, + inverted, + page, + simple, + } = this.props + + const classes = cx( + 'ui', + useKeyOnly(active, 'active'), + useKeyOnly(inverted, 'inverted'), + useKeyOnly(page, 'page'), + useKeyOnly(simple, 'simple'), + 'dimmer transition visible', + className, + ) + const rest = getUnhandledProps(Dimmer, this.props) + const ElementType = getElementType(Dimmer, this.props) + + const childrenJSX = (children || content) && ( +
+
(this.center = center)}> + { children || content } +
+
+ ) + + if (page) { + return ( + + {childrenJSX}
+ + ) + } + + return {childrenJSX}
+ } +} + +// Dimmer is not yet defined inside the class +// Do not use a static property initializer +Dimmer.create = createShorthandFactory(Dimmer, value => ({ content: value })) diff --git a/src/modules/Dimmer/DimmerDimmable.js b/src/modules/Dimmer/DimmerDimmable.js new file mode 100644 index 0000000000..40bec9ec07 --- /dev/null +++ b/src/modules/Dimmer/DimmerDimmable.js @@ -0,0 +1,58 @@ +import cx from 'classnames' +import React, { PropTypes } from 'react' + +import { + customPropTypes, + getElementType, + getUnhandledProps, + META, + useKeyOnly, +} from '../../lib' + +/** + * A dimmable sub-component for Dimmer. + */ +function DimmerDimmable(props) { + const { + blurring, + className, + children, + dimmed, + } = props + + const classes = cx( + useKeyOnly(blurring, 'blurring'), + useKeyOnly(dimmed, 'dimmed'), + 'dimmable', + className, + ) + const rest = getUnhandledProps(DimmerDimmable, props) + const ElementType = getElementType(DimmerDimmable, props) + + return {children} +} + +DimmerDimmable._meta = { + name: 'DimmerDimmable', + type: META.TYPES.MODULE, + parent: 'Dimmer', +} + +DimmerDimmable.propTypes = { + /** An element type to render as (string or function). */ + as: customPropTypes.as, + + /** A dimmable element can blur its contents. */ + blurring: PropTypes.bool, + + /** Primary content. */ + children: PropTypes.node, + + /** Additional classes. */ + className: PropTypes.string, + + /** Controls whether or not the dim is displayed. */ + dimmed: PropTypes.bool, +} + +export default DimmerDimmable diff --git a/src/modules/Dimmer/index.js b/src/modules/Dimmer/index.js new file mode 100644 index 0000000000..9267961719 --- /dev/null +++ b/src/modules/Dimmer/index.js @@ -0,0 +1 @@ +export default from './Dimmer' diff --git a/test/specs/elements/Image/Image-test.js b/test/specs/elements/Image/Image-test.js index 5497743fbd..bec414c24e 100644 --- a/test/specs/elements/Image/Image-test.js +++ b/test/specs/elements/Image/Image-test.js @@ -4,6 +4,7 @@ import React from 'react' import * as common from 'test/specs/commonTests' import Image from 'src/elements/Image/Image' import ImageGroup from 'src/elements/Image/ImageGroup' +import Dimmer from 'src/modules/Dimmer/Dimmer' describe('Image Component', () => { common.isConformant(Image) @@ -28,6 +29,11 @@ describe('Image Component', () => { common.implementsCreateMethod(Image) common.implementsLabelProp(Image) + common.implementsShorthandProp(Image, { + propKey: 'dimmer', + ShorthandComponent: Dimmer, + mapValueToProps: val => ({ content: val }), + }) common.implementsVerticalAlignProp(Image, 'verticalAlign') it('renders an img tag', () => { diff --git a/test/specs/modules/Dimmer/Dimmer-test.js b/test/specs/modules/Dimmer/Dimmer-test.js new file mode 100644 index 0000000000..03711469d0 --- /dev/null +++ b/test/specs/modules/Dimmer/Dimmer-test.js @@ -0,0 +1,117 @@ +import faker from 'faker' +import React from 'react' + +import Portal from 'src/addons/Portal/Portal' +import Dimmer from 'src/modules/Dimmer/Dimmer' +import DimmerDimmable from 'src/modules/Dimmer/DimmerDimmable' +import * as common from 'test/specs/commonTests' +import { sandbox } from 'test/utils' + +describe('Dimmer', () => { + common.isConformant(Dimmer) + common.hasSubComponents(Dimmer[DimmerDimmable]) + common.hasUIClassName(Dimmer) + common.rendersChildren(Dimmer) + + common.propKeyOnlyToClassName(Dimmer, 'active') + common.propKeyOnlyToClassName(Dimmer, 'inverted') + common.propKeyOnlyToClassName(Dimmer, 'simple') + + common.implementsCreateMethod(Dimmer) + + describe('content', () => { + it('renders text', () => { + const text = faker.hacker.phrase() + + shallow() + .should.contain.text(text) + }) + }) + + describe('onClickOutside', () => { + it('omitted when not defined', () => { + const wrapper = shallow({faker.hacker.phrase()}) + const click = () => wrapper.find('div.center').simulate('click') + + expect(click).to.not.throw() + }) + + it('called when Dimmer has not children', () => { + const spy = sandbox.spy() + shallow() + .simulate('click') + + spy.should.have.been.calledOnce() + }) + + it('omitted when click on children', () => { + const spy = sandbox.spy() + const wrapper = mount(
{faker.hacker.phrase()}
) + + wrapper.find('div.center').childAt(0).simulate('click') + spy.should.have.been.callCount(0) + }) + + it('called when click on Dimmer', () => { + const spy = sandbox.spy() + + mount({faker.hacker.phrase()}) + .simulate('click') + spy.should.have.been.calledOnce() + }) + + it('called when click on center', () => { + const spy = sandbox.spy() + const wrapper = mount({faker.hacker.phrase()}) + + wrapper.find('div.center').simulate('click') + spy.should.have.been.calledOnce() + }) + }) + + describe('page', () => { + it('renders a Portal', () => { + shallow() + .type() + .should.equal(Portal) + }) + + describe('active', () => { + beforeEach(() => { + document.body.classList.remove('dimmable', 'dimmed') + }) + + it('when true, Portal is opened dimmer classes are present on body', () => { + const dimmer = mount() + const classes = document.body.classList + + dimmer.find(Portal) + .should.have.prop('open', true) + + classes.contains('dimmable').should.be.true() + classes.contains('dimmed').should.be.true() + }) + + it('when false, Portal is closed dimmer classes are absent on body', () => { + const dimmer = mount() + const classes = document.body.classList + + dimmer.find(Portal) + .should.have.prop('open', false) + + classes.contains('dimmable').should.be.false() + classes.contains('dimmed').should.be.false() + }) + + it('when changed to false, dimmer classes are removed from body', () => { + const dimmer = mount() + const classes = document.body.classList + + dimmer.setProps({ active: false }) + + classes.contains('dimmable').should.be.false() + classes.contains('dimmed').should.be.false() + }) + }) + }) +}) diff --git a/test/specs/modules/Dimmer/DimmerDimmable-test.js b/test/specs/modules/Dimmer/DimmerDimmable-test.js new file mode 100644 index 0000000000..35aa391b15 --- /dev/null +++ b/test/specs/modules/Dimmer/DimmerDimmable-test.js @@ -0,0 +1,10 @@ +import DimmerDimmable from 'src/modules/Dimmer/DimmerDimmable' +import * as common from 'test/specs/commonTests' + +describe('DimmerDimmable', () => { + common.isConformant(DimmerDimmable) + common.rendersChildren(DimmerDimmable) + + common.propKeyOnlyToClassName(DimmerDimmable, 'blurring') + common.propKeyOnlyToClassName(DimmerDimmable, 'dimmed') +})