117 lines
2.8 KiB
TypeScript
117 lines
2.8 KiB
TypeScript
|
/**
|
||
|
* External dependencies
|
||
|
*/
|
||
|
import { useMemo, useRef, useEffect } from '@wordpress/element';
|
||
|
|
||
|
/**
|
||
|
* Internal dependencies
|
||
|
*/
|
||
|
import { useStoreNoticesContext } from '../providers/store-notices/context';
|
||
|
|
||
|
type WPNoticeAction = {
|
||
|
label: string;
|
||
|
url?: string;
|
||
|
onClick?: () => void;
|
||
|
};
|
||
|
|
||
|
type WPNotice = {
|
||
|
id: string;
|
||
|
status: 'success' | 'info' | 'error' | 'warning';
|
||
|
content: string;
|
||
|
spokenMessage: string;
|
||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||
|
__unstableHTML: string;
|
||
|
isDismissible: boolean;
|
||
|
type: 'default' | 'snackbar';
|
||
|
speak: boolean;
|
||
|
actions: WPNoticeAction[];
|
||
|
};
|
||
|
|
||
|
type NoticeOptions = {
|
||
|
id: string;
|
||
|
type?: string;
|
||
|
isDismissible: boolean;
|
||
|
};
|
||
|
|
||
|
type NoticeCreator = ( text: string, noticeProps: NoticeOptions ) => void;
|
||
|
|
||
|
export const useStoreNotices = (): {
|
||
|
notices: WPNotice[];
|
||
|
hasNoticesOfType: ( type: string ) => boolean;
|
||
|
removeNotices: ( status: string | null ) => void;
|
||
|
removeNotice: ( id: string, context: string ) => void;
|
||
|
addDefaultNotice: NoticeCreator;
|
||
|
addErrorNotice: NoticeCreator;
|
||
|
addWarningNotice: NoticeCreator;
|
||
|
addInfoNotice: NoticeCreator;
|
||
|
addSuccessNotice: NoticeCreator;
|
||
|
setIsSuppressed: ( isSuppressed: boolean ) => void;
|
||
|
} => {
|
||
|
const {
|
||
|
notices,
|
||
|
createNotice,
|
||
|
removeNotice,
|
||
|
setIsSuppressed,
|
||
|
} = useStoreNoticesContext();
|
||
|
// Added to a ref so the surface for notices doesn't change frequently
|
||
|
// and thus can be used as dependencies on effects.
|
||
|
const currentNotices = useRef( notices );
|
||
|
|
||
|
// Update notices ref whenever they change
|
||
|
useEffect( () => {
|
||
|
currentNotices.current = notices;
|
||
|
}, [ notices ] );
|
||
|
|
||
|
const noticesApi = useMemo(
|
||
|
() => ( {
|
||
|
hasNoticesOfType: ( type: 'default' | 'snackbar' ): boolean => {
|
||
|
return currentNotices.current.some(
|
||
|
( notice ) => notice.type === type
|
||
|
);
|
||
|
},
|
||
|
removeNotices: ( status = null ) => {
|
||
|
currentNotices.current.forEach( ( notice ) => {
|
||
|
if ( status === null || notice.status === status ) {
|
||
|
removeNotice( notice.id );
|
||
|
}
|
||
|
} );
|
||
|
},
|
||
|
removeNotice,
|
||
|
} ),
|
||
|
[ removeNotice ]
|
||
|
);
|
||
|
|
||
|
const noticeCreators = useMemo(
|
||
|
() => ( {
|
||
|
addDefaultNotice: ( text: string, noticeProps = {} ) =>
|
||
|
void createNotice( 'default', text, {
|
||
|
...noticeProps,
|
||
|
} ),
|
||
|
addErrorNotice: ( text: string, noticeProps = {} ) =>
|
||
|
void createNotice( 'error', text, {
|
||
|
...noticeProps,
|
||
|
} ),
|
||
|
addWarningNotice: ( text: string, noticeProps = {} ) =>
|
||
|
void createNotice( 'warning', text, {
|
||
|
...noticeProps,
|
||
|
} ),
|
||
|
addInfoNotice: ( text: string, noticeProps = {} ) =>
|
||
|
void createNotice( 'info', text, {
|
||
|
...noticeProps,
|
||
|
} ),
|
||
|
addSuccessNotice: ( text: string, noticeProps = {} ) =>
|
||
|
void createNotice( 'success', text, {
|
||
|
...noticeProps,
|
||
|
} ),
|
||
|
} ),
|
||
|
[ createNotice ]
|
||
|
);
|
||
|
|
||
|
return {
|
||
|
notices,
|
||
|
...noticesApi,
|
||
|
...noticeCreators,
|
||
|
setIsSuppressed,
|
||
|
};
|
||
|
};
|