diff --git a/docs/app/Examples/elements/Image/Usage/ImageExampleImageProps.js b/docs/app/Examples/elements/Image/Usage/ImageExampleImageProps.js new file mode 100644 index 0000000000..7da3c4b3ba --- /dev/null +++ b/docs/app/Examples/elements/Image/Usage/ImageExampleImageProps.js @@ -0,0 +1,13 @@ +import React from 'react' +import { Image } from 'semantic-ui-react' + +const ImageExampleImageProps = () => ( + An example alt +) + +export default ImageExampleImageProps diff --git a/docs/app/Examples/elements/Image/Usage/ImageExampleWrappedImageProps.js b/docs/app/Examples/elements/Image/Usage/ImageExampleWrappedImageProps.js new file mode 100644 index 0000000000..ef6d07a93a --- /dev/null +++ b/docs/app/Examples/elements/Image/Usage/ImageExampleWrappedImageProps.js @@ -0,0 +1,14 @@ +import React from 'react' +import { Image } from 'semantic-ui-react' + +const ImageExampleWrappedImageProps = () => ( + An example alt +) + +export default ImageExampleWrappedImageProps diff --git a/docs/app/Examples/elements/Image/Usage/index.js b/docs/app/Examples/elements/Image/Usage/index.js index a328b48891..94f0e448ab 100644 --- a/docs/app/Examples/elements/Image/Usage/index.js +++ b/docs/app/Examples/elements/Image/Usage/index.js @@ -1,4 +1,5 @@ import React from 'react' + import ComponentExample from 'docs/app/Components/ComponentDoc/ComponentExample' import ExampleSection from 'docs/app/Components/ComponentDoc/ExampleSection' @@ -9,6 +10,15 @@ const ImageUsageExamples = () => ( description='An image can render children.' examplePath='elements/Image/Usage/ImageExampleChildren' /> + An image correctly handles props of an HTML img.} + examplePath='elements/Image/Usage/ImageExampleImageProps' + /> + ) diff --git a/src/elements/Image/Image.d.ts b/src/elements/Image/Image.d.ts index 85af9ced07..c88046891f 100644 --- a/src/elements/Image/Image.d.ts +++ b/src/elements/Image/Image.d.ts @@ -18,9 +18,6 @@ export interface ImageProps { /** An element type to render as (string or function). */ as?: any; - /** Alternate text for the image specified. */ - alt?: string; - /** An image may be formatted to appear inline with text as an avatar. */ avatar?: boolean; @@ -54,9 +51,6 @@ export interface ImageProps { /** An image can take up the width of its container. */ fluid?: boolean; - /** The img element height attribute. */ - height?: string | number; - /** An image can be hidden. */ hidden?: boolean; @@ -76,10 +70,7 @@ export interface ImageProps { size?: SemanticSIZES; /** An image can specify that it needs an additional spacing to separate it from nearby content. */ - spaced?: boolean|'left'|'right'; - - /** Specifies the URL of the image. */ - src?: string; + spaced?: boolean | 'left' | 'right'; /** Whether or not to add the ui className. */ ui?: boolean; @@ -87,9 +78,6 @@ export interface ImageProps { /** An image can specify its vertical alignment. */ verticalAlign?: SemanticVERTICALALIGNMENTS; - /** The img element width attribute. */ - width?: string | number; - /** An image can render wrapped in a `div.ui.image` as alternative HTML markup. */ wrapped?: boolean; } diff --git a/src/elements/Image/Image.js b/src/elements/Image/Image.js index 686a093e20..8611cd25c6 100644 --- a/src/elements/Image/Image.js +++ b/src/elements/Image/Image.js @@ -10,6 +10,7 @@ import { getElementType, getUnhandledProps, META, + partitionHTMLProps, SUI, useKeyOnly, useKeyOrValueAndKey, @@ -18,16 +19,16 @@ import { } from '../../lib' import Dimmer from '../../modules/Dimmer' import Label from '../Label/Label' - import ImageGroup from './ImageGroup' +const imageProps = ['alt', 'height', 'src', 'srcSet', 'width'] + /** * An image is a graphic representation of something. * @see Icon */ function Image(props) { const { - alt, avatar, bordered, centered, @@ -39,7 +40,6 @@ function Image(props) { disabled, floated, fluid, - height, hidden, href, inline, @@ -47,9 +47,7 @@ function Image(props) { rounded, size, spaced, - src, verticalAlign, - width, wrapped, ui, } = props @@ -73,6 +71,7 @@ function Image(props) { className, ) const rest = getUnhandledProps(Image, props) + const [imgTagProps, rootProps] = partitionHTMLProps(rest, { htmlProps: imageProps }) const ElementType = getElementType(Image, props, () => { if (!_.isNil(dimmer) || !_.isNil(label) || !_.isNil(wrapped) || !childrenUtils.isNil(children)) return 'div' }) @@ -84,13 +83,9 @@ function Image(props) { return {content} } - const rootProps = { ...rest, className: classes } - const imgTagProps = { alt, src, height, width } - - if (ElementType === 'img') return - + if (ElementType === 'img') return return ( - + {Dimmer.create(dimmer)} {Label.create(label)} @@ -109,9 +104,6 @@ Image.propTypes = { /** An element type to render as (string or function). */ as: customPropTypes.as, - /** Alternate text for the image specified. */ - alt: PropTypes.string, - /** An image may be formatted to appear inline with text as an avatar. */ avatar: PropTypes.bool, @@ -148,12 +140,6 @@ Image.propTypes = { customPropTypes.disallow(['size']), ]), - /** The img element height attribute. */ - height: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.string, - ]), - /** An image can be hidden. */ hidden: PropTypes.bool, @@ -178,21 +164,12 @@ Image.propTypes = { PropTypes.oneOf(['left', 'right']), ]), - /** Specifies the URL of the image. */ - src: PropTypes.string, - /** Whether or not to add the ui className. */ ui: PropTypes.bool, /** An image can specify its vertical alignment. */ verticalAlign: PropTypes.oneOf(SUI.VERTICAL_ALIGNMENTS), - /** The img element width attribute. */ - width: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.number, - ]), - /** An image can render wrapped in a `div.ui.image` as alternative HTML markup. */ wrapped: PropTypes.bool, } diff --git a/src/elements/Input/Input.js b/src/elements/Input/Input.js index b71b71dbaf..e4c5a4cb1c 100644 --- a/src/elements/Input/Input.js +++ b/src/elements/Input/Input.js @@ -11,7 +11,7 @@ import { getElementType, getUnhandledProps, META, - partitionHTMLInputProps, + partitionHTMLProps, SUI, useKeyOnly, useValueAndKey, @@ -154,7 +154,7 @@ class Input extends Component { const tabIndex = this.computeTabIndex() const unhandled = getUnhandledProps(Input, this.props) - const [htmlInputProps, rest] = partitionHTMLInputProps(unhandled) + const [htmlInputProps, rest] = partitionHTMLProps(unhandled) return [{ ...htmlInputProps, diff --git a/src/lib/htmlInputPropsUtils.js b/src/lib/htmlPropsUtils.js similarity index 96% rename from src/lib/htmlInputPropsUtils.js rename to src/lib/htmlPropsUtils.js index c5f07ce06a..ad86c86ab4 100644 --- a/src/lib/htmlInputPropsUtils.js +++ b/src/lib/htmlPropsUtils.js @@ -43,7 +43,7 @@ export const htmlInputProps = [...htmlInputAttrs, ...htmlInputEvents] * @param {boolean} [options.includeAria] Includes all input props that starts with "aria-" * @returns {[{}, {}]} An array of objects */ -export const partitionHTMLInputProps = (props, options = {}) => { +export const partitionHTMLProps = (props, options = {}) => { const { htmlProps = htmlInputProps, includeAria = true, diff --git a/src/lib/index.js b/src/lib/index.js index 5601f842e3..f6f506a619 100644 --- a/src/lib/index.js +++ b/src/lib/index.js @@ -29,8 +29,8 @@ export { htmlInputAttrs, htmlInputEvents, htmlInputProps, - partitionHTMLInputProps, -} from './htmlInputPropsUtils' + partitionHTMLProps, +} from './htmlPropsUtils' export { default as isBrowser } from './isBrowser' export { default as leven } from './leven' diff --git a/src/modules/Checkbox/Checkbox.js b/src/modules/Checkbox/Checkbox.js index a303960e7c..2d37e214b2 100644 --- a/src/modules/Checkbox/Checkbox.js +++ b/src/modules/Checkbox/Checkbox.js @@ -12,7 +12,7 @@ import { htmlInputAttrs, makeDebugger, META, - partitionHTMLInputProps, + partitionHTMLProps, useKeyOnly, } from '../../lib' @@ -217,7 +217,7 @@ export default class Checkbox extends Component { ) const unhandled = getUnhandledProps(Checkbox, this.props) const ElementType = getElementType(Checkbox, this.props) - const [htmlInputProps, rest] = partitionHTMLInputProps(unhandled, { htmlProps: htmlInputAttrs }) + const [htmlInputProps, rest] = partitionHTMLProps(unhandled, { htmlProps: htmlInputAttrs }) const id = _.get(htmlInputProps, 'id') return ( diff --git a/src/modules/Search/Search.js b/src/modules/Search/Search.js index 5c2f3de66e..d7f5fc1420 100644 --- a/src/modules/Search/Search.js +++ b/src/modules/Search/Search.js @@ -15,7 +15,7 @@ import { makeDebugger, META, objectDiff, - partitionHTMLInputProps, + partitionHTMLProps, shallowEqual, SUI, useKeyOnly, @@ -643,7 +643,7 @@ export default class Search extends Component { ) const unhandled = getUnhandledProps(Search, this.props) const ElementType = getElementType(Search, this.props) - const [htmlInputProps, rest] = partitionHTMLInputProps(unhandled, { + const [htmlInputProps, rest] = partitionHTMLProps(unhandled, { htmlProps: htmlInputAttrs, }) diff --git a/test/specs/elements/Image/Image-test.js b/test/specs/elements/Image/Image-test.js index 14c2cfc200..163bb76ce9 100644 --- a/test/specs/elements/Image/Image-test.js +++ b/test/specs/elements/Image/Image-test.js @@ -38,10 +38,12 @@ describe('Image', () => { common.propValueOnlyToClassName(Image, 'size', SUI.SIZES) - it('renders an img tag', () => { - shallow() - .type() - .should.equal('img') + describe('as', () => { + it('renders an img tag', () => { + shallow() + .type() + .should.equal('img') + }) }) describe('href', () => { @@ -52,6 +54,23 @@ describe('Image', () => { }) }) + describe('image props', () => { + _.forEach(['alt', 'height', 'src', 'srcSet', 'width'], (propName) => { + it(`keeps "${propName}" on root element by default`, () => { + const wrapper = shallow() + + wrapper.should.have.tagName('img') + wrapper.should.have.prop(propName, 'foo') + }) + + it(`passes "${propName}" to the img tag when wrapped`, () => { + shallow() + .find('img') + .should.have.prop(propName, 'foo') + }) + }) + }) + describe('ui', () => { it('is true by default', () => { Image.defaultProps.should.have.any.keys('ui') @@ -68,14 +87,10 @@ describe('Image', () => { }) describe('wrapped', () => { - it('applies all img attribute props to the img tag', () => { - const props = { src: 'http://g.co', alt: 'alt text', width: 10, height: '10' } - const img = shallow() - .find('img') - - _.each(props, (val, key) => { - img.should.have.prop(key, val) - }) + it('renders an div tag when true', () => { + shallow() + .type() + .should.equal('div') }) }) }) diff --git a/test/specs/lib/htmlInputPropsUtils-test.js b/test/specs/lib/htmlInputPropsUtils-test.js index 82e93b9826..f60d11e2fe 100644 --- a/test/specs/lib/htmlInputPropsUtils-test.js +++ b/test/specs/lib/htmlInputPropsUtils-test.js @@ -1,4 +1,4 @@ -import { partitionHTMLInputProps } from 'src/lib/htmlInputPropsUtils' +import { partitionHTMLProps } from 'src/lib/htmlPropsUtils' const props = { autoFocus: false, @@ -7,15 +7,15 @@ const props = { required: true, } -describe('partitionHTMLInputProps', () => { +describe('partitionHTMLProps', () => { it('should return two arrays with objects', () => { - partitionHTMLInputProps(props).should.have.lengthOf(2) + partitionHTMLProps(props).should.have.lengthOf(2) }) it('should split props by definition', () => { - const [htmlInputProps, rest] = partitionHTMLInputProps(props) + const [htmlProps, rest] = partitionHTMLProps(props) - htmlInputProps.should.deep.equal({ + htmlProps.should.deep.equal({ autoFocus: false, placeholder: 'baz', required: true, @@ -24,24 +24,24 @@ describe('partitionHTMLInputProps', () => { }) it('should split props by own definition', () => { - const [htmlInputProps, rest] = partitionHTMLInputProps(props, { + const [htmlProps, rest] = partitionHTMLProps(props, { htmlProps: ['placeholder', 'required'], }) - htmlInputProps.should.deep.equal({ placeholder: 'baz', required: true }) + htmlProps.should.deep.equal({ placeholder: 'baz', required: true }) rest.should.deep.equal({ autoFocus: false, className: 'foo' }) }) describe('aria', () => { it('split aria props by default to htmlProps', () => { - const [htmlInputProps, rest] = partitionHTMLInputProps({ + const [htmlProps, rest] = partitionHTMLProps({ 'aria-atomic': false, 'aria-busy': true, className: 'foo', role: 'bar', }) - htmlInputProps.should.deep.equal({ + htmlProps.should.deep.equal({ 'aria-atomic': false, 'aria-busy': true, role: 'bar', @@ -50,14 +50,14 @@ describe('partitionHTMLInputProps', () => { }) it('split aria props by default to rest when disabled', () => { - const [htmlInputProps, rest] = partitionHTMLInputProps({ + const [htmlProps, rest] = partitionHTMLProps({ 'aria-atomic': false, 'aria-busy': true, className: 'foo', role: 'bar', }, { includeAria: false }) - htmlInputProps.should.deep.equal({}) + htmlProps.should.deep.equal({}) rest.should.deep.equal({ 'aria-atomic': false, 'aria-busy': true,