index.tsx 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import React, { ReactElement } from 'react';
  2. import getUuid from '@douyinfe/semi-foundation/utils/uuid';
  3. import HookToast from './HookToast';
  4. import { ToastInstance, ToastProps } from '@douyinfe/semi-foundation/toast/toastFoundation';
  5. // const ref = null;
  6. // TODO: toast larger than N bars, automatic folding, allowing expansion, N configurable
  7. const defaultOpts = {
  8. motion: true,
  9. zIndex: 1010,
  10. duration: 3,
  11. };
  12. function usePatchElement(): [any, typeof patchElement] {
  13. const [elements, setElements] = React.useState([]);
  14. function patchElement(element: ReactElement, config: ToastInstance) {
  15. setElements(originElements => [{ element, config }, ...originElements]);
  16. return (id: string) => {
  17. setElements(originElements =>
  18. originElements.filter(({ config: configOfCurrentElement }) => configOfCurrentElement.id !== id));
  19. };
  20. }
  21. return [elements, patchElement];
  22. }
  23. export default function useToast() {
  24. const [elements, patchElement] = usePatchElement();
  25. const toastRef = new Map<string, { close: () => void } & ReactElement>();
  26. const addToast = (config: ToastProps) => {
  27. const id = getUuid('semi_toast_');
  28. const mergeConfig = {
  29. ...config,
  30. id,
  31. };
  32. // eslint-disable-next-line prefer-const
  33. let closeFunc: ReturnType<typeof patchElement>;
  34. const ref = (ele: { close: () => void } & ReactElement) => {
  35. toastRef.set(id, ele);
  36. };
  37. const toast = (
  38. <HookToast
  39. {...mergeConfig}
  40. key={id}
  41. afterClose={instanceId => closeFunc(instanceId)}
  42. ref={ref}
  43. />
  44. );
  45. closeFunc = patchElement(toast, { ...mergeConfig });
  46. return id;
  47. };
  48. const removeElement = (id: string) => {
  49. const ele = toastRef.get(id);
  50. ele && ele.close();
  51. };
  52. return [
  53. {
  54. success: (config: ToastProps) => addToast({ ...defaultOpts, ...config, type: 'success' }),
  55. info: (config: ToastProps) => addToast({ ...defaultOpts, ...config, type: 'info' }),
  56. error: (config: ToastProps) => addToast({ ...defaultOpts, ...config, type: 'error' }),
  57. warning: (config: ToastProps) => addToast({ ...defaultOpts, ...config, type: 'warning' }),
  58. open: (config: ToastProps) => addToast({ ...defaultOpts, ...config, type: 'default' }),
  59. close: (id: string) => removeElement(id)
  60. },
  61. <>
  62. {
  63. Array.isArray(elements) && elements.length ?
  64. <>{elements.map(item => item.element)}</> :
  65. null
  66. }
  67. </>,
  68. ];
  69. }