index.tsx 2.7 KB

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