index.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. import { resetComponent, resetIcon, textEllipsis } from '../../style';
  2. import { genCompactItemStyle } from '../../style/compact-item';
  3. import { genStyleHooks, mergeToken } from '../../theme/internal';
  4. import genDropdownStyle from './dropdown';
  5. import genMultipleStyle from './multiple';
  6. import genSingleStyle from './single';
  7. import { prepareComponentToken } from './token';
  8. import genVariantsStyle from './variants';
  9. // ============================= Selector =============================
  10. const genSelectorStyle = token => {
  11. const {
  12. componentCls
  13. } = token;
  14. return {
  15. position: 'relative',
  16. transition: `all ${token.motionDurationMid} ${token.motionEaseInOut}`,
  17. input: {
  18. cursor: 'pointer'
  19. },
  20. [`${componentCls}-show-search&`]: {
  21. cursor: 'text',
  22. input: {
  23. cursor: 'auto',
  24. color: 'inherit',
  25. height: '100%'
  26. }
  27. },
  28. [`${componentCls}-disabled&`]: {
  29. cursor: 'not-allowed',
  30. input: {
  31. cursor: 'not-allowed'
  32. }
  33. }
  34. };
  35. };
  36. // ============================== Styles ==============================
  37. // /* Reset search input style */
  38. const getSearchInputWithoutBorderStyle = token => {
  39. const {
  40. componentCls
  41. } = token;
  42. return {
  43. [`${componentCls}-selection-search-input`]: {
  44. margin: 0,
  45. padding: 0,
  46. background: 'transparent',
  47. border: 'none',
  48. outline: 'none',
  49. appearance: 'none',
  50. fontFamily: 'inherit',
  51. '&::-webkit-search-cancel-button': {
  52. display: 'none',
  53. appearance: 'none'
  54. }
  55. }
  56. };
  57. };
  58. // =============================== Base ===============================
  59. const genBaseStyle = token => {
  60. const {
  61. antCls,
  62. componentCls,
  63. inputPaddingHorizontalBase,
  64. iconCls
  65. } = token;
  66. const hoverShowClearStyle = {
  67. [`${componentCls}-clear`]: {
  68. opacity: 1,
  69. background: token.colorBgBase,
  70. borderRadius: '50%'
  71. }
  72. };
  73. return {
  74. [componentCls]: Object.assign(Object.assign({}, resetComponent(token)), {
  75. position: 'relative',
  76. display: 'inline-flex',
  77. cursor: 'pointer',
  78. [`&:not(${componentCls}-customize-input) ${componentCls}-selector`]: Object.assign(Object.assign({}, genSelectorStyle(token)), getSearchInputWithoutBorderStyle(token)),
  79. // ======================== Selection ========================
  80. [`${componentCls}-selection-item`]: Object.assign(Object.assign({
  81. flex: 1,
  82. fontWeight: 'normal',
  83. position: 'relative',
  84. userSelect: 'none'
  85. }, textEllipsis), {
  86. // https://github.com/ant-design/ant-design/issues/40421
  87. [`> ${antCls}-typography`]: {
  88. display: 'inline'
  89. }
  90. }),
  91. // ======================= Placeholder =======================
  92. [`${componentCls}-selection-placeholder`]: Object.assign(Object.assign({}, textEllipsis), {
  93. flex: 1,
  94. color: token.colorTextPlaceholder,
  95. pointerEvents: 'none'
  96. }),
  97. // ========================== Arrow ==========================
  98. [`${componentCls}-arrow`]: Object.assign(Object.assign({}, resetIcon()), {
  99. position: 'absolute',
  100. top: '50%',
  101. insetInlineStart: 'auto',
  102. insetInlineEnd: inputPaddingHorizontalBase,
  103. height: token.fontSizeIcon,
  104. marginTop: token.calc(token.fontSizeIcon).mul(-1).div(2).equal(),
  105. color: token.colorTextQuaternary,
  106. fontSize: token.fontSizeIcon,
  107. lineHeight: 1,
  108. textAlign: 'center',
  109. pointerEvents: 'none',
  110. display: 'flex',
  111. alignItems: 'center',
  112. transition: `opacity ${token.motionDurationSlow} ease`,
  113. [iconCls]: {
  114. verticalAlign: 'top',
  115. transition: `transform ${token.motionDurationSlow}`,
  116. '> svg': {
  117. verticalAlign: 'top'
  118. },
  119. [`&:not(${componentCls}-suffix)`]: {
  120. pointerEvents: 'auto'
  121. }
  122. },
  123. [`${componentCls}-disabled &`]: {
  124. cursor: 'not-allowed'
  125. },
  126. '> *:not(:last-child)': {
  127. marginInlineEnd: 8 // FIXME: magic
  128. }
  129. }),
  130. // ========================== Wrap ===========================
  131. [`${componentCls}-selection-wrap`]: {
  132. display: 'flex',
  133. width: '100%',
  134. position: 'relative',
  135. minWidth: 0,
  136. // https://github.com/ant-design/ant-design/issues/51669
  137. '&:after': {
  138. content: '"\\a0"',
  139. width: 0,
  140. overflow: 'hidden'
  141. }
  142. },
  143. // ========================= Prefix ==========================
  144. [`${componentCls}-prefix`]: {
  145. flex: 'none',
  146. marginInlineEnd: token.selectAffixPadding
  147. },
  148. // ========================== Clear ==========================
  149. [`${componentCls}-clear`]: {
  150. position: 'absolute',
  151. top: '50%',
  152. insetInlineStart: 'auto',
  153. insetInlineEnd: inputPaddingHorizontalBase,
  154. zIndex: 1,
  155. display: 'inline-block',
  156. width: token.fontSizeIcon,
  157. height: token.fontSizeIcon,
  158. marginTop: token.calc(token.fontSizeIcon).mul(-1).div(2).equal(),
  159. color: token.colorTextQuaternary,
  160. fontSize: token.fontSizeIcon,
  161. fontStyle: 'normal',
  162. lineHeight: 1,
  163. textAlign: 'center',
  164. textTransform: 'none',
  165. cursor: 'pointer',
  166. opacity: 0,
  167. transition: `color ${token.motionDurationMid} ease, opacity ${token.motionDurationSlow} ease`,
  168. textRendering: 'auto',
  169. // https://github.com/ant-design/ant-design/issues/54205
  170. // Force GPU compositing on Safari to prevent flickering on opacity/transform transitions
  171. transform: 'translateZ(0)',
  172. '&:before': {
  173. display: 'block'
  174. },
  175. '&:hover': {
  176. color: token.colorIcon
  177. }
  178. },
  179. '@media(hover:none)': hoverShowClearStyle,
  180. '&:hover': hoverShowClearStyle
  181. }),
  182. // ========================= Feedback ==========================
  183. [`${componentCls}-status`]: {
  184. '&-error, &-warning, &-success, &-validating': {
  185. [`&${componentCls}-has-feedback`]: {
  186. [`${componentCls}-clear`]: {
  187. insetInlineEnd: token.calc(inputPaddingHorizontalBase).add(token.fontSize).add(token.paddingXS).equal()
  188. }
  189. }
  190. }
  191. }
  192. };
  193. };
  194. // ============================== Styles ==============================
  195. const genSelectStyle = token => {
  196. const {
  197. componentCls
  198. } = token;
  199. return [{
  200. [componentCls]: {
  201. // ==================== In Form ====================
  202. [`&${componentCls}-in-form-item`]: {
  203. width: '100%'
  204. }
  205. }
  206. },
  207. // =====================================================
  208. // == LTR ==
  209. // =====================================================
  210. // Base
  211. genBaseStyle(token),
  212. // Single
  213. genSingleStyle(token),
  214. // Multiple
  215. genMultipleStyle(token),
  216. // Dropdown
  217. genDropdownStyle(token),
  218. // =====================================================
  219. // == RTL ==
  220. // =====================================================
  221. {
  222. [`${componentCls}-rtl`]: {
  223. direction: 'rtl'
  224. }
  225. },
  226. // =====================================================
  227. // == Space Compact ==
  228. // =====================================================
  229. genCompactItemStyle(token, {
  230. borderElCls: `${componentCls}-selector`,
  231. focusElCls: `${componentCls}-focused`
  232. })];
  233. };
  234. // ============================== Export ==============================
  235. export default genStyleHooks('Select', (token, {
  236. rootPrefixCls
  237. }) => {
  238. const selectToken = mergeToken(token, {
  239. rootPrefixCls,
  240. inputPaddingHorizontalBase: token.calc(token.paddingSM).sub(1).equal(),
  241. multipleSelectItemHeight: token.multipleItemHeight,
  242. selectHeight: token.controlHeight
  243. });
  244. return [genSelectStyle(selectToken), genVariantsStyle(selectToken)];
  245. }, prepareComponentToken, {
  246. unitless: {
  247. optionLineHeight: true,
  248. optionSelectedFontWeight: true
  249. }
  250. });