initial commit
This commit is contained in:
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { SnackbarList } from 'wordpress-components';
|
||||
import classnames from 'classnames';
|
||||
import { __experimentalApplyCheckoutFilter } from '@woocommerce/blocks-checkout';
|
||||
|
||||
const EMPTY_SNACKBAR_NOTICES = {};
|
||||
|
||||
const SnackbarNoticesContainer = ( {
|
||||
className,
|
||||
notices,
|
||||
removeNotice,
|
||||
isEditor,
|
||||
} ) => {
|
||||
if ( isEditor ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const snackbarNotices = notices.filter(
|
||||
( notice ) => notice.type === 'snackbar'
|
||||
);
|
||||
|
||||
const noticeVisibility =
|
||||
snackbarNotices.length > 0
|
||||
? snackbarNotices.reduce( ( acc, { content } ) => {
|
||||
acc[ content ] = true;
|
||||
return acc;
|
||||
}, {} )
|
||||
: EMPTY_SNACKBAR_NOTICES;
|
||||
|
||||
const filteredNotices = __experimentalApplyCheckoutFilter( {
|
||||
filterName: 'snackbarNoticeVisibility',
|
||||
defaultValue: noticeVisibility,
|
||||
} );
|
||||
|
||||
const visibleNotices = snackbarNotices.filter(
|
||||
( notice ) => filteredNotices[ notice.content ] === true
|
||||
);
|
||||
|
||||
const wrapperClass = classnames(
|
||||
className,
|
||||
'wc-block-components-notices__snackbar'
|
||||
);
|
||||
|
||||
return (
|
||||
<SnackbarList
|
||||
notices={ visibleNotices }
|
||||
className={ wrapperClass }
|
||||
onRemove={ removeNotice }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default SnackbarNoticesContainer;
|
@ -0,0 +1,20 @@
|
||||
.wc-block-components-notices__snackbar {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
left: 16px;
|
||||
width: auto;
|
||||
|
||||
@include breakpoint("<782px") {
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
bottom: auto;
|
||||
}
|
||||
|
||||
.components-snackbar-list__notice-container {
|
||||
@include breakpoint("<782px") {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
createContext,
|
||||
useContext,
|
||||
useCallback,
|
||||
useState,
|
||||
} from '@wordpress/element';
|
||||
import { useSelect, useDispatch } from '@wordpress/data';
|
||||
import SnackbarNoticesContainer from '@woocommerce/base-context/providers/store-snackbar-notices/components/snackbar-notices-container';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { useStoreEvents } from '../../hooks/use-store-events';
|
||||
import { useEditorContext } from '../editor-context';
|
||||
|
||||
/**
|
||||
* @typedef {import('@woocommerce/type-defs/contexts').NoticeContext} NoticeContext
|
||||
* @typedef {import('react')} React
|
||||
*/
|
||||
|
||||
const StoreSnackbarNoticesContext = createContext( {
|
||||
notices: [],
|
||||
createSnackbarNotice: ( content, options ) => void { content, options },
|
||||
removeSnackbarNotice: ( 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 useStoreSnackbarNoticesContext = () => {
|
||||
return useContext( StoreSnackbarNoticesContext );
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 {React.ReactChildren} props.children The Elements wrapped by this component.
|
||||
* @param {string} props.context The notice context for notices being rendered.
|
||||
*/
|
||||
export const StoreSnackbarNoticesProvider = ( {
|
||||
children,
|
||||
context = 'wc/core',
|
||||
} ) => {
|
||||
const { createNotice, removeNotice } = useDispatch( 'core/notices' );
|
||||
const [ isSuppressed, setIsSuppressed ] = useState( false );
|
||||
const { dispatchStoreEvent } = useStoreEvents();
|
||||
const { isEditor } = useEditorContext();
|
||||
|
||||
const createSnackbarNotice = useCallback(
|
||||
( content = '', options = {} ) => {
|
||||
createNotice( 'default', content, {
|
||||
...options,
|
||||
type: 'snackbar',
|
||||
context: options.context || context,
|
||||
} );
|
||||
dispatchStoreEvent( 'store-notice-create', {
|
||||
status: 'default',
|
||||
content,
|
||||
options,
|
||||
} );
|
||||
},
|
||||
[ createNotice, dispatchStoreEvent, context ]
|
||||
);
|
||||
|
||||
const removeSnackbarNotice = useCallback(
|
||||
( id, ctxt = context ) => {
|
||||
removeNotice( id, ctxt );
|
||||
},
|
||||
[ removeNotice, context ]
|
||||
);
|
||||
|
||||
const { notices } = useSelect(
|
||||
( select ) => {
|
||||
return {
|
||||
notices: select( 'core/notices' ).getNotices( context ),
|
||||
};
|
||||
},
|
||||
[ context ]
|
||||
);
|
||||
|
||||
const contextValue = {
|
||||
notices,
|
||||
createSnackbarNotice,
|
||||
removeSnackbarNotice,
|
||||
context,
|
||||
setIsSuppressed,
|
||||
};
|
||||
|
||||
const snackbarNoticeOutput = isSuppressed ? null : (
|
||||
<SnackbarNoticesContainer
|
||||
notices={ contextValue.notices }
|
||||
removeNotice={ contextValue.removeSnackbarNotice }
|
||||
isEditor={ isEditor }
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<StoreSnackbarNoticesContext.Provider value={ contextValue }>
|
||||
{ children }
|
||||
{ snackbarNoticeOutput }
|
||||
</StoreSnackbarNoticesContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
StoreSnackbarNoticesProvider.propTypes = {
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
context: PropTypes.string,
|
||||
};
|
@ -0,0 +1 @@
|
||||
export * from './context';
|
Reference in New Issue
Block a user