index.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. import { unit } from '@ant-design/cssinjs';
  2. import { FastColor } from '@ant-design/fast-color';
  3. import { genModalMaskStyle } from '../../modal/style';
  4. import { textEllipsis } from '../../style';
  5. import { initFadeMotion, initZoomMotion } from '../../style/motion';
  6. import { genStyleHooks, mergeToken } from '../../theme/internal';
  7. export const genBoxStyle = position => ({
  8. position: position || 'absolute',
  9. inset: 0
  10. });
  11. export const genImageMaskStyle = token => {
  12. const {
  13. iconCls,
  14. motionDurationSlow,
  15. paddingXXS,
  16. marginXXS,
  17. prefixCls,
  18. colorTextLightSolid
  19. } = token;
  20. return {
  21. position: 'absolute',
  22. inset: 0,
  23. display: 'flex',
  24. alignItems: 'center',
  25. justifyContent: 'center',
  26. color: colorTextLightSolid,
  27. background: new FastColor('#000').setA(0.5).toRgbString(),
  28. cursor: 'pointer',
  29. opacity: 0,
  30. transition: `opacity ${motionDurationSlow}`,
  31. [`.${prefixCls}-mask-info`]: Object.assign(Object.assign({}, textEllipsis), {
  32. padding: `0 ${unit(paddingXXS)}`,
  33. [iconCls]: {
  34. marginInlineEnd: marginXXS,
  35. svg: {
  36. verticalAlign: 'baseline'
  37. }
  38. }
  39. })
  40. };
  41. };
  42. export const genPreviewOperationsStyle = token => {
  43. const {
  44. previewCls,
  45. modalMaskBg,
  46. paddingSM,
  47. marginXL,
  48. margin,
  49. paddingLG,
  50. previewOperationColorDisabled,
  51. previewOperationHoverColor,
  52. motionDurationSlow,
  53. iconCls,
  54. colorTextLightSolid
  55. } = token;
  56. const operationBg = new FastColor(modalMaskBg).setA(0.1);
  57. const operationBgHover = operationBg.clone().setA(0.2);
  58. return {
  59. [`${previewCls}-footer`]: {
  60. position: 'fixed',
  61. bottom: marginXL,
  62. left: {
  63. _skip_check_: true,
  64. value: '50%'
  65. },
  66. display: 'flex',
  67. flexDirection: 'column',
  68. alignItems: 'center',
  69. color: token.previewOperationColor,
  70. transform: 'translateX(-50%)'
  71. },
  72. [`${previewCls}-progress`]: {
  73. marginBottom: margin
  74. },
  75. [`${previewCls}-close`]: {
  76. position: 'fixed',
  77. top: marginXL,
  78. right: {
  79. _skip_check_: true,
  80. value: marginXL
  81. },
  82. display: 'flex',
  83. color: colorTextLightSolid,
  84. backgroundColor: operationBg.toRgbString(),
  85. borderRadius: '50%',
  86. padding: paddingSM,
  87. outline: 0,
  88. border: 0,
  89. cursor: 'pointer',
  90. transition: `all ${motionDurationSlow}`,
  91. '&:hover': {
  92. backgroundColor: operationBgHover.toRgbString()
  93. },
  94. [`& > ${iconCls}`]: {
  95. fontSize: token.previewOperationSize
  96. }
  97. },
  98. [`${previewCls}-operations`]: {
  99. display: 'flex',
  100. alignItems: 'center',
  101. padding: `0 ${unit(paddingLG)}`,
  102. backgroundColor: operationBg.toRgbString(),
  103. borderRadius: 100,
  104. '&-operation': {
  105. marginInlineStart: paddingSM,
  106. padding: paddingSM,
  107. cursor: 'pointer',
  108. transition: `all ${motionDurationSlow}`,
  109. userSelect: 'none',
  110. [`&:not(${previewCls}-operations-operation-disabled):hover > ${iconCls}`]: {
  111. color: previewOperationHoverColor
  112. },
  113. '&-disabled': {
  114. color: previewOperationColorDisabled,
  115. cursor: 'not-allowed'
  116. },
  117. '&:first-of-type': {
  118. marginInlineStart: 0
  119. },
  120. [`& > ${iconCls}`]: {
  121. fontSize: token.previewOperationSize
  122. }
  123. }
  124. }
  125. };
  126. };
  127. export const genPreviewSwitchStyle = token => {
  128. const {
  129. modalMaskBg,
  130. iconCls,
  131. previewOperationColorDisabled,
  132. previewCls,
  133. zIndexPopup,
  134. motionDurationSlow
  135. } = token;
  136. const operationBg = new FastColor(modalMaskBg).setA(0.1);
  137. const operationBgHover = operationBg.clone().setA(0.2);
  138. return {
  139. [`${previewCls}-switch-left, ${previewCls}-switch-right`]: {
  140. position: 'fixed',
  141. insetBlockStart: '50%',
  142. zIndex: token.calc(zIndexPopup).add(1).equal(),
  143. display: 'flex',
  144. alignItems: 'center',
  145. justifyContent: 'center',
  146. width: token.imagePreviewSwitchSize,
  147. height: token.imagePreviewSwitchSize,
  148. marginTop: token.calc(token.imagePreviewSwitchSize).mul(-1).div(2).equal(),
  149. color: token.previewOperationColor,
  150. background: operationBg.toRgbString(),
  151. borderRadius: '50%',
  152. transform: `translateY(-50%)`,
  153. cursor: 'pointer',
  154. transition: `all ${motionDurationSlow}`,
  155. userSelect: 'none',
  156. '&:hover': {
  157. background: operationBgHover.toRgbString()
  158. },
  159. '&-disabled': {
  160. '&, &:hover': {
  161. color: previewOperationColorDisabled,
  162. background: 'transparent',
  163. cursor: 'not-allowed',
  164. [`> ${iconCls}`]: {
  165. cursor: 'not-allowed'
  166. }
  167. }
  168. },
  169. [`> ${iconCls}`]: {
  170. fontSize: token.previewOperationSize
  171. }
  172. },
  173. [`${previewCls}-switch-left`]: {
  174. insetInlineStart: token.marginSM
  175. },
  176. [`${previewCls}-switch-right`]: {
  177. insetInlineEnd: token.marginSM
  178. }
  179. };
  180. };
  181. export const genImagePreviewStyle = token => {
  182. const {
  183. motionEaseOut,
  184. previewCls,
  185. motionDurationSlow,
  186. componentCls
  187. } = token;
  188. return [{
  189. [`${componentCls}-preview-root`]: {
  190. [previewCls]: {
  191. height: '100%',
  192. textAlign: 'center',
  193. pointerEvents: 'none'
  194. },
  195. [`${previewCls}-body`]: Object.assign(Object.assign({}, genBoxStyle()), {
  196. overflow: 'hidden'
  197. }),
  198. [`${previewCls}-img`]: {
  199. maxWidth: '100%',
  200. maxHeight: '70%',
  201. verticalAlign: 'middle',
  202. transform: 'scale3d(1, 1, 1)',
  203. cursor: 'grab',
  204. transition: `transform ${motionDurationSlow} ${motionEaseOut} 0s`,
  205. userSelect: 'none',
  206. '&-wrapper': Object.assign(Object.assign({}, genBoxStyle()), {
  207. transition: `transform ${motionDurationSlow} ${motionEaseOut} 0s`,
  208. // https://github.com/ant-design/ant-design/issues/39913
  209. // TailwindCSS will reset img default style.
  210. // Let's set back.
  211. display: 'flex',
  212. justifyContent: 'center',
  213. alignItems: 'center',
  214. '& > *': {
  215. pointerEvents: 'auto'
  216. },
  217. '&::before': {
  218. display: 'inline-block',
  219. width: 1,
  220. height: '50%',
  221. marginInlineEnd: -1,
  222. content: '""'
  223. }
  224. })
  225. },
  226. [`${previewCls}-moving`]: {
  227. [`${previewCls}-preview-img`]: {
  228. cursor: 'grabbing',
  229. '&-wrapper': {
  230. transitionDuration: '0s'
  231. }
  232. }
  233. }
  234. }
  235. },
  236. // Override
  237. {
  238. [`${componentCls}-preview-root`]: {
  239. [`${previewCls}-wrap`]: {
  240. zIndex: token.zIndexPopup
  241. }
  242. }
  243. },
  244. // Preview operations & switch
  245. {
  246. [`${componentCls}-preview-operations-wrapper`]: {
  247. position: 'fixed',
  248. zIndex: token.calc(token.zIndexPopup).add(1).equal()
  249. },
  250. '&': [genPreviewOperationsStyle(token), genPreviewSwitchStyle(token)]
  251. }];
  252. };
  253. const genImageStyle = token => {
  254. const {
  255. componentCls
  256. } = token;
  257. return {
  258. // ============================== image ==============================
  259. [componentCls]: {
  260. position: 'relative',
  261. display: 'inline-block',
  262. [`${componentCls}-img`]: {
  263. width: '100%',
  264. height: 'auto',
  265. verticalAlign: 'middle'
  266. },
  267. [`${componentCls}-img-placeholder`]: {
  268. backgroundColor: token.colorBgContainerDisabled,
  269. backgroundImage: "url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTQuNSAyLjVoLTEzQS41LjUgMCAwIDAgMSAzdjEwYS41LjUgMCAwIDAgLjUuNWgxM2EuNS41IDAgMCAwIC41LS41VjNhLjUuNSAwIDAgMC0uNS0uNXpNNS4yODEgNC43NWExIDEgMCAwIDEgMCAyIDEgMSAwIDAgMSAwLTJ6bTguMDMgNi44M2EuMTI3LjEyNyAwIDAgMS0uMDgxLjAzSDIuNzY5YS4xMjUuMTI1IDAgMCAxLS4wOTYtLjIwN2wyLjY2MS0zLjE1NmEuMTI2LjEyNiAwIDAgMSAuMTc3LS4wMTZsLjAxNi4wMTZMNy4wOCAxMC4wOWwyLjQ3LTIuOTNhLjEyNi4xMjYgMCAwIDEgLjE3Ny0uMDE2bC4wMTUuMDE2IDMuNTg4IDQuMjQ0YS4xMjcuMTI3IDAgMCAxLS4wMi4xNzV6IiBmaWxsPSIjOEM4QzhDIiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48L3N2Zz4=')",
  270. backgroundRepeat: 'no-repeat',
  271. backgroundPosition: 'center center',
  272. backgroundSize: '30%'
  273. },
  274. [`${componentCls}-mask`]: Object.assign({}, genImageMaskStyle(token)),
  275. [`${componentCls}-mask:hover`]: {
  276. opacity: 1
  277. },
  278. [`${componentCls}-placeholder`]: Object.assign({}, genBoxStyle())
  279. }
  280. };
  281. };
  282. const genPreviewMotion = token => {
  283. const {
  284. previewCls
  285. } = token;
  286. return {
  287. [`${previewCls}-root`]: initZoomMotion(token, 'zoom'),
  288. '&': initFadeMotion(token, true)
  289. };
  290. };
  291. // ============================== Export ==============================
  292. export const prepareComponentToken = token => ({
  293. zIndexPopup: token.zIndexPopupBase + 80,
  294. previewOperationColor: new FastColor(token.colorTextLightSolid).setA(0.65).toRgbString(),
  295. previewOperationHoverColor: new FastColor(token.colorTextLightSolid).setA(0.85).toRgbString(),
  296. previewOperationColorDisabled: new FastColor(token.colorTextLightSolid).setA(0.25).toRgbString(),
  297. previewOperationSize: token.fontSizeIcon * 1.5 // FIXME: fontSizeIconLG
  298. });
  299. export default genStyleHooks('Image', token => {
  300. const previewCls = `${token.componentCls}-preview`;
  301. const imageToken = mergeToken(token, {
  302. previewCls,
  303. modalMaskBg: new FastColor('#000').setA(0.45).toRgbString(),
  304. // FIXME: Shared Token
  305. imagePreviewSwitchSize: token.controlHeightLG
  306. });
  307. return [genImageStyle(imageToken), genImagePreviewStyle(imageToken), genModalMaskStyle(mergeToken(imageToken, {
  308. componentCls: previewCls
  309. })), genPreviewMotion(imageToken)];
  310. }, prepareComponentToken);