multiple.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. import { unit } from '@ant-design/cssinjs';
  2. import { resetIcon } from '../../style';
  3. import { mergeToken } from '../../theme/internal';
  4. /**
  5. * Get multiple selector needed style. The calculation:
  6. *
  7. * ContainerPadding = BasePadding - ItemMargin
  8. *
  9. * Border: ╔═══════════════════════════╗ ┬
  10. * ContainerPadding: ║ ║ │
  11. * ╟───────────────────────────╢ ┬ │
  12. * Item Margin: ║ ║ │ │
  13. * ║ ┌──────────┐ ║ │ │
  14. * Item(multipleItemHeight): ║ BasePadding │ Item │ ║ Overflow Container(ControlHeight)
  15. * ║ └──────────┘ ║ │ │
  16. * Item Margin: ║ ║ │ │
  17. * ╟───────────────────────────╢ ┴ │
  18. * ContainerPadding: ║ ║ │
  19. * Border: ╚═══════════════════════════╝ ┴
  20. */
  21. export const getMultipleSelectorUnit = token => {
  22. const {
  23. multipleSelectItemHeight,
  24. paddingXXS,
  25. lineWidth,
  26. INTERNAL_FIXED_ITEM_MARGIN
  27. } = token;
  28. const basePadding = token.max(token.calc(paddingXXS).sub(lineWidth).equal(), 0);
  29. const containerPadding = token.max(token.calc(basePadding).sub(INTERNAL_FIXED_ITEM_MARGIN).equal(), 0);
  30. return {
  31. basePadding,
  32. containerPadding,
  33. itemHeight: unit(multipleSelectItemHeight),
  34. itemLineHeight: unit(token.calc(multipleSelectItemHeight).sub(token.calc(token.lineWidth).mul(2)).equal())
  35. };
  36. };
  37. const getSelectItemStyle = token => {
  38. const {
  39. multipleSelectItemHeight,
  40. selectHeight,
  41. lineWidth
  42. } = token;
  43. const selectItemDist = token.calc(selectHeight).sub(multipleSelectItemHeight).div(2).sub(lineWidth).equal();
  44. return selectItemDist;
  45. };
  46. /**
  47. * Get the `rc-overflow` needed style.
  48. * It's a share style which means not affected by `size`.
  49. */
  50. export const genOverflowStyle = token => {
  51. const {
  52. componentCls,
  53. iconCls,
  54. borderRadiusSM,
  55. motionDurationSlow,
  56. paddingXS,
  57. multipleItemColorDisabled,
  58. multipleItemBorderColorDisabled,
  59. colorIcon,
  60. colorIconHover,
  61. INTERNAL_FIXED_ITEM_MARGIN
  62. } = token;
  63. const selectOverflowPrefixCls = `${componentCls}-selection-overflow`;
  64. return {
  65. /**
  66. * Do not merge `height` & `line-height` under style with `selection` & `search`, since chrome
  67. * may update to redesign with its align logic.
  68. */
  69. // =========================== Overflow ===========================
  70. [selectOverflowPrefixCls]: {
  71. position: 'relative',
  72. display: 'flex',
  73. flex: 'auto',
  74. flexWrap: 'wrap',
  75. maxWidth: '100%',
  76. '&-item': {
  77. flex: 'none',
  78. alignSelf: 'center',
  79. // https://github.com/ant-design/ant-design/issues/54179
  80. maxWidth: 'calc(100% - 4px)',
  81. display: 'inline-flex'
  82. },
  83. // ======================== Selections ==========================
  84. [`${componentCls}-selection-item`]: {
  85. display: 'flex',
  86. alignSelf: 'center',
  87. flex: 'none',
  88. boxSizing: 'border-box',
  89. maxWidth: '100%',
  90. marginBlock: INTERNAL_FIXED_ITEM_MARGIN,
  91. borderRadius: borderRadiusSM,
  92. cursor: 'default',
  93. transition: `font-size ${motionDurationSlow}, line-height ${motionDurationSlow}, height ${motionDurationSlow}`,
  94. marginInlineEnd: token.calc(INTERNAL_FIXED_ITEM_MARGIN).mul(2).equal(),
  95. paddingInlineStart: paddingXS,
  96. paddingInlineEnd: token.calc(paddingXS).div(2).equal(),
  97. [`${componentCls}-disabled&`]: {
  98. color: multipleItemColorDisabled,
  99. borderColor: multipleItemBorderColorDisabled,
  100. cursor: 'not-allowed'
  101. },
  102. // It's ok not to do this, but 24px makes bottom narrow in view should adjust
  103. '&-content': {
  104. display: 'inline-block',
  105. marginInlineEnd: token.calc(paddingXS).div(2).equal(),
  106. overflow: 'hidden',
  107. whiteSpace: 'pre',
  108. // fix whitespace wrapping. custom tags display all whitespace within.
  109. textOverflow: 'ellipsis'
  110. },
  111. '&-remove': Object.assign(Object.assign({}, resetIcon()), {
  112. display: 'inline-flex',
  113. alignItems: 'center',
  114. color: colorIcon,
  115. fontWeight: 'bold',
  116. fontSize: 10,
  117. lineHeight: 'inherit',
  118. cursor: 'pointer',
  119. [`> ${iconCls}`]: {
  120. verticalAlign: '-0.2em'
  121. },
  122. '&:hover': {
  123. color: colorIconHover
  124. }
  125. })
  126. }
  127. }
  128. };
  129. };
  130. const genSelectionStyle = (token, suffix) => {
  131. const {
  132. componentCls,
  133. INTERNAL_FIXED_ITEM_MARGIN
  134. } = token;
  135. const selectOverflowPrefixCls = `${componentCls}-selection-overflow`;
  136. const selectItemHeight = token.multipleSelectItemHeight;
  137. const selectItemDist = getSelectItemStyle(token);
  138. const suffixCls = suffix ? `${componentCls}-${suffix}` : '';
  139. const multipleSelectorUnit = getMultipleSelectorUnit(token);
  140. return {
  141. [`${componentCls}-multiple${suffixCls}`]: Object.assign(Object.assign({}, genOverflowStyle(token)), {
  142. // ========================= Selector =========================
  143. [`${componentCls}-selector`]: {
  144. display: 'flex',
  145. alignItems: 'center',
  146. width: '100%',
  147. height: '100%',
  148. // Multiple is little different that horizontal is follow the vertical
  149. paddingInline: multipleSelectorUnit.basePadding,
  150. paddingBlock: multipleSelectorUnit.containerPadding,
  151. borderRadius: token.borderRadius,
  152. [`${componentCls}-disabled&`]: {
  153. background: token.multipleSelectorBgDisabled,
  154. cursor: 'not-allowed'
  155. },
  156. '&:after': {
  157. display: 'inline-block',
  158. width: 0,
  159. margin: `${unit(INTERNAL_FIXED_ITEM_MARGIN)} 0`,
  160. lineHeight: unit(selectItemHeight),
  161. visibility: 'hidden',
  162. content: '"\\a0"'
  163. }
  164. },
  165. // ======================== Selections ========================
  166. [`${componentCls}-selection-item`]: {
  167. height: multipleSelectorUnit.itemHeight,
  168. lineHeight: unit(multipleSelectorUnit.itemLineHeight)
  169. },
  170. // ========================== Wrap ===========================
  171. [`${componentCls}-selection-wrap`]: {
  172. alignSelf: 'flex-start',
  173. '&:after': {
  174. lineHeight: unit(selectItemHeight),
  175. marginBlock: INTERNAL_FIXED_ITEM_MARGIN
  176. }
  177. },
  178. // ========================== Input ==========================
  179. [`${componentCls}-prefix`]: {
  180. marginInlineStart: token.calc(token.inputPaddingHorizontalBase).sub(multipleSelectorUnit.basePadding).equal()
  181. },
  182. [`${selectOverflowPrefixCls}-item + ${selectOverflowPrefixCls}-item,
  183. ${componentCls}-prefix + ${componentCls}-selection-wrap
  184. `]: {
  185. [`${componentCls}-selection-search`]: {
  186. marginInlineStart: 0
  187. },
  188. [`${componentCls}-selection-placeholder`]: {
  189. insetInlineStart: 0
  190. }
  191. },
  192. // https://github.com/ant-design/ant-design/issues/44754
  193. // Same as `wrap:after`
  194. [`${selectOverflowPrefixCls}-item-suffix`]: {
  195. minHeight: multipleSelectorUnit.itemHeight,
  196. marginBlock: INTERNAL_FIXED_ITEM_MARGIN
  197. },
  198. [`${componentCls}-selection-search`]: {
  199. display: 'inline-flex',
  200. position: 'relative',
  201. maxWidth: '100%',
  202. marginInlineStart: token.calc(token.inputPaddingHorizontalBase).sub(selectItemDist).equal(),
  203. [`
  204. &-input,
  205. &-mirror
  206. `]: {
  207. height: selectItemHeight,
  208. fontFamily: token.fontFamily,
  209. lineHeight: unit(selectItemHeight),
  210. transition: `all ${token.motionDurationSlow}`
  211. },
  212. '&-input': {
  213. width: '100%',
  214. minWidth: 4.1 // fix search cursor missing
  215. },
  216. '&-mirror': {
  217. position: 'absolute',
  218. top: 0,
  219. insetInlineStart: 0,
  220. insetInlineEnd: 'auto',
  221. zIndex: 999,
  222. whiteSpace: 'pre',
  223. // fix whitespace wrapping caused width calculation bug
  224. visibility: 'hidden'
  225. }
  226. },
  227. // ======================= Placeholder =======================
  228. [`${componentCls}-selection-placeholder`]: {
  229. position: 'absolute',
  230. top: '50%',
  231. insetInlineStart: token.calc(token.inputPaddingHorizontalBase).sub(multipleSelectorUnit.basePadding).equal(),
  232. insetInlineEnd: token.inputPaddingHorizontalBase,
  233. transform: 'translateY(-50%)',
  234. transition: `all ${token.motionDurationSlow}`
  235. }
  236. })
  237. };
  238. };
  239. function genSizeStyle(token, suffix) {
  240. const {
  241. componentCls
  242. } = token;
  243. const suffixCls = suffix ? `${componentCls}-${suffix}` : '';
  244. const rawStyle = {
  245. [`${componentCls}-multiple${suffixCls}`]: {
  246. fontSize: token.fontSize,
  247. // ========================= Selector =========================
  248. [`${componentCls}-selector`]: {
  249. [`${componentCls}-show-search&`]: {
  250. cursor: 'text'
  251. }
  252. },
  253. [`
  254. &${componentCls}-show-arrow ${componentCls}-selector,
  255. &${componentCls}-allow-clear ${componentCls}-selector
  256. `]: {
  257. paddingInlineEnd: token.calc(token.fontSizeIcon).add(token.controlPaddingHorizontal).equal()
  258. }
  259. }
  260. };
  261. return [genSelectionStyle(token, suffix), rawStyle];
  262. }
  263. const genMultipleStyle = token => {
  264. const {
  265. componentCls
  266. } = token;
  267. const smallToken = mergeToken(token, {
  268. selectHeight: token.controlHeightSM,
  269. multipleSelectItemHeight: token.multipleItemHeightSM,
  270. borderRadius: token.borderRadiusSM,
  271. borderRadiusSM: token.borderRadiusXS
  272. });
  273. const largeToken = mergeToken(token, {
  274. fontSize: token.fontSizeLG,
  275. selectHeight: token.controlHeightLG,
  276. multipleSelectItemHeight: token.multipleItemHeightLG,
  277. borderRadius: token.borderRadiusLG,
  278. borderRadiusSM: token.borderRadius
  279. });
  280. return [genSizeStyle(token),
  281. // ======================== Small ========================
  282. genSizeStyle(smallToken, 'sm'),
  283. // Padding
  284. {
  285. [`${componentCls}-multiple${componentCls}-sm`]: {
  286. [`${componentCls}-selection-placeholder`]: {
  287. insetInline: token.calc(token.controlPaddingHorizontalSM).sub(token.lineWidth).equal()
  288. },
  289. // https://github.com/ant-design/ant-design/issues/29559
  290. [`${componentCls}-selection-search`]: {
  291. marginInlineStart: 2 // Magic Number
  292. }
  293. }
  294. },
  295. // ======================== Large ========================
  296. genSizeStyle(largeToken, 'lg')];
  297. };
  298. export default genMultipleStyle;