index.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. import _extends from "@babel/runtime/helpers/esm/extends";
  2. import { getArrowOffset } from '../../style/placementArrow';
  3. import { initMoveMotion, initSlideMotion, initZoomMotion, slideDownIn, slideDownOut, slideUpIn, slideUpOut } from '../../style/motion';
  4. import { genComponentStyleHook, mergeToken } from '../../theme/internal';
  5. import genButtonStyle from './button';
  6. import genStatusStyle from './status';
  7. import { genFocusStyle, resetComponent, roundedArrow } from '../../style';
  8. // =============================== Base ===============================
  9. const genBaseStyle = token => {
  10. const {
  11. componentCls,
  12. menuCls,
  13. zIndexPopup,
  14. dropdownArrowDistance,
  15. dropdownArrowOffset,
  16. sizePopupArrow,
  17. antCls,
  18. iconCls,
  19. motionDurationMid,
  20. dropdownPaddingVertical,
  21. fontSize,
  22. dropdownEdgeChildPadding,
  23. colorTextDisabled,
  24. fontSizeIcon,
  25. controlPaddingHorizontal,
  26. colorBgElevated,
  27. boxShadowPopoverArrow
  28. } = token;
  29. return [{
  30. [componentCls]: _extends(_extends({}, resetComponent(token)), {
  31. position: 'absolute',
  32. top: -9999,
  33. left: {
  34. _skip_check_: true,
  35. value: -9999
  36. },
  37. zIndex: zIndexPopup,
  38. display: 'block',
  39. // A placeholder out of dropdown visible range to avoid close when user moving
  40. '&::before': {
  41. position: 'absolute',
  42. insetBlock: -dropdownArrowDistance + sizePopupArrow / 2,
  43. // insetInlineStart: -7, // FIXME: Seems not work for hidden element
  44. zIndex: -9999,
  45. opacity: 0.0001,
  46. content: '""'
  47. },
  48. [`${componentCls}-wrap`]: {
  49. position: 'relative',
  50. [`${antCls}-btn > ${iconCls}-down`]: {
  51. fontSize: fontSizeIcon
  52. },
  53. [`${iconCls}-down::before`]: {
  54. transition: `transform ${motionDurationMid}`
  55. }
  56. },
  57. [`${componentCls}-wrap-open`]: {
  58. [`${iconCls}-down::before`]: {
  59. transform: `rotate(180deg)`
  60. }
  61. },
  62. [`
  63. &-hidden,
  64. &-menu-hidden,
  65. &-menu-submenu-hidden
  66. `]: {
  67. display: 'none'
  68. },
  69. // =============================================================
  70. // == Arrow ==
  71. // =============================================================
  72. // Offset the popover to account for the dropdown arrow
  73. [`
  74. &-show-arrow${componentCls}-placement-topLeft,
  75. &-show-arrow${componentCls}-placement-top,
  76. &-show-arrow${componentCls}-placement-topRight
  77. `]: {
  78. paddingBottom: dropdownArrowDistance
  79. },
  80. [`
  81. &-show-arrow${componentCls}-placement-bottomLeft,
  82. &-show-arrow${componentCls}-placement-bottom,
  83. &-show-arrow${componentCls}-placement-bottomRight
  84. `]: {
  85. paddingTop: dropdownArrowDistance
  86. },
  87. // Note: .popover-arrow is outer, .popover-arrow:after is inner
  88. [`${componentCls}-arrow`]: _extends({
  89. position: 'absolute',
  90. zIndex: 1,
  91. display: 'block'
  92. }, roundedArrow(sizePopupArrow, token.borderRadiusXS, token.borderRadiusOuter, colorBgElevated, boxShadowPopoverArrow)),
  93. [`
  94. &-placement-top > ${componentCls}-arrow,
  95. &-placement-topLeft > ${componentCls}-arrow,
  96. &-placement-topRight > ${componentCls}-arrow
  97. `]: {
  98. bottom: dropdownArrowDistance,
  99. transform: 'translateY(100%) rotate(180deg)'
  100. },
  101. [`&-placement-top > ${componentCls}-arrow`]: {
  102. left: {
  103. _skip_check_: true,
  104. value: '50%'
  105. },
  106. transform: 'translateX(-50%) translateY(100%) rotate(180deg)'
  107. },
  108. [`&-placement-topLeft > ${componentCls}-arrow`]: {
  109. left: {
  110. _skip_check_: true,
  111. value: dropdownArrowOffset
  112. }
  113. },
  114. [`&-placement-topRight > ${componentCls}-arrow`]: {
  115. right: {
  116. _skip_check_: true,
  117. value: dropdownArrowOffset
  118. }
  119. },
  120. [`
  121. &-placement-bottom > ${componentCls}-arrow,
  122. &-placement-bottomLeft > ${componentCls}-arrow,
  123. &-placement-bottomRight > ${componentCls}-arrow
  124. `]: {
  125. top: dropdownArrowDistance,
  126. transform: `translateY(-100%)`
  127. },
  128. [`&-placement-bottom > ${componentCls}-arrow`]: {
  129. left: {
  130. _skip_check_: true,
  131. value: '50%'
  132. },
  133. transform: `translateY(-100%) translateX(-50%)`
  134. },
  135. [`&-placement-bottomLeft > ${componentCls}-arrow`]: {
  136. left: {
  137. _skip_check_: true,
  138. value: dropdownArrowOffset
  139. }
  140. },
  141. [`&-placement-bottomRight > ${componentCls}-arrow`]: {
  142. right: {
  143. _skip_check_: true,
  144. value: dropdownArrowOffset
  145. }
  146. },
  147. // =============================================================
  148. // == Motion ==
  149. // =============================================================
  150. // When position is not enough for dropdown, the placement will revert.
  151. // We will handle this with revert motion name.
  152. [`&${antCls}-slide-down-enter${antCls}-slide-down-enter-active${componentCls}-placement-bottomLeft,
  153. &${antCls}-slide-down-appear${antCls}-slide-down-appear-active${componentCls}-placement-bottomLeft,
  154. &${antCls}-slide-down-enter${antCls}-slide-down-enter-active${componentCls}-placement-bottom,
  155. &${antCls}-slide-down-appear${antCls}-slide-down-appear-active${componentCls}-placement-bottom,
  156. &${antCls}-slide-down-enter${antCls}-slide-down-enter-active${componentCls}-placement-bottomRight,
  157. &${antCls}-slide-down-appear${antCls}-slide-down-appear-active${componentCls}-placement-bottomRight`]: {
  158. animationName: slideUpIn
  159. },
  160. [`&${antCls}-slide-up-enter${antCls}-slide-up-enter-active${componentCls}-placement-topLeft,
  161. &${antCls}-slide-up-appear${antCls}-slide-up-appear-active${componentCls}-placement-topLeft,
  162. &${antCls}-slide-up-enter${antCls}-slide-up-enter-active${componentCls}-placement-top,
  163. &${antCls}-slide-up-appear${antCls}-slide-up-appear-active${componentCls}-placement-top,
  164. &${antCls}-slide-up-enter${antCls}-slide-up-enter-active${componentCls}-placement-topRight,
  165. &${antCls}-slide-up-appear${antCls}-slide-up-appear-active${componentCls}-placement-topRight`]: {
  166. animationName: slideDownIn
  167. },
  168. [`&${antCls}-slide-down-leave${antCls}-slide-down-leave-active${componentCls}-placement-bottomLeft,
  169. &${antCls}-slide-down-leave${antCls}-slide-down-leave-active${componentCls}-placement-bottom,
  170. &${antCls}-slide-down-leave${antCls}-slide-down-leave-active${componentCls}-placement-bottomRight`]: {
  171. animationName: slideUpOut
  172. },
  173. [`&${antCls}-slide-up-leave${antCls}-slide-up-leave-active${componentCls}-placement-topLeft,
  174. &${antCls}-slide-up-leave${antCls}-slide-up-leave-active${componentCls}-placement-top,
  175. &${antCls}-slide-up-leave${antCls}-slide-up-leave-active${componentCls}-placement-topRight`]: {
  176. animationName: slideDownOut
  177. }
  178. })
  179. }, {
  180. // =============================================================
  181. // == Menu ==
  182. // =============================================================
  183. [`${componentCls} ${menuCls}`]: {
  184. position: 'relative',
  185. margin: 0
  186. },
  187. [`${menuCls}-submenu-popup`]: {
  188. position: 'absolute',
  189. zIndex: zIndexPopup,
  190. background: 'transparent',
  191. boxShadow: 'none',
  192. transformOrigin: '0 0',
  193. 'ul,li': {
  194. listStyle: 'none'
  195. },
  196. ul: {
  197. marginInline: '0.3em'
  198. }
  199. },
  200. [`${componentCls}, ${componentCls}-menu-submenu`]: {
  201. [menuCls]: _extends(_extends({
  202. padding: dropdownEdgeChildPadding,
  203. listStyleType: 'none',
  204. backgroundColor: colorBgElevated,
  205. backgroundClip: 'padding-box',
  206. borderRadius: token.borderRadiusLG,
  207. outline: 'none',
  208. boxShadow: token.boxShadowSecondary
  209. }, genFocusStyle(token)), {
  210. [`${menuCls}-item-group-title`]: {
  211. padding: `${dropdownPaddingVertical}px ${controlPaddingHorizontal}px`,
  212. color: token.colorTextDescription,
  213. transition: `all ${motionDurationMid}`
  214. },
  215. // ======================= Item Content =======================
  216. [`${menuCls}-item`]: {
  217. position: 'relative',
  218. display: 'flex',
  219. alignItems: 'center',
  220. borderRadius: token.borderRadiusSM
  221. },
  222. [`${menuCls}-item-icon`]: {
  223. minWidth: fontSize,
  224. marginInlineEnd: token.marginXS,
  225. fontSize: token.fontSizeSM
  226. },
  227. [`${menuCls}-title-content`]: {
  228. flex: 'auto',
  229. '> a': {
  230. color: 'inherit',
  231. transition: `all ${motionDurationMid}`,
  232. '&:hover': {
  233. color: 'inherit'
  234. },
  235. '&::after': {
  236. position: 'absolute',
  237. inset: 0,
  238. content: '""'
  239. }
  240. }
  241. },
  242. // =========================== Item ===========================
  243. [`${menuCls}-item, ${menuCls}-submenu-title`]: _extends(_extends({
  244. clear: 'both',
  245. margin: 0,
  246. padding: `${dropdownPaddingVertical}px ${controlPaddingHorizontal}px`,
  247. color: token.colorText,
  248. fontWeight: 'normal',
  249. fontSize,
  250. lineHeight: token.lineHeight,
  251. cursor: 'pointer',
  252. transition: `all ${motionDurationMid}`,
  253. [`&:hover, &-active`]: {
  254. backgroundColor: token.controlItemBgHover
  255. }
  256. }, genFocusStyle(token)), {
  257. '&-selected': {
  258. color: token.colorPrimary,
  259. backgroundColor: token.controlItemBgActive,
  260. '&:hover, &-active': {
  261. backgroundColor: token.controlItemBgActiveHover
  262. }
  263. },
  264. '&-disabled': {
  265. color: colorTextDisabled,
  266. cursor: 'not-allowed',
  267. '&:hover': {
  268. color: colorTextDisabled,
  269. backgroundColor: colorBgElevated,
  270. cursor: 'not-allowed'
  271. },
  272. a: {
  273. pointerEvents: 'none'
  274. }
  275. },
  276. '&-divider': {
  277. height: 1,
  278. margin: `${token.marginXXS}px 0`,
  279. overflow: 'hidden',
  280. lineHeight: 0,
  281. backgroundColor: token.colorSplit
  282. },
  283. [`${componentCls}-menu-submenu-expand-icon`]: {
  284. position: 'absolute',
  285. insetInlineEnd: token.paddingXS,
  286. [`${componentCls}-menu-submenu-arrow-icon`]: {
  287. marginInlineEnd: '0 !important',
  288. color: token.colorTextDescription,
  289. fontSize: fontSizeIcon,
  290. fontStyle: 'normal'
  291. }
  292. }
  293. }),
  294. [`${menuCls}-item-group-list`]: {
  295. margin: `0 ${token.marginXS}px`,
  296. padding: 0,
  297. listStyle: 'none'
  298. },
  299. [`${menuCls}-submenu-title`]: {
  300. paddingInlineEnd: controlPaddingHorizontal + token.fontSizeSM
  301. },
  302. [`${menuCls}-submenu-vertical`]: {
  303. position: 'relative'
  304. },
  305. [`${menuCls}-submenu${menuCls}-submenu-disabled ${componentCls}-menu-submenu-title`]: {
  306. [`&, ${componentCls}-menu-submenu-arrow-icon`]: {
  307. color: colorTextDisabled,
  308. backgroundColor: colorBgElevated,
  309. cursor: 'not-allowed'
  310. }
  311. },
  312. // https://github.com/ant-design/ant-design/issues/19264
  313. [`${menuCls}-submenu-selected ${componentCls}-menu-submenu-title`]: {
  314. color: token.colorPrimary
  315. }
  316. })
  317. }
  318. },
  319. // Follow code may reuse in other components
  320. [initSlideMotion(token, 'slide-up'), initSlideMotion(token, 'slide-down'), initMoveMotion(token, 'move-up'), initMoveMotion(token, 'move-down'), initZoomMotion(token, 'zoom-big')]];
  321. };
  322. // ============================== Export ==============================
  323. export default genComponentStyleHook('Dropdown', (token, _ref) => {
  324. let {
  325. rootPrefixCls
  326. } = _ref;
  327. const {
  328. marginXXS,
  329. sizePopupArrow,
  330. controlHeight,
  331. fontSize,
  332. lineHeight,
  333. paddingXXS,
  334. componentCls,
  335. borderRadiusOuter,
  336. borderRadiusLG
  337. } = token;
  338. const dropdownPaddingVertical = (controlHeight - fontSize * lineHeight) / 2;
  339. const {
  340. dropdownArrowOffset
  341. } = getArrowOffset({
  342. sizePopupArrow,
  343. contentRadius: borderRadiusLG,
  344. borderRadiusOuter
  345. });
  346. const dropdownToken = mergeToken(token, {
  347. menuCls: `${componentCls}-menu`,
  348. rootPrefixCls,
  349. dropdownArrowDistance: sizePopupArrow / 2 + marginXXS,
  350. dropdownArrowOffset,
  351. dropdownPaddingVertical,
  352. dropdownEdgeChildPadding: paddingXXS
  353. });
  354. return [genBaseStyle(dropdownToken), genButtonStyle(dropdownToken), genStatusStyle(dropdownToken)];
  355. }, token => ({
  356. zIndexPopup: token.zIndexPopupBase + 50
  357. }));