useClosable.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. "use client";
  2. import React from 'react';
  3. import CloseOutlined from "@ant-design/icons/es/icons/CloseOutlined";
  4. import pickAttrs from "rc-util/es/pickAttrs";
  5. import { useLocale } from '../../locale';
  6. import defaultLocale from '../../locale/en_US';
  7. import extendsObject from '../extendsObject';
  8. export function pickClosable(context) {
  9. if (!context) {
  10. return undefined;
  11. }
  12. const {
  13. closable,
  14. closeIcon
  15. } = context;
  16. return {
  17. closable,
  18. closeIcon
  19. };
  20. }
  21. /** Convert `closable` and `closeIcon` to config object */
  22. function useClosableConfig(closableCollection) {
  23. const {
  24. closable,
  25. closeIcon
  26. } = closableCollection || {};
  27. return React.useMemo(() => {
  28. if (
  29. // If `closable`, whatever rest be should be true
  30. !closable && (closable === false || closeIcon === false || closeIcon === null)) {
  31. return false;
  32. }
  33. if (closable === undefined && closeIcon === undefined) {
  34. return null;
  35. }
  36. let closableConfig = {
  37. closeIcon: typeof closeIcon !== 'boolean' && closeIcon !== null ? closeIcon : undefined
  38. };
  39. if (closable && typeof closable === 'object') {
  40. closableConfig = Object.assign(Object.assign({}, closableConfig), closable);
  41. }
  42. return closableConfig;
  43. }, [closable, closeIcon]);
  44. }
  45. /** Use same object to support `useMemo` optimization */
  46. const EmptyFallbackCloseCollection = {};
  47. export default function useClosable(propCloseCollection, contextCloseCollection, fallbackCloseCollection = EmptyFallbackCloseCollection) {
  48. // Align the `props`, `context` `fallback` to config object first
  49. const propCloseConfig = useClosableConfig(propCloseCollection);
  50. const contextCloseConfig = useClosableConfig(contextCloseCollection);
  51. const [contextLocale] = useLocale('global', defaultLocale.global);
  52. const closeBtnIsDisabled = typeof propCloseConfig !== 'boolean' ? !!(propCloseConfig === null || propCloseConfig === void 0 ? void 0 : propCloseConfig.disabled) : false;
  53. const mergedFallbackCloseCollection = React.useMemo(() => Object.assign({
  54. closeIcon: /*#__PURE__*/React.createElement(CloseOutlined, null)
  55. }, fallbackCloseCollection), [fallbackCloseCollection]);
  56. // Use fallback logic to fill the config
  57. const mergedClosableConfig = React.useMemo(() => {
  58. // ================ Props First ================
  59. // Skip if prop is disabled
  60. if (propCloseConfig === false) {
  61. return false;
  62. }
  63. if (propCloseConfig) {
  64. return extendsObject(mergedFallbackCloseCollection, contextCloseConfig, propCloseConfig);
  65. }
  66. // =============== Context Second ==============
  67. // Skip if context is disabled
  68. if (contextCloseConfig === false) {
  69. return false;
  70. }
  71. if (contextCloseConfig) {
  72. return extendsObject(mergedFallbackCloseCollection, contextCloseConfig);
  73. }
  74. // ============= Fallback Default ==============
  75. return !mergedFallbackCloseCollection.closable ? false : mergedFallbackCloseCollection;
  76. }, [propCloseConfig, contextCloseConfig, mergedFallbackCloseCollection]);
  77. // Calculate the final closeIcon
  78. return React.useMemo(() => {
  79. var _a, _b;
  80. if (mergedClosableConfig === false) {
  81. return [false, null, closeBtnIsDisabled, {}];
  82. }
  83. const {
  84. closeIconRender
  85. } = mergedFallbackCloseCollection;
  86. const {
  87. closeIcon
  88. } = mergedClosableConfig;
  89. let mergedCloseIcon = closeIcon;
  90. // Wrap the closeIcon with aria props
  91. const ariaOrDataProps = pickAttrs(mergedClosableConfig, true);
  92. if (mergedCloseIcon !== null && mergedCloseIcon !== undefined) {
  93. // Wrap the closeIcon if needed
  94. if (closeIconRender) {
  95. mergedCloseIcon = closeIconRender(closeIcon);
  96. }
  97. mergedCloseIcon = /*#__PURE__*/React.isValidElement(mergedCloseIcon) ? (/*#__PURE__*/React.cloneElement(mergedCloseIcon, Object.assign(Object.assign(Object.assign({}, mergedCloseIcon.props), {
  98. 'aria-label': (_b = (_a = mergedCloseIcon.props) === null || _a === void 0 ? void 0 : _a['aria-label']) !== null && _b !== void 0 ? _b : contextLocale.close
  99. }), ariaOrDataProps))) : (/*#__PURE__*/React.createElement("span", Object.assign({
  100. "aria-label": contextLocale.close
  101. }, ariaOrDataProps), mergedCloseIcon));
  102. }
  103. return [true, mergedCloseIcon, closeBtnIsDisabled, ariaOrDataProps];
  104. }, [mergedClosableConfig, mergedFallbackCloseCollection]);
  105. }