button.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. "use strict";
  2. "use client";
  3. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
  4. var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
  5. Object.defineProperty(exports, "__esModule", {
  6. value: true
  7. });
  8. exports.default = void 0;
  9. var _react = _interopRequireWildcard(require("react"));
  10. var _classnames = _interopRequireDefault(require("classnames"));
  11. var _omit = _interopRequireDefault(require("rc-util/lib/omit"));
  12. var _ref = require("rc-util/lib/ref");
  13. var _useLayoutEffect = _interopRequireDefault(require("rc-util/lib/hooks/useLayoutEffect"));
  14. var _warning = require("../_util/warning");
  15. var _wave = _interopRequireDefault(require("../_util/wave"));
  16. var _context = require("../config-provider/context");
  17. var _DisabledContext = _interopRequireDefault(require("../config-provider/DisabledContext"));
  18. var _useSize = _interopRequireDefault(require("../config-provider/hooks/useSize"));
  19. var _Compact = require("../space/Compact");
  20. var _buttonGroup = _interopRequireWildcard(require("./button-group"));
  21. var _buttonHelpers = require("./buttonHelpers");
  22. var _DefaultLoadingIcon = _interopRequireDefault(require("./DefaultLoadingIcon"));
  23. var _IconWrapper = _interopRequireDefault(require("./IconWrapper"));
  24. var _style = _interopRequireDefault(require("./style"));
  25. var _compact = _interopRequireDefault(require("./style/compact"));
  26. var __rest = void 0 && (void 0).__rest || function (s, e) {
  27. var t = {};
  28. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
  29. if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  30. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
  31. }
  32. return t;
  33. };
  34. function getLoadingConfig(loading) {
  35. if (typeof loading === 'object' && loading) {
  36. let delay = loading === null || loading === void 0 ? void 0 : loading.delay;
  37. delay = !Number.isNaN(delay) && typeof delay === 'number' ? delay : 0;
  38. return {
  39. loading: delay <= 0,
  40. delay
  41. };
  42. }
  43. return {
  44. loading: !!loading,
  45. delay: 0
  46. };
  47. }
  48. const ButtonTypeMap = {
  49. default: ['default', 'outlined'],
  50. primary: ['primary', 'solid'],
  51. dashed: ['default', 'dashed'],
  52. // `link` is not a real color but we should compatible with it
  53. link: ['link', 'link'],
  54. text: ['default', 'text']
  55. };
  56. const InternalCompoundedButton = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
  57. var _a, _b;
  58. const {
  59. loading = false,
  60. prefixCls: customizePrefixCls,
  61. color,
  62. variant,
  63. type,
  64. danger = false,
  65. shape: customizeShape,
  66. size: customizeSize,
  67. styles,
  68. disabled: customDisabled,
  69. className,
  70. rootClassName,
  71. children,
  72. icon,
  73. iconPosition = 'start',
  74. ghost = false,
  75. block = false,
  76. // React does not recognize the `htmlType` prop on a DOM element. Here we pick it out of `rest`.
  77. htmlType = 'button',
  78. classNames: customClassNames,
  79. style: customStyle = {},
  80. autoInsertSpace,
  81. autoFocus
  82. } = props,
  83. rest = __rest(props, ["loading", "prefixCls", "color", "variant", "type", "danger", "shape", "size", "styles", "disabled", "className", "rootClassName", "children", "icon", "iconPosition", "ghost", "block", "htmlType", "classNames", "style", "autoInsertSpace", "autoFocus"]);
  84. // https://github.com/ant-design/ant-design/issues/47605
  85. // Compatible with original `type` behavior
  86. const mergedType = type || 'default';
  87. const {
  88. button
  89. } = _react.default.useContext(_context.ConfigContext);
  90. const shape = customizeShape || (button === null || button === void 0 ? void 0 : button.shape) || 'default';
  91. const [mergedColor, mergedVariant] = (0, _react.useMemo)(() => {
  92. // >>>>> Local
  93. // Color & Variant
  94. if (color && variant) {
  95. return [color, variant];
  96. }
  97. // Sugar syntax
  98. if (type || danger) {
  99. const colorVariantPair = ButtonTypeMap[mergedType] || [];
  100. if (danger) {
  101. return ['danger', colorVariantPair[1]];
  102. }
  103. return colorVariantPair;
  104. }
  105. // >>> Context fallback
  106. if ((button === null || button === void 0 ? void 0 : button.color) && (button === null || button === void 0 ? void 0 : button.variant)) {
  107. return [button.color, button.variant];
  108. }
  109. return ['default', 'outlined'];
  110. }, [type, color, variant, danger, button === null || button === void 0 ? void 0 : button.variant, button === null || button === void 0 ? void 0 : button.color]);
  111. const isDanger = mergedColor === 'danger';
  112. const mergedColorText = isDanger ? 'dangerous' : mergedColor;
  113. const {
  114. getPrefixCls,
  115. direction,
  116. autoInsertSpace: contextAutoInsertSpace,
  117. className: contextClassName,
  118. style: contextStyle,
  119. classNames: contextClassNames,
  120. styles: contextStyles
  121. } = (0, _context.useComponentConfig)('button');
  122. const mergedInsertSpace = (_a = autoInsertSpace !== null && autoInsertSpace !== void 0 ? autoInsertSpace : contextAutoInsertSpace) !== null && _a !== void 0 ? _a : true;
  123. const prefixCls = getPrefixCls('btn', customizePrefixCls);
  124. const [wrapCSSVar, hashId, cssVarCls] = (0, _style.default)(prefixCls);
  125. const disabled = (0, _react.useContext)(_DisabledContext.default);
  126. const mergedDisabled = customDisabled !== null && customDisabled !== void 0 ? customDisabled : disabled;
  127. const groupSize = (0, _react.useContext)(_buttonGroup.GroupSizeContext);
  128. const loadingOrDelay = (0, _react.useMemo)(() => getLoadingConfig(loading), [loading]);
  129. const [innerLoading, setLoading] = (0, _react.useState)(loadingOrDelay.loading);
  130. const [hasTwoCNChar, setHasTwoCNChar] = (0, _react.useState)(false);
  131. const buttonRef = (0, _react.useRef)(null);
  132. const mergedRef = (0, _ref.useComposeRef)(ref, buttonRef);
  133. const needInserted = _react.Children.count(children) === 1 && !icon && !(0, _buttonHelpers.isUnBorderedButtonVariant)(mergedVariant);
  134. // ========================= Mount ==========================
  135. // Record for mount status.
  136. // This will help to no to show the animation of loading on the first mount.
  137. const isMountRef = (0, _react.useRef)(true);
  138. _react.default.useEffect(() => {
  139. isMountRef.current = false;
  140. return () => {
  141. isMountRef.current = true;
  142. };
  143. }, []);
  144. // ========================= Effect =========================
  145. // Loading. Should use `useLayoutEffect` to avoid low perf multiple click issue.
  146. // https://github.com/ant-design/ant-design/issues/51325
  147. (0, _useLayoutEffect.default)(() => {
  148. let delayTimer = null;
  149. if (loadingOrDelay.delay > 0) {
  150. delayTimer = setTimeout(() => {
  151. delayTimer = null;
  152. setLoading(true);
  153. }, loadingOrDelay.delay);
  154. } else {
  155. setLoading(loadingOrDelay.loading);
  156. }
  157. function cleanupTimer() {
  158. if (delayTimer) {
  159. clearTimeout(delayTimer);
  160. delayTimer = null;
  161. }
  162. }
  163. return cleanupTimer;
  164. }, [loadingOrDelay.delay, loadingOrDelay.loading]);
  165. // Two chinese characters check
  166. (0, _react.useEffect)(() => {
  167. // FIXME: for HOC usage like <FormatMessage />
  168. if (!buttonRef.current || !mergedInsertSpace) {
  169. return;
  170. }
  171. const buttonText = buttonRef.current.textContent || '';
  172. if (needInserted && (0, _buttonHelpers.isTwoCNChar)(buttonText)) {
  173. if (!hasTwoCNChar) {
  174. setHasTwoCNChar(true);
  175. }
  176. } else if (hasTwoCNChar) {
  177. setHasTwoCNChar(false);
  178. }
  179. });
  180. // Auto focus
  181. (0, _react.useEffect)(() => {
  182. if (autoFocus && buttonRef.current) {
  183. buttonRef.current.focus();
  184. }
  185. }, []);
  186. // ========================= Events =========================
  187. const handleClick = _react.default.useCallback(e => {
  188. var _a;
  189. // FIXME: https://github.com/ant-design/ant-design/issues/30207
  190. if (innerLoading || mergedDisabled) {
  191. e.preventDefault();
  192. return;
  193. }
  194. (_a = props.onClick) === null || _a === void 0 ? void 0 : _a.call(props, 'href' in props ? e : e);
  195. }, [props.onClick, innerLoading, mergedDisabled]);
  196. // ========================== Warn ==========================
  197. if (process.env.NODE_ENV !== 'production') {
  198. const warning = (0, _warning.devUseWarning)('Button');
  199. process.env.NODE_ENV !== "production" ? warning(!(typeof icon === 'string' && icon.length > 2), 'breaking', `\`icon\` is using ReactNode instead of string naming in v4. Please check \`${icon}\` at https://ant.design/components/icon`) : void 0;
  200. process.env.NODE_ENV !== "production" ? warning(!(ghost && (0, _buttonHelpers.isUnBorderedButtonVariant)(mergedVariant)), 'usage', "`link` or `text` button can't be a `ghost` button.") : void 0;
  201. }
  202. // ========================== Size ==========================
  203. const {
  204. compactSize,
  205. compactItemClassnames
  206. } = (0, _Compact.useCompactItemContext)(prefixCls, direction);
  207. const sizeClassNameMap = {
  208. large: 'lg',
  209. small: 'sm',
  210. middle: undefined
  211. };
  212. const sizeFullName = (0, _useSize.default)(ctxSize => {
  213. var _a, _b;
  214. return (_b = (_a = customizeSize !== null && customizeSize !== void 0 ? customizeSize : compactSize) !== null && _a !== void 0 ? _a : groupSize) !== null && _b !== void 0 ? _b : ctxSize;
  215. });
  216. const sizeCls = sizeFullName ? (_b = sizeClassNameMap[sizeFullName]) !== null && _b !== void 0 ? _b : '' : '';
  217. const iconType = innerLoading ? 'loading' : icon;
  218. const linkButtonRestProps = (0, _omit.default)(rest, ['navigate']);
  219. // ========================= Render =========================
  220. const classes = (0, _classnames.default)(prefixCls, hashId, cssVarCls, {
  221. [`${prefixCls}-${shape}`]: shape !== 'default' && shape,
  222. // Compatible with versions earlier than 5.21.0
  223. [`${prefixCls}-${mergedType}`]: mergedType,
  224. [`${prefixCls}-dangerous`]: danger,
  225. [`${prefixCls}-color-${mergedColorText}`]: mergedColorText,
  226. [`${prefixCls}-variant-${mergedVariant}`]: mergedVariant,
  227. [`${prefixCls}-${sizeCls}`]: sizeCls,
  228. [`${prefixCls}-icon-only`]: !children && children !== 0 && !!iconType,
  229. [`${prefixCls}-background-ghost`]: ghost && !(0, _buttonHelpers.isUnBorderedButtonVariant)(mergedVariant),
  230. [`${prefixCls}-loading`]: innerLoading,
  231. [`${prefixCls}-two-chinese-chars`]: hasTwoCNChar && mergedInsertSpace && !innerLoading,
  232. [`${prefixCls}-block`]: block,
  233. [`${prefixCls}-rtl`]: direction === 'rtl',
  234. [`${prefixCls}-icon-end`]: iconPosition === 'end'
  235. }, compactItemClassnames, className, rootClassName, contextClassName);
  236. const fullStyle = Object.assign(Object.assign({}, contextStyle), customStyle);
  237. const iconClasses = (0, _classnames.default)(customClassNames === null || customClassNames === void 0 ? void 0 : customClassNames.icon, contextClassNames.icon);
  238. const iconStyle = Object.assign(Object.assign({}, (styles === null || styles === void 0 ? void 0 : styles.icon) || {}), contextStyles.icon || {});
  239. const iconNode = icon && !innerLoading ? (/*#__PURE__*/_react.default.createElement(_IconWrapper.default, {
  240. prefixCls: prefixCls,
  241. className: iconClasses,
  242. style: iconStyle
  243. }, icon)) : loading && typeof loading === 'object' && loading.icon ? (/*#__PURE__*/_react.default.createElement(_IconWrapper.default, {
  244. prefixCls: prefixCls,
  245. className: iconClasses,
  246. style: iconStyle
  247. }, loading.icon)) : (/*#__PURE__*/_react.default.createElement(_DefaultLoadingIcon.default, {
  248. existIcon: !!icon,
  249. prefixCls: prefixCls,
  250. loading: innerLoading,
  251. mount: isMountRef.current
  252. }));
  253. const kids = children || children === 0 ? (0, _buttonHelpers.spaceChildren)(children, needInserted && mergedInsertSpace) : null;
  254. if (linkButtonRestProps.href !== undefined) {
  255. return wrapCSSVar(/*#__PURE__*/_react.default.createElement("a", Object.assign({}, linkButtonRestProps, {
  256. className: (0, _classnames.default)(classes, {
  257. [`${prefixCls}-disabled`]: mergedDisabled
  258. }),
  259. href: mergedDisabled ? undefined : linkButtonRestProps.href,
  260. style: fullStyle,
  261. onClick: handleClick,
  262. ref: mergedRef,
  263. tabIndex: mergedDisabled ? -1 : 0,
  264. "aria-disabled": mergedDisabled
  265. }), iconNode, kids));
  266. }
  267. let buttonNode = /*#__PURE__*/_react.default.createElement("button", Object.assign({}, rest, {
  268. type: htmlType,
  269. className: classes,
  270. style: fullStyle,
  271. onClick: handleClick,
  272. disabled: mergedDisabled,
  273. ref: mergedRef
  274. }), iconNode, kids, compactItemClassnames && /*#__PURE__*/_react.default.createElement(_compact.default, {
  275. prefixCls: prefixCls
  276. }));
  277. if (!(0, _buttonHelpers.isUnBorderedButtonVariant)(mergedVariant)) {
  278. buttonNode = /*#__PURE__*/_react.default.createElement(_wave.default, {
  279. component: "Button",
  280. disabled: innerLoading
  281. }, buttonNode);
  282. }
  283. return wrapCSSVar(buttonNode);
  284. });
  285. const Button = InternalCompoundedButton;
  286. Button.Group = _buttonGroup.default;
  287. Button.__ANT_BUTTON = true;
  288. if (process.env.NODE_ENV !== 'production') {
  289. Button.displayName = 'Button';
  290. }
  291. var _default = exports.default = Button;