From 3a151cca56672de1c7809cc83847e3c3e1c05e58 Mon Sep 17 00:00:00 2001 From: Mikael Korpela Date: Thu, 29 Nov 2018 15:55:25 +0200 Subject: [PATCH] Tiled Gallery block: rewrite (#27458) --- .../extensions/presets/jetpack/editor.js | 1 - .../extensions/tiled-gallery/constants.js | 34 ++ .../extensions/tiled-gallery/edit.jsx | 252 ++++++++---- .../extensions/tiled-gallery/editor.js | 223 +++++++---- .../extensions/tiled-gallery/editor.scss | 150 +++++++ .../extensions/tiled-gallery/gallery-grid.jsx | 131 +++++++ .../tiled-gallery/gallery-image.jsx | 168 ++++++++ .../extensions/tiled-gallery/item.jsx | 103 ----- .../tiled-gallery/layout-square.jsx | 165 -------- .../extensions/tiled-gallery/layouts.js | 131 +++++++ .../extensions/tiled-gallery/save.jsx | 81 +++- .../extensions/tiled-gallery/variables.scss | 8 + .../extensions/tiled-gallery/view.js | 111 ++++++ .../extensions/tiled-gallery/view.scss | 144 ++++--- npm-shrinkwrap.json | 369 ++++++++++++------ package.json | 3 + 16 files changed, 1485 insertions(+), 589 deletions(-) create mode 100644 client/gutenberg/extensions/tiled-gallery/constants.js create mode 100644 client/gutenberg/extensions/tiled-gallery/editor.scss create mode 100644 client/gutenberg/extensions/tiled-gallery/gallery-grid.jsx create mode 100644 client/gutenberg/extensions/tiled-gallery/gallery-image.jsx delete mode 100644 client/gutenberg/extensions/tiled-gallery/item.jsx delete mode 100644 client/gutenberg/extensions/tiled-gallery/layout-square.jsx create mode 100644 client/gutenberg/extensions/tiled-gallery/layouts.js create mode 100644 client/gutenberg/extensions/tiled-gallery/variables.scss diff --git a/client/gutenberg/extensions/presets/jetpack/editor.js b/client/gutenberg/extensions/presets/jetpack/editor.js index 6d85923809fef..e072e721ea5fa 100644 --- a/client/gutenberg/extensions/presets/jetpack/editor.js +++ b/client/gutenberg/extensions/presets/jetpack/editor.js @@ -10,4 +10,3 @@ import 'gutenberg/extensions/markdown/editor'; import 'gutenberg/extensions/publicize/editor'; import 'gutenberg/extensions/related-posts/editor'; import 'gutenberg/extensions/simple-payments/editor'; -import 'gutenberg/extensions/tiled-gallery/editor'; diff --git a/client/gutenberg/extensions/tiled-gallery/constants.js b/client/gutenberg/extensions/tiled-gallery/constants.js new file mode 100644 index 0000000000000..aa814a58f8ac9 --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/constants.js @@ -0,0 +1,34 @@ +/** @format */ + +/** + * Internal Dependencies + */ +import { _x } from 'gutenberg/extensions/presets/jetpack/utils/i18n'; + +export const ALLOWED_MEDIA_TYPES = [ 'image' ]; +export const DEFAULT_COLUMNS = 3; +export const DEFAULT_GALLERY_WIDTH = 580; +export const DEFAULT_LAYOUT = 'rectangular'; +export const LAYOUT_STYLES = [ + { + label: _x( 'Tiled mosaic', 'Tiled gallery layout' ), + name: 'rectangular', + isDefault: true, + }, + { + label: _x( 'Tiled columns', 'Tiled gallery layout' ), + name: 'columns', + }, + { + label: _x( 'Square tiles', 'Tiled gallery layout' ), + name: 'square', + }, + { + label: _x( 'Circles', 'Tiled gallery layout' ), + name: 'circle', + }, +]; +export const LAYOUTS = [ 'rectangular', 'columns', 'square', 'circle' ]; +export const MAX_COLUMNS = 20; +export const RESIZE_RATE_IN_MS = 200; +export const TILE_MARGIN = 2; diff --git a/client/gutenberg/extensions/tiled-gallery/edit.jsx b/client/gutenberg/extensions/tiled-gallery/edit.jsx index 93a514b26367e..d0ceddedeb0de 100644 --- a/client/gutenberg/extensions/tiled-gallery/edit.jsx +++ b/client/gutenberg/extensions/tiled-gallery/edit.jsx @@ -3,44 +3,53 @@ /** * External Dependencies */ -import { pick } from 'lodash'; - -/** - * WordPress dependencies - */ +import { filter, pick } from 'lodash'; import { Component, Fragment } from '@wordpress/element'; -import { - BlockControls, - InspectorControls, - MediaPlaceholder, - MediaUpload, - mediaUpload, -} from '@wordpress/editor'; import { DropZone, + FormFileUpload, IconButton, PanelBody, RangeControl, SelectControl, + ToggleControl, Toolbar, withNotices, } from '@wordpress/components'; +import { + BlockControls, + InspectorControls, + MediaPlaceholder, + mediaUpload, + MediaUpload, +} from '@wordpress/editor'; +import { create } from '@wordpress/rich-text'; /** * Internal dependencies */ import { __ } from 'gutenberg/extensions/presets/jetpack/utils/i18n'; -import TiledGallerySave from './save.jsx'; +import { ALLOWED_MEDIA_TYPES, MAX_COLUMNS, DEFAULT_COLUMNS } from './constants'; +import GalleryGrid from './gallery-grid'; +import GalleryImage from './gallery-image'; +import { getActiveStyleName } from './layouts'; -/** - * Module variables - */ -const MAX_COLUMNS = 8; -const linkOptions = [ - { value: 'attachment', label: __( 'Attachment Page' ) }, - { value: 'media', label: __( 'Media File' ) }, - { value: 'none', label: __( 'None' ) }, -]; +export function defaultColumnsNumber( attributes ) { + return Math.min( DEFAULT_COLUMNS, attributes.images.length ); +} + +const pickRelevantMediaFiles = image => { + let { caption } = image; + + if ( typeof caption !== 'object' ) { + caption = create( { html: caption } ); + } + + return { + ...pick( image, [ 'alt', 'id', 'link', 'url' ] ), + caption, + }; +}; class TiledGalleryEdit extends Component { constructor() { @@ -48,13 +57,18 @@ class TiledGalleryEdit extends Component { this.onSelectImage = this.onSelectImage.bind( this ); this.onSelectImages = this.onSelectImages.bind( this ); + this.setLayout = this.setLayout.bind( this ); this.setLinkTo = this.setLinkTo.bind( this ); this.setColumnsNumber = this.setColumnsNumber.bind( this ); + this.toggleImageCrop = this.toggleImageCrop.bind( this ); + this.onRemoveImage = this.onRemoveImage.bind( this ); this.setImageAttributes = this.setImageAttributes.bind( this ); this.addFiles = this.addFiles.bind( this ); + this.uploadFromFiles = this.uploadFromFiles.bind( this ); this.state = { selectedImage: null, + layout: getActiveStyleName( arguments[ 0 ].className ), }; } @@ -68,18 +82,42 @@ class TiledGalleryEdit extends Component { }; } + onRemoveImage( index ) { + return () => { + const images = filter( this.props.attributes.images, ( img, i ) => index !== i ); + const { columns } = this.props.attributes; + this.setState( { selectedImage: null } ); + this.props.setAttributes( { + images, + columns: columns ? Math.min( images.length, columns ) : columns, + } ); + }; + } + onSelectImages( images ) { this.props.setAttributes( { - images: images.map( image => pick( image, [ 'alt', 'caption', 'id', 'url', 'link' ] ) ), + images: images.map( image => pickRelevantMediaFiles( image ) ), } ); } - setLinkTo( value ) { - this.props.setAttributes( { linkTo: value } ); + setLayout( layout ) { + this.setState( { layout } ); + } + + setLinkTo( linkTo ) { + this.props.setAttributes( { linkTo } ); + } + + setColumnsNumber( columns ) { + this.props.setAttributes( { columns } ); } - setColumnsNumber( value ) { - this.props.setAttributes( { columns: value } ); + toggleImageCrop() { + this.props.setAttributes( { imageCrop: ! this.props.attributes.imageCrop } ); + } + + getImageCropHelp( checked ) { + return checked ? __( 'Thumbnails are cropped to align.' ) : __( 'Thumbnails are not cropped.' ); } setImageAttributes( index, attributes ) { @@ -102,15 +140,20 @@ class TiledGalleryEdit extends Component { } ); } + uploadFromFiles( event ) { + this.addFiles( event.target.files ); + } + addFiles( files ) { const currentImages = this.props.attributes.images || []; const { noticeOperations, setAttributes } = this.props; mediaUpload( { - allowedType: 'image', + allowedTypes: ALLOWED_MEDIA_TYPES, filesList: files, onFileChange: images => { + const imagesNormalized = images.map( image => pickRelevantMediaFiles( image ) ); setAttributes( { - images: currentImages.concat( images ), + images: currentImages.concat( imagesNormalized ), } ); }, onError: noticeOperations.createErrorNotice, @@ -120,28 +163,46 @@ class TiledGalleryEdit extends Component { componentDidUpdate( prevProps ) { // Deselect images when deselecting the block if ( ! this.props.isSelected && prevProps.isSelected ) { - // @TODO refactor - // eslint-disable-next-line react/no-did-update-set-state + //eslint-disable-next-line this.setState( { selectedImage: null, captionSelected: false, } ); } + + if ( this.props.className !== prevProps.className ) { + const activeStyleName = getActiveStyleName( this.props.className ); + + if ( activeStyleName !== this.state.layout ) { + this.setLayout( activeStyleName ); + } + } } render() { - const { attributes, className, isSelected, noticeOperations, noticeUI } = this.props; - const { images, columns, linkTo } = attributes; + const { selectedImage } = this.state; - const dropZone = ; + const { attributes, isSelected, className, noticeOperations, noticeUI } = this.props; - const controls = isSelected && ( - + const { + images, + columns = defaultColumnsNumber( attributes ), + align, + imageCrop, + linkTo, + } = attributes; + + const layoutsSupportingColumns = [ 'square', 'circle' ]; + + const dropZone = ; + + const controls = ( + { !! images.length && ( img.id ) } @@ -163,65 +224,102 @@ class TiledGalleryEdit extends Component { return ( { controls } - { noticeUI } ); } - // To avoid users accidentally navigating out of Gutenberg by clicking an image, we disable linkTo in the editor view here by forcing 'none'. - const imageTiles = ( - - ); + const renderGalleryImage = index => { + if ( ! images[ index ] ) { + return null; + } + + const image = images[ index ]; + + return ( + this.setImageAttributes( index, attrs ) } + url={ image.url } + /> + ); + }; return ( { controls } - { isSelected && ( - - - { images.length > 1 && ( - - ) } - + + { images.length > 1 && ( + - - - ) } - { dropZone } + ) } + + + + { noticeUI } - { imageTiles } + { dropZone } + + { isSelected && ( + + { __( 'Upload an image' ) } + + ) } + ); } diff --git a/client/gutenberg/extensions/tiled-gallery/editor.js b/client/gutenberg/extensions/tiled-gallery/editor.js index d34abaa62689a..19f38ba769f1d 100644 --- a/client/gutenberg/extensions/tiled-gallery/editor.js +++ b/client/gutenberg/extensions/tiled-gallery/editor.js @@ -1,87 +1,161 @@ /** @format */ /** - * WordPress dependencies + * External dependencies */ import { createBlock, registerBlockType } from '@wordpress/blocks'; +import { filter } from 'lodash'; +import { Rect, SVG } from '@wordpress/components'; /** * Internal dependencies */ -import TiledGalleryEdit from './edit.jsx'; -import TiledGallerySave from './save.jsx'; -import { __ } from 'gutenberg/extensions/presets/jetpack/utils/i18n'; +import { __, _x } from 'gutenberg/extensions/presets/jetpack/utils/i18n'; +import { default as edit } from './edit'; +import { default as save } from './save'; +import { DEFAULT_COLUMNS, DEFAULT_LAYOUT, LAYOUT_STYLES, LAYOUTS } from './constants'; -const blockType = 'jetpack/tiled-gallery'; +/** + * Style dependencies + */ +import './editor.scss'; -const blockSettings = { - title: __( 'Tiled Gallery' ), - description: __( 'Display multiple images in an elegantly organized tiled layout.' ), - icon: 'format-gallery', - category: 'jetpack', - keywords: [ __( 'images' ), __( 'photos' ) ], - attributes: { - columns: { - type: 'integer', - default: 3, - }, - linkTo: { - type: 'string', - default: 'none', - }, - images: { - type: 'array', - default: [], - source: 'query', - selector: '.tiled-gallery-item', - query: { - width: { - source: 'attribute', - selector: 'img', - attribute: 'data-original-width', - }, - height: { - source: 'attribute', - selector: 'img', - attribute: 'data-original-height', - }, - url: { - source: 'attribute', - selector: 'img', - attribute: 'src', - }, - link: { - source: 'attribute', - selector: 'img', - attribute: 'data-link', - }, - alt: { - source: 'attribute', - selector: 'img', - attribute: 'alt', - default: '', - }, - id: { - source: 'attribute', - selector: 'img', - attribute: 'data-id', - }, - caption: { - type: 'array', - source: 'children', - selector: 'figcaption', - }, +const blockAttributes = { + images: { + type: 'array', + default: [], + source: 'query', + selector: '.wp-block-jetpack-tiled-gallery .tiled-gallery__item', + query: { + url: { + source: 'attribute', + selector: 'img', + attribute: 'src', + }, + link: { + source: 'attribute', + selector: 'img', + attribute: 'data-link', + }, + alt: { + source: 'attribute', + selector: 'img', + attribute: 'alt', + default: '', + }, + id: { + source: 'attribute', + selector: 'img', + attribute: 'data-id', + }, + caption: { + source: 'html', + selector: 'figcaption', }, }, }, + columns: { + type: 'number', + default: DEFAULT_COLUMNS, + }, + imageCrop: { + type: 'boolean', + default: true, + }, + linkTo: { + type: 'string', + default: 'none', + }, +}; +export const name = 'jetpack/tiled-gallery'; + +export const settings = { + attributes: blockAttributes, + category: 'jetpack', + description: __( 'Display multiple images in an elegantly organized tiled layout.' ), + icon: ( + + + + + + + + ), + keywords: [ + _x( 'images', 'block search term' ), + _x( 'photos', 'block search term' ), + _x( 'masonry', 'block search term' ), + ], + styles: LAYOUT_STYLES, + supports: { + align: true, + }, + title: __( 'Tiled gallery' ), transforms: { from: [ { type: 'block', blocks: [ 'core/gallery' ], - transform: function( content ) { - return createBlock( blockType, content ); + transform: attributes => { + const validImages = filter( attributes.images, ( { id, url } ) => id && url ); + if ( validImages.length > 0 ) { + return createBlock( name, { + images: validImages.map( ( { id, url, alt, caption } ) => ( { + id, + url, + alt, + caption, + } ) ), + } ); + } + return createBlock( name ); + }, + }, + { + type: 'shortcode', + tag: 'gallery', + attributes: { + // @TODO: other params: https://en.support.wordpress.com/gallery/#gallery-shortcode + images: { + type: 'array', + shortcode: ( { named: { ids } } ) => { + if ( ! ids ) { + return []; + } + + return ids.split( ',' ).map( id => ( { + id: parseInt( id, 10 ), + } ) ); + }, + }, + columns: { + type: 'number', + shortcode: ( { named: { columns = 3 } } ) => { + if ( ! columns ) { + return; + } + + const result = parseInt( columns, 10 ); + if ( result ) { + return result; + } + }, + }, + linkTo: { + type: 'string', + shortcode: ( { named: { link = 'attachment' } } ) => { + return link === 'file' ? 'media' : link; + }, + }, + layout: { + type: 'string', + shortcode: ( { named: { type = DEFAULT_LAYOUT } } ) => { + // @TODO: if `type=slideshow`, return a slideshow block + return LAYOUTS.indexOf( type ) > -1 ? type : DEFAULT_LAYOUT; + }, + }, }, }, ], @@ -89,14 +163,25 @@ const blockSettings = { { type: 'block', blocks: [ 'core/gallery' ], - transform: function( content ) { - return createBlock( 'core/gallery', content ); + transform: ( { images, columns, imageCrop, linkTo } ) => + createBlock( 'core/gallery', { images, columns, imageCrop, linkTo } ), + }, + { + type: 'block', + blocks: [ 'core/image' ], + transform: ( { images } ) => { + if ( images.length > 0 ) { + return images.map( ( { id, url, alt, caption } ) => + createBlock( 'core/image', { id, url, alt, caption } ) + ); + } + return createBlock( 'core/image' ); }, }, ], }, - edit: TiledGalleryEdit, - save: TiledGallerySave, + edit, + save, }; -registerBlockType( blockType, blockSettings ); +registerBlockType( name, settings ); diff --git a/client/gutenberg/extensions/tiled-gallery/editor.scss b/client/gutenberg/extensions/tiled-gallery/editor.scss new file mode 100644 index 0000000000000..55434171edb6d --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/editor.scss @@ -0,0 +1,150 @@ +/** @format */ + +@import './view.scss'; + +@import './variables.scss'; + +.wp-block-jetpack-tiled-gallery.components-placeholder { + margin: 0; +} + +.gutenberg { + // Allow gallery items to go edge to edge. + .wp-block-jetpack-tiled-gallery:not( .components-placeholder ) { + margin-left: -$tiled-gallery-margin; + margin-right: -$tiled-gallery-margin; + } + + // Don't use negative margins when full-wide. + [data-align='full'] .wp-block-jetpack-tiled-gallery:not( .components-placeholder ) { + margin-left: auto; + margin-right: auto; + } +} + +.wp-block-jetpack-tiled-gallery { + .tiled-gallery__row { + .tiled-gallery__item { + // Hide the focus outline that otherwise briefly appears when selecting a block. + figure:not( .is-selected ):focus { + outline: none; + } + + .is-selected { + outline: 4px solid $tiled-gallery-selection; + } + + /* + // Animation for photos being uploaded + // @TODO Import animation from Calypso + &.is-transient img { + @include loading_fade; + } + */ + + .editor-rich-text { + position: absolute; + bottom: 0; + width: 100%; + max-height: 100%; + overflow-y: auto; + } + + .editor-rich-text figcaption:not( [data-is-placeholder-visible='true'] ) { + position: relative; + overflow: hidden; + } + + .is-selected .editor-rich-text { + // IE calculates this incorrectly, so leave it to modern browsers. + @supports ( position: sticky ) { + right: 0; + left: 0; + margin-top: -4px; + } + + // Override negative margins so this toolbar isn't hidden by overflow. Overflow is needed for long captions. + .editor-rich-text__inline-toolbar { + top: 0; + } + + // Make extra space for the inline toolbar. + .editor-rich-text__tinymce { + padding-top: 48px; + } + } + + .editor-rich-text .editor-rich-text__tinymce { + a { + color: $white; + } + + &:focus a[data-mce-selected] { + color: rgba( 0, 0, 0, 0.2 ); + } + } + } + } + + // Circle layout doesn't support captions + &.is-style-circle .tiled-gallery__item .editor-rich-text { + display: none; + } + + .tiled-gallery__row-extras { + &, + .components-form-file-upload, + .components-button.block-library-gallery-add-item-button { + width: 100%; + height: 100%; + } + + .components-button.block-library-gallery-add-item-button { + display: flex; + flex-direction: column; + justify-content: center; + box-shadow: none; + border: none; + border-radius: 0; + min-height: 100px; + + & .dashicon { + margin-top: 10px; + } + + &:hover, + &:focus { + border: $tiled-gallery-add-item-border-width solid $tiled-gallery-add-item-border-color; + } + } + } + + .block-library-gallery-item__inline-menu { + padding: 2px; + position: absolute; + top: -2px; + right: -2px; + background-color: $tiled-gallery-selection; + display: inline-flex; + // z-index: z-index( '.block-library-gallery-item__inline-menu' ); + + .components-button { + color: $white; + &:hover, + &:focus { + color: $white; + } + } + } + + .blocks-gallery-item__remove { + padding: 0; + } + + .blocks-gallery-item .components-spinner { + position: absolute; + top: 50%; + left: 50%; + transform: translate( -50%, -50% ); + } +} diff --git a/client/gutenberg/extensions/tiled-gallery/gallery-grid.jsx b/client/gutenberg/extensions/tiled-gallery/gallery-grid.jsx new file mode 100644 index 0000000000000..c497b007dc065 --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/gallery-grid.jsx @@ -0,0 +1,131 @@ +/** @format */ + +/** + * External dependencies + */ +import { Component, Fragment, createRef } from '@wordpress/element'; +import classnames from 'classnames'; +import { defer, throttle } from 'lodash'; +import ResizeObserver from 'resize-observer-polyfill'; + +/** + * Internal dependencies + */ +import { DEFAULT_GALLERY_WIDTH, RESIZE_RATE_IN_MS } from './constants'; +import { getLayout } from './layouts'; + +class TiledGalleryGrid extends Component { + state = { + width: DEFAULT_GALLERY_WIDTH, + }; + + // Create a ref to store the wrapper DOM element for ResizeObserver + wrapper = createRef(); + + throttleOnResize = throttle( entries => { + for ( const entry of entries ) { + const { width } = entry.contentRect; + if ( width && width !== this.state.width ) { + this.setWidth( width ); + } + } + }, RESIZE_RATE_IN_MS ); + + setWidth( width ) { + this.setState( { width } ); + } + + componentDidMount() { + this.deferredMount = defer( () => { + // ResizeObserver has checks for `window` & `document`: + // it does nothing if those are not available. + this.observer = new ResizeObserver( this.throttleOnResize ); + this.observer.observe( this.wrapper.current.parentNode ); + } ); + } + + componentWillUnmount() { + if ( this.observer ) { + this.observer.disconnect(); + } + clearTimeout( this.deferredMount ); + } + + render() { + const { + align, + children, + className, + columns, + imageCrop, + images, + layout, + renderGalleryImage, + } = this.props; + const { width } = this.state; + const rows = getLayout( { + columns, + layout, + tileCount: images.length, + width, + } ); + let imageIndex = 0; + + return ( +
+ + { rows.map( ( row, rowIndex ) => { + return ( +
+ { row.tiles.map( tile => { + const galleryItem = ( +
+ { renderGalleryImage( imageIndex ) } +
+ ); + + imageIndex++; + + return galleryItem; + } ) } +
+ ); + } ) } + { children ? ( +
+ { children } +
+ ) : null } +
+
+ ); + } +} + +export default TiledGalleryGrid; diff --git a/client/gutenberg/extensions/tiled-gallery/gallery-image.jsx b/client/gutenberg/extensions/tiled-gallery/gallery-image.jsx new file mode 100644 index 0000000000000..4f18eb286d82d --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/gallery-image.jsx @@ -0,0 +1,168 @@ +/** @format */ + +/** + * This component is originally from Gutenberg Gallery block: + * @link https://github.com/WordPress/gutenberg/blob/1cd604df7e9017e0dbe3ab64897ac3af35ca35c5/packages/block-library/src/gallery/gallery-image.js + */ + +/** + * External Dependencies + */ +import { BACKSPACE, DELETE } from '@wordpress/keycodes'; +import { Component } from '@wordpress/element'; +import { IconButton, Spinner } from '@wordpress/components'; +import { RichText } from '@wordpress/editor'; +import { withSelect } from '@wordpress/data'; +import classnames from 'classnames'; + +/** + * Internal Dependencies + */ +import { __ } from 'gutenberg/extensions/presets/jetpack/utils/i18n'; + +class GalleryImage extends Component { + constructor() { + super( ...arguments ); + + this.onImageClick = this.onImageClick.bind( this ); + this.onSelectCaption = this.onSelectCaption.bind( this ); + this.onKeyDown = this.onKeyDown.bind( this ); + this.bindContainer = this.bindContainer.bind( this ); + + this.state = { + captionSelected: false, + }; + } + + bindContainer( ref ) { + this.container = ref; + } + + onSelectCaption() { + if ( ! this.state.captionSelected ) { + this.setState( { + captionSelected: true, + } ); + } + + if ( ! this.props.isSelected ) { + this.props.onSelect(); + } + } + + onImageClick() { + if ( ! this.props.isSelected ) { + this.props.onSelect(); + } + + if ( this.state.captionSelected ) { + this.setState( { + captionSelected: false, + } ); + } + } + + onKeyDown( event ) { + if ( + this.container === document.activeElement && + this.props.isSelected && + [ BACKSPACE, DELETE ].indexOf( event.keyCode ) !== -1 + ) { + event.stopPropagation(); + event.preventDefault(); + this.props.onRemove(); + } + } + + componentDidUpdate( prevProps ) { + const { isSelected, image, url } = this.props; + if ( image && ! url ) { + this.props.setAttributes( { + url: image.source_url, + alt: image.alt_text, + } ); + } + + // unselect the caption so when the user selects other image and comeback + // the caption is not immediately selected + if ( this.state.captionSelected && ! isSelected && prevProps.isSelected ) { + //eslint-disable-next-line + this.setState( { + captionSelected: false, + } ); + } + } + + render() { + const { url, alt, id, linkTo, link, isSelected, caption, onRemove, setAttributes } = this.props; + + let href; + + switch ( linkTo ) { + case 'media': + href = url; + break; + case 'attachment': + href = link; + break; + } + + const img = url ? ( + // Disable reason: Image itself is not meant to be + // interactive, but should direct image selection and unfocus caption fields + // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events + { + ) : ( + + ); + + const className = classnames( { + 'is-selected': isSelected, + 'is-transient': url && 0 === url.indexOf( 'blob:' ), + } ); + + // Disable reason: Each block can be selected by clicking on it and we should keep the same saved markup + /* eslint-disable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/onclick-has-role, jsx-a11y/click-events-have-key-events */ + return ( +
+ { isSelected && ( +
+ +
+ ) } + { href ? { img } : img } + { ! RichText.isEmpty( caption ) || isSelected ? ( + setAttributes( { caption: newCaption } ) } + unstableOnFocus={ this.onSelectCaption } + inlineToolbar + /> + ) : null } +
+ ); + /* eslint-enable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/onclick-has-role, jsx-a11y/click-events-have-key-events */ + } +} + +export default withSelect( ( select, ownProps ) => { + const { getMedia } = select( 'core' ); + const { id } = ownProps; + + return { + image: id ? getMedia( id ) : null, + }; +} )( GalleryImage ); diff --git a/client/gutenberg/extensions/tiled-gallery/item.jsx b/client/gutenberg/extensions/tiled-gallery/item.jsx deleted file mode 100644 index 57b0b506023e1..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/item.jsx +++ /dev/null @@ -1,103 +0,0 @@ -/** @format */ - -/** - * External Dependencies - */ -import classnames from 'classnames'; - -/** - * WordPress dependencies - */ -import { Component } from '@wordpress/element'; -import { withSelect } from '@wordpress/data'; - -class TiledGalleryImage extends Component { - componentDidUpdate( prevProps ) { - if ( prevProps.image && this.props.setAttributes ) { - if ( prevProps.height !== this.props.height ) { - this.props.setAttributes( { height: this.props.height } ); - } - } - } - - render() { - const { url, alt, id, link, width, height, caption } = this.props; - const style = { - width: width + 'px', - height: height + 'px', - }; - - return ( -
- - - { - { caption && - caption.length > 0 && ( -
{ caption }
- ) } -
- ); - } -} - -function TiledGalleryItem( props ) { - const { alt, caption, height, id, link, linkTo, url, width } = props; - - let href; - switch ( linkTo ) { - case 'media': - href = url; - break; - case 'attachment': - href = link; - break; - } - - const img = ( - - ); - - return ( -
- { href ? { img } : img } -
- ); -} - -export default withSelect( ( select, ownProps ) => { - const { getMedia } = select( 'core' ); - const { id } = ownProps; - - return { - image: id ? getMedia( id ) : null, - }; -} )( TiledGalleryItem ); diff --git a/client/gutenberg/extensions/tiled-gallery/layout-square.jsx b/client/gutenberg/extensions/tiled-gallery/layout-square.jsx deleted file mode 100644 index 2279aab08a1e4..0000000000000 --- a/client/gutenberg/extensions/tiled-gallery/layout-square.jsx +++ /dev/null @@ -1,165 +0,0 @@ -/** @format */ - -/** - * WordPress dependencies - */ -import { Component } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import TiledGalleryItem from './item.jsx'; - -// hard coded for now - ideally we'd inject $content_width -// not sure how critical this is, likely necessary to work nicely with themes -const CONTENT_WIDTH = 520; - -function TiledGallerySquareGroup( { - group_size, - id, - url, - link, - width, - height, - caption, - linkTo, - setAttributes, -} ) { - const styleAttr = { - width: group_size + 'px', - height: group_size + 'px', - }; - return ( -
- -
- ); -} - -class TiledGalleryLayoutSquare extends Component { - computeItems() { - const { columns, images } = this.props; - - const content_width = CONTENT_WIDTH; // todo: get content width - const images_per_row = columns > 1 ? columns : 1; - const margin = 2; - - const margin_space = images_per_row * margin * 2; - const size = Math.floor( ( content_width - margin_space ) / images_per_row ); - let remainder_size = size; - let img_size = remainder_size; - const remainder = images.length % images_per_row; - let remainder_space = 0; - if ( remainder > 0 ) { - remainder_space = remainder * margin * 2; - remainder_size = Math.floor( ( content_width - remainder_space ) / remainder ); - } - - let c = 1; - let items_in_row = 0; - const rows = []; - let row = { - images: [], - }; - for ( const image of images ) { - if ( remainder > 0 && c <= remainder ) { - img_size = remainder_size; - } else { - img_size = size; - } - - image.width = image.height = img_size; - - row.images.push( image ); - c++; - items_in_row++; - - if ( images_per_row === items_in_row || remainder + 1 === c ) { - rows.push( row ); - items_in_row = 0; - - row.height = img_size + margin * 2; - row.width = content_width; - row.group_size = img_size + 2 * margin; - - row = { - images: [], - }; - } - } - - if ( row.images.length > 0 ) { - row.height = img_size + margin * 2; - row.width = content_width; - row.group_size = img_size + 2 * margin; - - rows.push( row ); - } - - return rows; - } - - render() { - const rows = this.computeItems(); - const { linkTo, className } = this.props; - - return ( -
-
- { rows.map( ( row, index ) => { - const styleAttr = { - width: row.width + 'px', - height: row.height + 'px', - }; - const setMyAttributes = attrs => this.setImageAttributes( index, attrs ); - - return ( -
- { row.images.map( image => ( - - ) ) } -
- ); - } ) } -
-
- ); - } -} - -export default TiledGalleryLayoutSquare; diff --git a/client/gutenberg/extensions/tiled-gallery/layouts.js b/client/gutenberg/extensions/tiled-gallery/layouts.js new file mode 100644 index 0000000000000..c07654f455a13 --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/layouts.js @@ -0,0 +1,131 @@ +/** @format */ + +/** + * External dependencies + */ +import { find } from 'lodash'; +import TokenList from '@wordpress/token-list'; + +/** + * Internal dependencies + */ +import { LAYOUT_STYLES, MAX_COLUMNS, TILE_MARGIN } from './constants'; + +const squareLayout = ( { columns, margin, width, tileCount } ) => { + columns = Math.min( MAX_COLUMNS, columns ); + const tilesPerRow = columns > 1 ? columns : 1; + const marginSpace = tilesPerRow * margin * 2; + const size = Math.floor( ( width - marginSpace ) / tilesPerRow ); + let remainderSize = size; + let tileSize = remainderSize; + const remainder = tileCount % tilesPerRow; + let remainderSpace = 0; + + if ( remainder > 0 ) { + remainderSpace = remainder * margin * 2; + remainderSize = Math.floor( ( width - remainderSpace ) / remainder ); + } + + let c = 1; + let tilesInRow = 0; + const rows = []; + let row = { + tiles: [], + }; + + for ( let i = 0; i < tileCount; i++ ) { + if ( remainder > 0 && c <= remainder ) { + tileSize = remainderSize; + } else { + tileSize = size; + } + + row.tiles.push( { + height: tileSize, + width: tileSize, + } ); + + c++; + tilesInRow++; + + if ( tilesPerRow === tilesInRow || remainder + 1 === c ) { + rows.push( row ); + tilesInRow = 0; + + row.height = tileSize + margin * 2; + row.width = width; + row.groupSize = tileSize + 2 * margin; + + row = { + tiles: [], + }; + } + } + + if ( row.tiles.length > 0 ) { + row.height = tileSize + margin * 2; + row.width = width; + row.groupSize = tileSize + 2 * margin; + + rows.push( row ); + } + + return rows; +}; + +// @TODO +const rectangularLayout = options => squareLayout( options ); +const columnsLayout = options => squareLayout( options ); + +export const getLayout = ( { columns, tileCount, width, layout } ) => { + const layoutOptions = { + columns, + margin: TILE_MARGIN, + tileCount, + width, + }; + + switch ( layout ) { + case 'square': + return squareLayout( layoutOptions ); + case 'circle': + // Circle and square layouts are identical by size calculations + return squareLayout( layoutOptions ); + case 'columns': + return columnsLayout( layoutOptions ); + case 'rectangular': + default: + return rectangularLayout( layoutOptions ); + } +}; + +/** + * Returns the active style from the given className. + * + * @param {Array} styles Block style variations. + * @param {string} className Class name + * + * @return {Object?} The active style. + * + * From https://github.com/WordPress/gutenberg/blob/077f6c4eb9ba061bc00d5f3ae956d4789a291fb5/packages/editor/src/components/block-styles/index.js#L21-L43 + */ +function getActiveStyle( styles, className ) { + for ( const style of new TokenList( className ).values() ) { + if ( style.indexOf( 'is-style-' ) === -1 ) { + continue; + } + + const potentialStyleName = style.substring( 9 ); + const activeStyle = find( styles, { name: potentialStyleName } ); + if ( activeStyle ) { + return activeStyle; + } + } + + return find( styles, 'isDefault' ); +} + +export const getActiveStyleName = className => { + const activeStyle = getActiveStyle( LAYOUT_STYLES, className ); + return activeStyle.name; +}; diff --git a/client/gutenberg/extensions/tiled-gallery/save.jsx b/client/gutenberg/extensions/tiled-gallery/save.jsx index 64aa9d47b15a0..e1554bf90efbc 100644 --- a/client/gutenberg/extensions/tiled-gallery/save.jsx +++ b/client/gutenberg/extensions/tiled-gallery/save.jsx @@ -1,12 +1,81 @@ +/** @format */ + +/** + * External dependencies + */ +import { RichText } from '@wordpress/editor'; +import classnames from 'classnames'; + /** * Internal dependencies */ -import TiledGalleryLayoutSquare from './layout-square.jsx'; +import { defaultColumnsNumber } from './edit'; +import GalleryGrid from './gallery-grid'; +import { getActiveStyleName } from './layouts'; + +export default ( { attributes } ) => { + const { + align, + className, + columns = defaultColumnsNumber( attributes ), + imageCrop, + images, + linkTo, + } = attributes; + + const layout = getActiveStyleName( className ); + + const renderGalleryImage = index => { + if ( ! images[ index ] ) { + return null; + } + + const image = images[ index ]; + + let href; + + switch ( linkTo ) { + case 'media': + href = image.url; + break; + case 'attachment': + href = image.link; + break; + } + + const img = ( + { + ); + + return ( +
+ { href ? { img } : img } + { layout !== 'circle' && + image.caption && + image.caption.length > 0 && ( + + ) } +
+ ); + }; -function TiledGallerySave( { attributes } ) { return ( - + ); -} - -export default TiledGallerySave; +}; diff --git a/client/gutenberg/extensions/tiled-gallery/variables.scss b/client/gutenberg/extensions/tiled-gallery/variables.scss new file mode 100644 index 0000000000000..1394d927ec3c2 --- /dev/null +++ b/client/gutenberg/extensions/tiled-gallery/variables.scss @@ -0,0 +1,8 @@ +/** @format */ + +$tiled-gallery-add-item-border-color: #555d66; // Gutenberg $dark-gray-500 +$tiled-gallery-add-item-border-width: 1px; // Gutenberg $border-width +$tiled-gallery-caption-background-color: #000; +$tiled-gallery-content-width: 610px; // Gutenberg $content-width +$tiled-gallery-margin: 2px; // Fixed in JS, see `LayoutStyles` from `edit.jsx` +$tiled-gallery-selection: #0085ba; // Gutenberg primary theme color (https://github.com/WordPress/gutenberg/blob/6928e41c8afd7daa3a709afdda7eee48218473b7/bin/packages/post-css-config.js#L4) diff --git a/client/gutenberg/extensions/tiled-gallery/view.js b/client/gutenberg/extensions/tiled-gallery/view.js index d7ad4b8ce8892..420fd58f76f84 100644 --- a/client/gutenberg/extensions/tiled-gallery/view.js +++ b/client/gutenberg/extensions/tiled-gallery/view.js @@ -1,6 +1,117 @@ /** @format */ +/** + * External dependencies + */ +import { throttle } from 'lodash'; +import ResizeObserver from 'resize-observer-polyfill'; + /** * Internal dependencies */ +import { RESIZE_RATE_IN_MS, DEFAULT_GALLERY_WIDTH } from './constants'; +import { getActiveStyleName, getLayout } from './layouts'; + +/** + * Styles + */ import './view.scss'; + +const applyNodeSize = ( node, { width, height } ) => { + node.style.width = `${ width }px`; + node.style.height = `${ height }px`; +}; + +/** + * Calculate new size for the gallery and apply it + */ +const resizeGallery = ( { galleryNode, width, columns, layout } ) => { + const tileCount = galleryNode.querySelectorAll( '.tiled-gallery__item' ).length; + + const galleryLayout = getLayout( { + columns, + layout, + tileCount, + width, + } ); + + // Resize rows within the gallery + galleryNode.childNodes.forEach( ( rowNode, rowIndex ) => { + const rowLayout = galleryLayout[ rowIndex ]; + applyNodeSize( rowNode, rowLayout ); + + // Resize tiles within the row + const tileNodes = rowNode.querySelectorAll( '.tiled-gallery__item' ); + tileNodes.forEach( ( tileNode, tileIndex ) => { + const tileLayout = rowLayout.tiles[ tileIndex ]; + applyNodeSize( tileNode, tileLayout ); + } ); + } ); +}; + +/** + * Throttled resize event + * Compares gallery width to its previous width to decide if to resize it. + */ +const throttleOnResize = throttle( entries => { + for ( const entry of entries ) { + const { width } = entry.contentRect; + // Don't resize if width didn't chance + if ( width !== entry.target.getAttribute( 'data-width' ) ) { + // Store width for later comparison + entry.target.setAttribute( 'data-width', width ); + resizeGallery( { + columns: parseInt( entry.target.getAttribute( 'data-columns' ), 10 ), + galleryNode: entry.target, + layout: getActiveStyleName( entry.target.className ), + width, + } ); + } + } +}, RESIZE_RATE_IN_MS ); + +/** + * Get different galleries on the page + * + * @returns {Array} List of gallery nodes on the page + */ +const getGalleries = () => { + return document ? [ ...document.querySelectorAll( '.wp-block-jetpack-tiled-gallery' ) ] : []; +}; + +/** + * Setup ResizeObserver to follow each gallery on the page + */ +const observeGalleries = () => { + const galleries = getGalleries(); + + if ( galleries.length === 0 ) { + return; + } + + const observer = new ResizeObserver( throttleOnResize ); + + galleries.forEach( gallery => { + // Observe only if gallery has child nodes + if ( gallery.childNodes.length > 0 ) { + // By default gallery has fixed width; element fluid fluid and move + // width to `data-` to be able to compare changes in element's + // current width to element's previous width. + gallery.setAttribute( + 'data-width', + parseInt( gallery.style.width, 10 ) || DEFAULT_GALLERY_WIDTH + ); + gallery.style.width = 'auto'; + observer.observe( gallery ); + } + } ); +}; + +if ( typeof window !== 'undefined' && typeof document !== 'undefined' ) { + // `DOMContentLoaded` may fire before the script has a chance to run + if ( document.readyState === 'loading' ) { + document.addEventListener( 'DOMContentLoaded', observeGalleries ); + } else { + observeGalleries(); + } +} diff --git a/client/gutenberg/extensions/tiled-gallery/view.scss b/client/gutenberg/extensions/tiled-gallery/view.scss index 9448b11422b63..37f4561f414c2 100644 --- a/client/gutenberg/extensions/tiled-gallery/view.scss +++ b/client/gutenberg/extensions/tiled-gallery/view.scss @@ -1,64 +1,110 @@ +/** @format */ + +@import './variables.scss'; + .wp-block-jetpack-tiled-gallery { - .tiled-gallery__square { - clear: both; - margin: 0 0 20px; - overflow: hidden; - } - .tiled-gallery__image { - margin: 2px !important; /* Ensure that this value isn't overridden by themes that give content images blanket margins */ - } - .tiled-gallery__group { - float: left; - position: relative; - } + display: flex; + flex-wrap: wrap; + padding: 0; + + // Allow gallery items to go edge to edge. + margin: 0 -$tiled-gallery-margin 0 -$tiled-gallery-margin; + .tiled-gallery__row { - overflow: hidden; - } - .tiled-gallery__item { - float: left; + // flex-grow: 1; + display: flex; + flex-direction: column; + flex-wrap: wrap; + justify-content: center; margin: 0; - position: relative; - width: inherit; /* prevents ie8 bug with inline width styles */ - a { /* Needs to reset some properties for theme compatibility */ - background: transparent; - border: none; - color: inherit; - margin: 0; - padding: 0; - text-decoration: none; - width: auto; + + .tiled-gallery__item { + justify-content: center; + margin: $tiled-gallery-margin; + position: relative; } + figure { margin: 0; + height: 100%; + + // IE doesn't support flex so omit that. + @supports ( position: sticky ) { + display: flex; + align-items: flex-end; + justify-content: flex-start; + } } - .tiled-gallery__image, - .tiled-gallery__image:hover { /* Needs to reset some properties for theme compatibility */ - background: none; - border: none; - box-shadow: none; + + img { + display: block; max-width: 100%; - padding: 0; - vertical-align: middle; + height: auto; + } + + // IE doesn't handle cropping, so we need an explicit width here. + img { + width: 100%; + + // IE11 doesn't read rules inside this query. They are applied only to modern browsers. + @supports ( position: sticky ) { + width: auto; + } + } + + figcaption { + position: absolute; + bottom: 0; + width: 100%; + max-height: 100%; + overflow: auto; + padding: 40px 10px 5px; + color: $white; + text-align: center; + font-size: $root-font-size; + // @TODO: conflicting linting rules + // stylelint-disable function-parentheses-space-inside + background: linear-gradient( + 0deg, + rgba( $color: $tiled-gallery-caption-background-color, $alpha: 0.7 ) 0, + rgba( $color: $tiled-gallery-caption-background-color, $alpha: 0.3 ) 60%, + transparent + ); + // stylelint-enable function-parentheses-space-inside + + img { + display: inline; + } } } - .tiled-gallery__caption { /* Captions */ - background: #eee; - background: rgba( 255,255,255,0.8 ); - color: #333; - font-size: 13px; - font-weight: 400; - overflow: hidden; - padding: 10px 0; - position: absolute; - bottom: 0; - text-indent: 10px; - text-overflow: ellipsis; - width: 100%; - white-space: nowrap; + &.is-style-circle .tiled-gallery__item img { + border-radius: 50%; + } + + // Cropped + &.is-cropped .tiled-gallery__item { + a, + img { + // IE11 doesn't support object-fit, so just make sure images aren't skewed. + // The following rules are for all browsers. + width: 100%; + + // IE11 doesn't read rules inside this query. They are applied only to modern browsers. + @supports ( position: sticky ) { + height: 100%; + flex: 1; + object-fit: cover; + } + } } - .tiled-gallery__item-small .tiled-gallery__caption { /* Smaller captions */ - font-size: 11px; + // Apply max-width to floated items that have no intrinsic width + [data-align='left'] &, + [data-align='right'] &, + &.alignleft, + &.alignright { + max-width: ( $tiled-gallery-content-width / 2 ); + width: 100%; } } diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 191d0d9458288..a2f92b4e79b41 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -2594,6 +2594,15 @@ "traverse": "^0.6.6" }, "dependencies": { + "@wordpress/token-list": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@wordpress/token-list/-/token-list-1.1.0.tgz", + "integrity": "sha512-1InK0ic0syqUEyY3XkiDiZW9rJB/C/KZEzaOZjyzl/mwDR0npMiAouY3fTQ6qZSsMHjszhSl90yXz1I9M/DapA==", + "requires": { + "@babel/runtime": "^7.0.0", + "lodash": "^4.17.10" + } + }, "jquery": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz", @@ -8152,21 +8161,25 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "optional": true }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "aproba": { "version": "1.2.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "optional": true }, "are-we-there-yet": { "version": "1.1.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", + "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "optional": true, "requires": { "delegates": "^1.0.0", @@ -8175,11 +8188,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "brace-expansion": { "version": "1.1.11", - "bundled": true, + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -8187,29 +8202,35 @@ }, "chownr": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", + "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", "optional": true }, "code-point-at": { "version": "1.1.0", - "bundled": true + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "concat-map": { "version": "0.0.1", - "bundled": true + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "core-util-is": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "optional": true }, "debug": { "version": "2.6.9", - "bundled": true, + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "optional": true, "requires": { "ms": "2.0.0" @@ -8217,22 +8238,26 @@ }, "deep-extend": { "version": "0.5.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.5.1.tgz", + "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", "optional": true }, "delegates": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "optional": true }, "detect-libc": { "version": "1.0.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "optional": true }, "fs-minipass": { "version": "1.2.5", - "bundled": true, + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", + "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "optional": true, "requires": { "minipass": "^2.2.1" @@ -8240,12 +8265,14 @@ }, "fs.realpath": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "optional": true }, "gauge": { "version": "2.7.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "optional": true, "requires": { "aproba": "^1.0.3", @@ -8260,7 +8287,8 @@ }, "glob": { "version": "7.1.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "optional": true, "requires": { "fs.realpath": "^1.0.0", @@ -8273,12 +8301,14 @@ }, "has-unicode": { "version": "2.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "optional": true }, "iconv-lite": { "version": "0.4.21", - "bundled": true, + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.21.tgz", + "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==", "optional": true, "requires": { "safer-buffer": "^2.1.0" @@ -8286,7 +8316,8 @@ }, "ignore-walk": { "version": "3.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", + "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "optional": true, "requires": { "minimatch": "^3.0.4" @@ -8294,7 +8325,8 @@ }, "inflight": { "version": "1.0.6", - "bundled": true, + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "optional": true, "requires": { "once": "^1.3.0", @@ -8303,39 +8335,46 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { "version": "1.3.5", - "bundled": true, + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { "number-is-nan": "^1.0.0" } }, "isarray": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "optional": true }, "minimatch": { "version": "3.0.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "minipass": { "version": "2.2.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.4.tgz", + "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -8343,7 +8382,8 @@ }, "minizlib": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz", + "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==", "optional": true, "requires": { "minipass": "^2.2.1" @@ -8351,19 +8391,22 @@ }, "mkdirp": { "version": "0.5.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" } }, "ms": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "optional": true }, "needle": { "version": "2.2.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.0.tgz", + "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", "optional": true, "requires": { "debug": "^2.1.2", @@ -8373,7 +8416,8 @@ }, "node-pre-gyp": { "version": "0.10.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.0.tgz", + "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==", "optional": true, "requires": { "detect-libc": "^1.0.2", @@ -8390,7 +8434,8 @@ }, "nopt": { "version": "4.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "optional": true, "requires": { "abbrev": "1", @@ -8399,12 +8444,14 @@ }, "npm-bundled": { "version": "1.0.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.3.tgz", + "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==", "optional": true }, "npm-packlist": { "version": "1.1.10", - "bundled": true, + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.10.tgz", + "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==", "optional": true, "requires": { "ignore-walk": "^3.0.1", @@ -8413,7 +8460,8 @@ }, "npmlog": { "version": "4.1.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "optional": true, "requires": { "are-we-there-yet": "~1.1.2", @@ -8424,33 +8472,39 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "object-assign": { "version": "4.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "optional": true }, "once": { "version": "1.4.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { "wrappy": "1" } }, "os-homedir": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "optional": true }, "os-tmpdir": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "optional": true }, "osenv": { "version": "0.1.5", - "bundled": true, + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "optional": true, "requires": { "os-homedir": "^1.0.0", @@ -8459,17 +8513,20 @@ }, "path-is-absolute": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "optional": true }, "process-nextick-args": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "optional": true }, "rc": { "version": "1.2.7", - "bundled": true, + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.7.tgz", + "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", "optional": true, "requires": { "deep-extend": "^0.5.1", @@ -8480,14 +8537,16 @@ "dependencies": { "minimist": { "version": "1.2.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "optional": true } } }, "readable-stream": { "version": "2.3.6", - "bundled": true, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "optional": true, "requires": { "core-util-is": "~1.0.0", @@ -8501,7 +8560,8 @@ }, "rimraf": { "version": "2.6.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "optional": true, "requires": { "glob": "^7.0.5" @@ -8509,36 +8569,43 @@ }, "safe-buffer": { "version": "5.1.1", - "bundled": true + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" }, "safer-buffer": { "version": "2.1.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "optional": true }, "sax": { "version": "1.2.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "optional": true }, "semver": { "version": "5.5.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "optional": true }, "set-blocking": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "optional": true }, "signal-exit": { "version": "3.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "optional": true }, "string-width": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -8547,7 +8614,8 @@ }, "string_decoder": { "version": "1.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "optional": true, "requires": { "safe-buffer": "~5.1.0" @@ -8555,19 +8623,22 @@ }, "strip-ansi": { "version": "3.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" } }, "strip-json-comments": { "version": "2.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "optional": true }, "tar": { "version": "4.4.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.1.tgz", + "integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==", "optional": true, "requires": { "chownr": "^1.0.1", @@ -8581,12 +8652,14 @@ }, "util-deprecate": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "optional": true }, "wide-align": { "version": "1.1.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", + "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "optional": true, "requires": { "string-width": "^1.0.2" @@ -8594,11 +8667,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "yallist": { "version": "3.0.2", - "bundled": true + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", + "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=" } } }, @@ -8819,7 +8894,7 @@ }, "gettext-parser": { "version": "1.4.0", - "resolved": "http://registry.npmjs.org/gettext-parser/-/gettext-parser-1.4.0.tgz", + "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-1.4.0.tgz", "integrity": "sha512-sedZYLHlHeBop/gZ1jdg59hlUEcpcZJofLq2JFwJT1zTqAU3l2wFv6IsuwFHGqbiT9DWzMUW4/em2+hspnmMMA==", "requires": { "encoding": "^0.1.12", @@ -13577,17 +13652,20 @@ "dependencies": { "ansi-regex": { "version": "2.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "code-point-at": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, "cross-spawn": { "version": "5.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { "lru-cache": "^4.0.1", @@ -13597,12 +13675,14 @@ }, "decamelize": { "version": "1.2.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, "execa": { "version": "0.7.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { "cross-spawn": "^5.0.1", @@ -13616,7 +13696,8 @@ }, "find-up": { "version": "2.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { "locate-path": "^2.0.0" @@ -13624,22 +13705,26 @@ }, "get-caller-file": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", "dev": true }, "get-stream": { "version": "3.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, "invert-kv": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", "dev": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { "number-is-nan": "^1.0.0" @@ -13647,17 +13732,20 @@ }, "is-stream": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, "isexe": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, "lcid": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "requires": { "invert-kv": "^1.0.0" @@ -13665,7 +13753,8 @@ }, "locate-path": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { "p-locate": "^2.0.0", @@ -13674,7 +13763,8 @@ }, "lru-cache": { "version": "4.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", "dev": true, "requires": { "pseudomap": "^1.0.2", @@ -13683,7 +13773,8 @@ }, "mem": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "dev": true, "requires": { "mimic-fn": "^1.0.0" @@ -13691,17 +13782,20 @@ }, "mimic-fn": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", + "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=", "dev": true }, "minimist": { "version": "0.0.8", - "bundled": true, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, "mkdirp": { "version": "0.5.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { "minimist": "0.0.8" @@ -13709,7 +13803,8 @@ }, "npm-run-path": { "version": "2.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { "path-key": "^2.0.0" @@ -13717,12 +13812,14 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, "os-locale": { "version": "2.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "dev": true, "requires": { "execa": "^0.7.0", @@ -13732,17 +13829,20 @@ }, "p-finally": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, "p-limit": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", + "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=", "dev": true }, "p-locate": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { "p-limit": "^1.1.0" @@ -13750,37 +13850,44 @@ }, "path-exists": { "version": "3.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, "path-key": { "version": "2.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, "pseudomap": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, "require-directory": { "version": "2.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, "require-main-filename": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, "set-blocking": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, "shebang-command": { "version": "1.2.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { "shebang-regex": "^1.0.0" @@ -13788,17 +13895,20 @@ }, "shebang-regex": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, "signal-exit": { "version": "3.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, "string-width": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { "code-point-at": "^1.0.0", @@ -13808,7 +13918,8 @@ }, "strip-ansi": { "version": "3.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -13816,12 +13927,14 @@ }, "strip-eof": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, "which": { "version": "1.3.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -13829,12 +13942,14 @@ }, "which-module": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, "wrap-ansi": { "version": "2.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { "string-width": "^1.0.1", @@ -13843,17 +13958,20 @@ }, "y18n": { "version": "3.2.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", "dev": true }, "yallist": { "version": "2.1.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true }, "yargs": { "version": "10.0.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/yargs/-/yargs-10.0.3.tgz", + "integrity": "sha512-DqBpQ8NAUX4GyPP/ijDGHsJya4tYqLQrjPr95HNsr1YwL3+daCfvBwg7+gIC6IdJhR2kATh3hb61vjzMWEtjdw==", "dev": true, "requires": { "cliui": "^3.2.0", @@ -13872,12 +13990,14 @@ "dependencies": { "ansi-regex": { "version": "3.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "cliui": { "version": "3.2.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "dev": true, "requires": { "string-width": "^1.0.1", @@ -13887,7 +14007,8 @@ "dependencies": { "string-width": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { "code-point-at": "^1.0.0", @@ -13899,7 +14020,8 @@ }, "string-width": { "version": "2.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", @@ -13908,12 +14030,14 @@ "dependencies": { "is-fullwidth-code-point": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, "strip-ansi": { "version": "4.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { "ansi-regex": "^3.0.0" @@ -13925,7 +14049,8 @@ }, "yargs-parser": { "version": "8.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.0.0.tgz", + "integrity": "sha1-IdR2Mw5agieaS4gTRb8GYQLiGcY=", "dev": true, "requires": { "camelcase": "^4.1.0" @@ -13933,7 +14058,8 @@ "dependencies": { "camelcase": { "version": "4.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true } } @@ -17823,7 +17949,7 @@ }, "react-autosize-textarea": { "version": "3.0.3", - "resolved": "http://registry.npmjs.org/react-autosize-textarea/-/react-autosize-textarea-3.0.3.tgz", + "resolved": "https://registry.npmjs.org/react-autosize-textarea/-/react-autosize-textarea-3.0.3.tgz", "integrity": "sha512-iOSZK7RUuJ+iEwkJ9rqYciqtjQgrG1CCRFL6h8Bk61kODnRyEq4tS74IgXpI1t4S6jBBZVm+6ugaU+tWTlVxXg==", "requires": { "autosize": "^4.0.0", @@ -18723,6 +18849,11 @@ "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", "dev": true }, + "resize-observer-polyfill": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.0.tgz", + "integrity": "sha512-M2AelyJDVR/oLnToJLtuDJRBBWUGUvvGigj1411hXhAdyFWqMaqHp7TixW3FpiLuVaikIcR1QL+zqoJoZlOgpg==" + }, "resolve": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", diff --git a/package.json b/package.json index 4a39c3b098ae5..9dd745b75528e 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,8 @@ "@wordpress/i18n": "3.1.0", "@wordpress/keycodes": "2.0.5", "@wordpress/plugins": "2.0.9", + "@wordpress/rich-text": "3.0.2", + "@wordpress/token-list": "1.1.0", "@wordpress/url": "2.3.1", "@wordpress/viewport": "2.0.12", "autoprefixer": "9.2.1", @@ -173,6 +175,7 @@ "redux-thunk": "2.3.0", "refx": "3.1.1", "rememo": "3.0.0", + "resize-observer-polyfill": "1.5.0", "rtlcss": "2.4.0", "sass-loader": "7.1.0", "social-logos": "2.0.0",