index.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. "use client";
  2. import React, { useContext } from 'react';
  3. import { AppConfigContext } from '../app/context';
  4. import ConfigProvider, { ConfigContext, globalConfig, warnContext } from '../config-provider';
  5. import { unstableSetRender } from '../config-provider/UnstableContext';
  6. import PurePanel from './PurePanel';
  7. import useNotification, { useInternalNotification } from './useNotification';
  8. let notification = null;
  9. let act = callback => callback();
  10. let taskQueue = [];
  11. let defaultGlobalConfig = {};
  12. function getGlobalContext() {
  13. const {
  14. getContainer,
  15. rtl,
  16. maxCount,
  17. top,
  18. bottom,
  19. showProgress,
  20. pauseOnHover
  21. } = defaultGlobalConfig;
  22. const mergedContainer = (getContainer === null || getContainer === void 0 ? void 0 : getContainer()) || document.body;
  23. return {
  24. getContainer: () => mergedContainer,
  25. rtl,
  26. maxCount,
  27. top,
  28. bottom,
  29. showProgress,
  30. pauseOnHover
  31. };
  32. }
  33. const GlobalHolder = /*#__PURE__*/React.forwardRef((props, ref) => {
  34. const {
  35. notificationConfig,
  36. sync
  37. } = props;
  38. const {
  39. getPrefixCls
  40. } = useContext(ConfigContext);
  41. const prefixCls = defaultGlobalConfig.prefixCls || getPrefixCls('notification');
  42. const appConfig = useContext(AppConfigContext);
  43. const [api, holder] = useInternalNotification(Object.assign(Object.assign(Object.assign({}, notificationConfig), {
  44. prefixCls
  45. }), appConfig.notification));
  46. React.useEffect(sync, []);
  47. React.useImperativeHandle(ref, () => {
  48. const instance = Object.assign({}, api);
  49. Object.keys(instance).forEach(method => {
  50. instance[method] = (...args) => {
  51. sync();
  52. return api[method].apply(api, args);
  53. };
  54. });
  55. return {
  56. instance,
  57. sync
  58. };
  59. });
  60. return holder;
  61. });
  62. const GlobalHolderWrapper = /*#__PURE__*/React.forwardRef((_, ref) => {
  63. const [notificationConfig, setNotificationConfig] = React.useState(getGlobalContext);
  64. const sync = () => {
  65. setNotificationConfig(getGlobalContext);
  66. };
  67. React.useEffect(sync, []);
  68. const global = globalConfig();
  69. const rootPrefixCls = global.getRootPrefixCls();
  70. const rootIconPrefixCls = global.getIconPrefixCls();
  71. const theme = global.getTheme();
  72. const dom = /*#__PURE__*/React.createElement(GlobalHolder, {
  73. ref: ref,
  74. sync: sync,
  75. notificationConfig: notificationConfig
  76. });
  77. return /*#__PURE__*/React.createElement(ConfigProvider, {
  78. prefixCls: rootPrefixCls,
  79. iconPrefixCls: rootIconPrefixCls,
  80. theme: theme
  81. }, global.holderRender ? global.holderRender(dom) : dom);
  82. });
  83. const flushNotificationQueue = () => {
  84. if (!notification) {
  85. const holderFragment = document.createDocumentFragment();
  86. const newNotification = {
  87. fragment: holderFragment
  88. };
  89. notification = newNotification;
  90. // Delay render to avoid sync issue
  91. act(() => {
  92. const reactRender = unstableSetRender();
  93. reactRender(/*#__PURE__*/React.createElement(GlobalHolderWrapper, {
  94. ref: node => {
  95. const {
  96. instance,
  97. sync
  98. } = node || {};
  99. Promise.resolve().then(() => {
  100. if (!newNotification.instance && instance) {
  101. newNotification.instance = instance;
  102. newNotification.sync = sync;
  103. flushNotificationQueue();
  104. }
  105. });
  106. }
  107. }), holderFragment);
  108. });
  109. return;
  110. }
  111. // Notification not ready
  112. if (!notification.instance) {
  113. return;
  114. }
  115. // >>> Execute task
  116. taskQueue.forEach(task => {
  117. switch (task.type) {
  118. case 'open':
  119. {
  120. act(() => {
  121. notification.instance.open(Object.assign(Object.assign({}, defaultGlobalConfig), task.config));
  122. });
  123. break;
  124. }
  125. case 'destroy':
  126. act(() => {
  127. var _a;
  128. (_a = notification === null || notification === void 0 ? void 0 : notification.instance) === null || _a === void 0 ? void 0 : _a.destroy(task.key);
  129. });
  130. break;
  131. }
  132. });
  133. // Clean up
  134. taskQueue = [];
  135. };
  136. // ==============================================================================
  137. // == Export ==
  138. // ==============================================================================
  139. function setNotificationGlobalConfig(config) {
  140. defaultGlobalConfig = Object.assign(Object.assign({}, defaultGlobalConfig), config);
  141. // Trigger sync for it
  142. act(() => {
  143. var _a;
  144. (_a = notification === null || notification === void 0 ? void 0 : notification.sync) === null || _a === void 0 ? void 0 : _a.call(notification);
  145. });
  146. }
  147. function open(config) {
  148. const global = globalConfig();
  149. if (process.env.NODE_ENV !== 'production' && !global.holderRender) {
  150. warnContext('notification');
  151. }
  152. taskQueue.push({
  153. type: 'open',
  154. config
  155. });
  156. flushNotificationQueue();
  157. }
  158. const destroy = key => {
  159. taskQueue.push({
  160. type: 'destroy',
  161. key
  162. });
  163. flushNotificationQueue();
  164. };
  165. const methods = ['success', 'info', 'warning', 'error'];
  166. const baseStaticMethods = {
  167. open,
  168. destroy,
  169. config: setNotificationGlobalConfig,
  170. useNotification,
  171. _InternalPanelDoNotUseOrYouWillBeFired: PurePanel
  172. };
  173. const staticMethods = baseStaticMethods;
  174. methods.forEach(type => {
  175. staticMethods[type] = config => open(Object.assign(Object.assign({}, config), {
  176. type
  177. }));
  178. });
  179. // ==============================================================================
  180. // == Test ==
  181. // ==============================================================================
  182. const noop = () => {};
  183. let _actWrapper = noop;
  184. if (process.env.NODE_ENV === 'test') {
  185. _actWrapper = wrapper => {
  186. act = wrapper;
  187. };
  188. }
  189. const actWrapper = _actWrapper;
  190. export { actWrapper };
  191. let _actDestroy = noop;
  192. if (process.env.NODE_ENV === 'test') {
  193. _actDestroy = () => {
  194. notification = null;
  195. };
  196. }
  197. const actDestroy = _actDestroy;
  198. export { actDestroy };
  199. export default staticMethods;