initial commit
This commit is contained in:
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
import { Notice } from 'wordpress-components';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './style.scss';
|
||||
|
||||
const getWooClassName = ( { status = 'default' } ) => {
|
||||
switch ( status ) {
|
||||
case 'error':
|
||||
return 'woocommerce-error';
|
||||
case 'success':
|
||||
return 'woocommerce-message';
|
||||
case 'info':
|
||||
case 'warning':
|
||||
return 'woocommerce-info';
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
const StoreNoticesContainer = ( { className, notices, removeNotice } ) => {
|
||||
const regularNotices = notices.filter(
|
||||
( notice ) => notice.type !== 'snackbar'
|
||||
);
|
||||
|
||||
if ( ! regularNotices.length ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const wrapperClass = classnames( className, 'wc-block-components-notices' );
|
||||
|
||||
return (
|
||||
<div className={ wrapperClass }>
|
||||
{ regularNotices.map( ( props ) => (
|
||||
<Notice
|
||||
key={ 'store-notice-' + props.id }
|
||||
{ ...props }
|
||||
className={ classnames(
|
||||
'wc-block-components-notices__notice',
|
||||
getWooClassName( props )
|
||||
) }
|
||||
onRemove={ () => {
|
||||
if ( props.isDismissible ) {
|
||||
removeNotice( props.id );
|
||||
}
|
||||
} }
|
||||
>
|
||||
{ props.content }
|
||||
</Notice>
|
||||
) ) }
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
StoreNoticesContainer.propTypes = {
|
||||
className: PropTypes.string,
|
||||
notices: PropTypes.arrayOf(
|
||||
PropTypes.shape( {
|
||||
content: PropTypes.string.isRequired,
|
||||
id: PropTypes.string.isRequired,
|
||||
status: PropTypes.string.isRequired,
|
||||
isDismissible: PropTypes.bool,
|
||||
type: PropTypes.oneOf( [ 'default', 'snackbar' ] ),
|
||||
} )
|
||||
),
|
||||
};
|
||||
|
||||
export default StoreNoticesContainer;
|
@ -0,0 +1,32 @@
|
||||
.wc-block-components-notices {
|
||||
display: block;
|
||||
margin-bottom: 2em;
|
||||
.wc-block-components-notices__notice {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
.components-notice__dismiss {
|
||||
background: transparent none;
|
||||
padding: 0;
|
||||
margin: 0 0 0 auto;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
color: currentColor;
|
||||
svg {
|
||||
fill: currentColor;
|
||||
vertical-align: text-top;
|
||||
}
|
||||
}
|
||||
}
|
||||
.wc-block-components-notices__notice + .wc-block-components-notices__notice {
|
||||
margin-top: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
// @todo Either move notice style fixes to Woo core, or take full control over notice component styling in blocks.
|
||||
.theme-twentytwentyone,
|
||||
.theme-twentytwenty {
|
||||
.wc-block-components-notices__notice {
|
||||
padding: 1.5rem 3rem;
|
||||
}
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
createContext,
|
||||
useContext,
|
||||
useCallback,
|
||||
useState,
|
||||
} from '@wordpress/element';
|
||||
import { useSelect, useDispatch } from '@wordpress/data';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { useStoreEvents } from '../../hooks/use-store-events';
|
||||
import { useEditorContext } from '../editor-context';
|
||||
import StoreNoticesContainer from './components/store-notices-container';
|
||||
|
||||
/**
|
||||
* @typedef {import('@woocommerce/type-defs/contexts').NoticeContext} NoticeContext
|
||||
* @typedef {import('react')} React
|
||||
*/
|
||||
|
||||
const StoreNoticesContext = createContext( {
|
||||
notices: [],
|
||||
createNotice: ( status, text, props ) => void { status, text, props },
|
||||
removeNotice: ( id, ctxt ) => void { id, ctxt },
|
||||
setIsSuppressed: ( val ) => void { val },
|
||||
context: 'wc/core',
|
||||
} );
|
||||
|
||||
/**
|
||||
* Returns the notices context values.
|
||||
*
|
||||
* @return {NoticeContext} The notice context value from the notice context.
|
||||
*/
|
||||
export const useStoreNoticesContext = () => {
|
||||
return useContext( StoreNoticesContext );
|
||||
};
|
||||
|
||||
/**
|
||||
* Provides an interface for blocks to add notices to the frontend UI.
|
||||
*
|
||||
* Statuses map to https://github.com/WordPress/gutenberg/tree/master/packages/components/src/notice
|
||||
* - Default (no status)
|
||||
* - Error
|
||||
* - Warning
|
||||
* - Info
|
||||
* - Success
|
||||
*
|
||||
* @param {Object} props Incoming props for the component.
|
||||
* @param {JSX.Element} props.children The Elements wrapped by this component.
|
||||
* @param {string} [props.className] CSS class used.
|
||||
* @param {boolean} [props.createNoticeContainer] Whether to create a notice container or not.
|
||||
* @param {string} [props.context] The notice context for notices being rendered.
|
||||
*/
|
||||
export const StoreNoticesProvider = ( {
|
||||
children,
|
||||
className = '',
|
||||
createNoticeContainer = true,
|
||||
context = 'wc/core',
|
||||
} ) => {
|
||||
const { createNotice, removeNotice } = useDispatch( 'core/notices' );
|
||||
const [ isSuppressed, setIsSuppressed ] = useState( false );
|
||||
const { dispatchStoreEvent } = useStoreEvents();
|
||||
const { isEditor } = useEditorContext();
|
||||
|
||||
const createNoticeWithContext = useCallback(
|
||||
( status = 'default', content = '', options = {} ) => {
|
||||
createNotice( status, content, {
|
||||
...options,
|
||||
context: options.context || context,
|
||||
} );
|
||||
dispatchStoreEvent( 'store-notice-create', {
|
||||
status,
|
||||
content,
|
||||
options,
|
||||
} );
|
||||
},
|
||||
[ createNotice, dispatchStoreEvent, context ]
|
||||
);
|
||||
|
||||
const removeNoticeWithContext = useCallback(
|
||||
( id, ctxt = context ) => {
|
||||
removeNotice( id, ctxt );
|
||||
},
|
||||
[ removeNotice, context ]
|
||||
);
|
||||
|
||||
const { notices } = useSelect(
|
||||
( select ) => {
|
||||
return {
|
||||
notices: select( 'core/notices' ).getNotices( context ),
|
||||
};
|
||||
},
|
||||
[ context ]
|
||||
);
|
||||
|
||||
const contextValue = {
|
||||
notices,
|
||||
createNotice: createNoticeWithContext,
|
||||
removeNotice: removeNoticeWithContext,
|
||||
context,
|
||||
setIsSuppressed,
|
||||
};
|
||||
|
||||
const noticeOutput = isSuppressed ? null : (
|
||||
<StoreNoticesContainer
|
||||
className={ className }
|
||||
notices={ contextValue.notices }
|
||||
removeNotice={ contextValue.removeNotice }
|
||||
isEditor={ isEditor }
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<StoreNoticesContext.Provider value={ contextValue }>
|
||||
{ createNoticeContainer && noticeOutput }
|
||||
{ children }
|
||||
</StoreNoticesContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
StoreNoticesProvider.propTypes = {
|
||||
className: PropTypes.string,
|
||||
createNoticeContainer: PropTypes.bool,
|
||||
children: PropTypes.node,
|
||||
context: PropTypes.string,
|
||||
};
|
@ -0,0 +1,2 @@
|
||||
export * from './components/store-notices-container';
|
||||
export * from './context';
|
Reference in New Issue
Block a user