diff --git a/docs/index.html b/docs/index.html index 9badccb4..d402ded6 100644 --- a/docs/index.html +++ b/docs/index.html @@ -174,6 +174,16 @@

polished

+
  • + retinaImage + + + +
  • + +
  • @@ -216,7 +226,7 @@

    clearFix

    -
    + src/mixins/clearFix.js @@ -300,7 +310,7 @@

    ellipsis

    - + src/mixins/ellipsis.js @@ -387,7 +397,7 @@

    hiDPI

    - + src/mixins/hiDPI.js @@ -477,7 +487,7 @@

    hideText

    - + src/mixins/hideText.js @@ -550,7 +560,7 @@

    selection

    - + src/mixins/selection.js @@ -646,7 +656,7 @@

    size

    - + src/mixins/size.js @@ -736,7 +746,7 @@

    timingFunctions

    - + src/mixins/timingFunctions.js @@ -816,7 +826,7 @@

    wordWrap

    - + src/mixins/wordWrap.js @@ -915,7 +925,7 @@

    stripUnit

    - + src/helpers/stripUnit.js @@ -1000,7 +1010,7 @@

    em

    - + src/helpers/em.js @@ -1090,7 +1100,7 @@

    modularScale

    - + src/helpers/modularScale.js @@ -1190,7 +1200,7 @@

    rem

    - + src/helpers/rem.js @@ -1280,7 +1290,7 @@

    placeholder

    - + src/mixins/placeholder.js @@ -1367,6 +1377,126 @@

    + + + + + +
    + + +
    +

    + retinaImage +

    + + + src/mixins/retinaImage.js + + +
    + + +

    The retina-image mixin is a helper to generate a retina background image and non-retina +background image. The retina background image will output to a HiDPI media query. The mixin uses +a _2x.png filename suffix by default.

    + + +
    retinaImage(filename: string, backgroundSize: string, extension: [string], retinaFilename: string, retinaSuffix: [string])
    + + + + + + + + + + +
    Parameters
    +
    + +
    +
    + filename (string) +
    + +
    + +
    +
    + backgroundSize (string) +
    + +
    + +
    +
    + extension ([string] + (default 'png') + ) +
    + +
    + +
    +
    + retinaFilename (string) +
    + +
    + +
    +
    + retinaSuffix ([string] + (default '_2x') + ) +
    + +
    + +
    + + + + + + + + + +
    Example
    + + +
    // Styles as object usage
    +const styles = {
    + ...retinaImage('my-img')
    +}
    +
    +// styled-components usage
    +const div = styled.div`
    +  ${retinaImage('my-img')}
    +`
    +
    +// CSS as JS Output
    +div {
    +  backgroundImage: 'url(my-img.png)',
    +  '@media only screen and (-webkit-min-device-pixel-ratio: 1.3),
    +   only screen and (min--moz-device-pixel-ratio: 1.3),
    +   only screen and (-o-min-device-pixel-ratio: 1.3/1),
    +   only screen and (min-resolution: 144dpi),
    +   only screen and (min-resolution: 1.5dppx)': {
    +    backgroundImage: 'url(my-img_2x.png)',
    +  }
    +}
    + + + + + + + +
    @@ -1380,7 +1510,7 @@

    animation

    - + src/shorthands/animation.js diff --git a/src/index.js b/src/index.js index 3f5b56c0..114df926 100644 --- a/src/index.js +++ b/src/index.js @@ -11,6 +11,7 @@ import ellipsis from './mixins/ellipsis' import hideText from './mixins/hideText' import hiDPI from './mixins/hiDPI' import placeholder from './mixins/placeholder' +import retinaImage from './mixins/retinaImage' import selection from './mixins/selection' import size from './mixins/size' import timingFunctions from './mixins/timingFunctions' @@ -29,6 +30,7 @@ const polished = { hiDPI, placeholder, rem, + retinaImage, selection, size, stripUnit, @@ -48,6 +50,7 @@ export { hiDPI, placeholder, rem, + retinaImage, selection, size, stripUnit, diff --git a/src/mixins/retinaImage.js b/src/mixins/retinaImage.js new file mode 100644 index 00000000..66ef5851 --- /dev/null +++ b/src/mixins/retinaImage.js @@ -0,0 +1,50 @@ +// @flow + +import hiDPI from './hiDPI' + +/** + * The retina-image mixin is a helper to generate a retina background image and non-retina + * background image. The retina background image will output to a HiDPI media query. The mixin uses + * a _2x.png filename suffix by default. + * + * @example + * // Styles as object usage + * const styles = { + * ...retinaImage('my-img') + * } + * + * // styled-components usage + * const div = styled.div` + * ${retinaImage('my-img')} + * ` + * + * // CSS as JS Output + * div { + * backgroundImage: 'url(my-img.png)', + * '@media only screen and (-webkit-min-device-pixel-ratio: 1.3), + * only screen and (min--moz-device-pixel-ratio: 1.3), + * only screen and (-o-min-device-pixel-ratio: 1.3/1), + * only screen and (min-resolution: 144dpi), + * only screen and (min-resolution: 1.5dppx)': { + * backgroundImage: 'url(my-img_2x.png)', + * } + * } + */ +function retinaImage(filename: string, backgroundSize?: string, extension?: string = 'png', retinaFilename?: string, retinaSuffix?: string = '_2x') { + if (!filename) { + throw new Error('Please supply a filename to retinaImage() as the first argument.') + } + // Replace the dot at the beginning of the passed extension if one exists + const ext = extension.replace(/^\./, '') + const rFilename = retinaFilename ? `${retinaFilename}.${ext}` : `${filename}${retinaSuffix}.${ext}` + + return { + backgroundImage: `url(${filename}.${ext})`, + [hiDPI()]: { + backgroundImage: `url(${rFilename})`, + backgroundSize, + }, + } +} + +export default retinaImage diff --git a/src/mixins/test/__snapshots__/retinaImage.test.js.snap b/src/mixins/test/__snapshots__/retinaImage.test.js.snap new file mode 100644 index 00000000..86a6511f --- /dev/null +++ b/src/mixins/test/__snapshots__/retinaImage.test.js.snap @@ -0,0 +1,95 @@ +exports[`retinaImage should allow passing in a separate filename for the retina version 1`] = ` +Object { + " + @media only screen and (-webkit-min-device-pixel-ratio: 1.3), + only screen and (min--moz-device-pixel-ratio: 1.3), + only screen and (-o-min-device-pixel-ratio: 1.3/1), + only screen and (min-resolution: 125dpi), + only screen and (min-resolution: 1.3dppx) + ": Object { + "backgroundImage": "url(retina_img.png)", + "backgroundSize": undefined, + }, + "backgroundImage": "url(img.png)", +} +`; + +exports[`retinaImage should allow passing in a separate suffix for the retina version 1`] = ` +Object { + " + @media only screen and (-webkit-min-device-pixel-ratio: 1.3), + only screen and (min--moz-device-pixel-ratio: 1.3), + only screen and (-o-min-device-pixel-ratio: 1.3/1), + only screen and (min-resolution: 125dpi), + only screen and (min-resolution: 1.3dppx) + ": Object { + "backgroundImage": "url(img_5x.png)", + "backgroundSize": undefined, + }, + "backgroundImage": "url(img.png)", +} +`; + +exports[`retinaImage should allow passing in an extension with a dot 1`] = ` +Object { + " + @media only screen and (-webkit-min-device-pixel-ratio: 1.3), + only screen and (min--moz-device-pixel-ratio: 1.3), + only screen and (-o-min-device-pixel-ratio: 1.3/1), + only screen and (min-resolution: 125dpi), + only screen and (min-resolution: 1.3dppx) + ": Object { + "backgroundImage": "url(img_2x.jpg)", + "backgroundSize": undefined, + }, + "backgroundImage": "url(img.jpg)", +} +`; + +exports[`retinaImage should set the background-size if one is passed in 1`] = ` +Object { + " + @media only screen and (-webkit-min-device-pixel-ratio: 1.3), + only screen and (min--moz-device-pixel-ratio: 1.3), + only screen and (-o-min-device-pixel-ratio: 1.3/1), + only screen and (min-resolution: 125dpi), + only screen and (min-resolution: 1.3dppx) + ": Object { + "backgroundImage": "url(img_2x.png)", + "backgroundSize": "cover", + }, + "backgroundImage": "url(img.png)", +} +`; + +exports[`retinaImage should set the extension if one is passed in 1`] = ` +Object { + " + @media only screen and (-webkit-min-device-pixel-ratio: 1.3), + only screen and (min--moz-device-pixel-ratio: 1.3), + only screen and (-o-min-device-pixel-ratio: 1.3/1), + only screen and (min-resolution: 125dpi), + only screen and (min-resolution: 1.3dppx) + ": Object { + "backgroundImage": "url(img_2x.jpg)", + "backgroundSize": undefined, + }, + "backgroundImage": "url(img.jpg)", +} +`; + +exports[`retinaImage should use _2x and png as the default suffix and extension, respectively 1`] = ` +Object { + " + @media only screen and (-webkit-min-device-pixel-ratio: 1.3), + only screen and (min--moz-device-pixel-ratio: 1.3), + only screen and (-o-min-device-pixel-ratio: 1.3/1), + only screen and (min-resolution: 125dpi), + only screen and (min-resolution: 1.3dppx) + ": Object { + "backgroundImage": "url(img_2x.png)", + "backgroundSize": undefined, + }, + "backgroundImage": "url(img.png)", +} +`; diff --git a/src/mixins/test/retinaImage.test.js b/src/mixins/test/retinaImage.test.js new file mode 100644 index 00000000..3be777f3 --- /dev/null +++ b/src/mixins/test/retinaImage.test.js @@ -0,0 +1,31 @@ +import retinaImage from '../retinaImage' + +describe('retinaImage', function() { + it('should throw an error if no filename is passed', function() { + expect(() => ({ ...retinaImage() })).toThrow() + }) + + it('should use _2x and png as the default suffix and extension, respectively', function() { + expect({ ...retinaImage('img') }).toMatchSnapshot() + }) + + it('should set the background-size if one is passed in', function() { + expect({ ...retinaImage('img', 'cover') }).toMatchSnapshot() + }) + + it('should set the extension if one is passed in', function() { + expect({ ...retinaImage('img', undefined, 'jpg') }).toMatchSnapshot() + }) + + it('should allow passing in an extension with a dot', function() { + expect({ ...retinaImage('img', undefined, '.jpg') }).toMatchSnapshot() + }) + + it('should allow passing in a separate filename for the retina version', function() { + expect({ ...retinaImage('img', undefined, undefined, 'retina_img') }).toMatchSnapshot() + }) + + it('should allow passing in a separate suffix for the retina version', function() { + expect({ ...retinaImage('img', undefined, undefined, undefined, '_5x') }).toMatchSnapshot() + }) +})