index.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. import _extends from "@babel/runtime/helpers/esm/extends";
  2. import { Keyframes } from '../../_util/cssinjs';
  3. import { genCollapseMotion } from '../../style/motion';
  4. import { getStyle as getCheckboxStyle } from '../../checkbox/style';
  5. import { genComponentStyleHook, mergeToken } from '../../theme/internal';
  6. import { genFocusOutline, resetComponent } from '../../style';
  7. // ============================ Keyframes =============================
  8. const treeNodeFX = new Keyframes('ant-tree-node-fx-do-not-use', {
  9. '0%': {
  10. opacity: 0
  11. },
  12. '100%': {
  13. opacity: 1
  14. }
  15. });
  16. // ============================== Switch ==============================
  17. const getSwitchStyle = (prefixCls, token) => ({
  18. [`.${prefixCls}-switcher-icon`]: {
  19. display: 'inline-block',
  20. fontSize: 10,
  21. verticalAlign: 'baseline',
  22. svg: {
  23. transition: `transform ${token.motionDurationSlow}`
  24. }
  25. }
  26. });
  27. // =============================== Drop ===============================
  28. const getDropIndicatorStyle = (prefixCls, token) => ({
  29. [`.${prefixCls}-drop-indicator`]: {
  30. position: 'absolute',
  31. // it should displayed over the following node
  32. zIndex: 1,
  33. height: 2,
  34. backgroundColor: token.colorPrimary,
  35. borderRadius: 1,
  36. pointerEvents: 'none',
  37. '&:after': {
  38. position: 'absolute',
  39. top: -3,
  40. insetInlineStart: -6,
  41. width: 8,
  42. height: 8,
  43. backgroundColor: 'transparent',
  44. border: `${token.lineWidthBold}px solid ${token.colorPrimary}`,
  45. borderRadius: '50%',
  46. content: '""'
  47. }
  48. }
  49. });
  50. export const genBaseStyle = (prefixCls, token) => {
  51. const {
  52. treeCls,
  53. treeNodeCls,
  54. treeNodePadding,
  55. treeTitleHeight
  56. } = token;
  57. const treeCheckBoxMarginVertical = (treeTitleHeight - token.fontSizeLG) / 2;
  58. const treeCheckBoxMarginHorizontal = token.paddingXS;
  59. return {
  60. [treeCls]: _extends(_extends({}, resetComponent(token)), {
  61. background: token.colorBgContainer,
  62. borderRadius: token.borderRadius,
  63. transition: `background-color ${token.motionDurationSlow}`,
  64. [`&${treeCls}-rtl`]: {
  65. // >>> Switcher
  66. [`${treeCls}-switcher`]: {
  67. '&_close': {
  68. [`${treeCls}-switcher-icon`]: {
  69. svg: {
  70. transform: 'rotate(90deg)'
  71. }
  72. }
  73. }
  74. }
  75. },
  76. [`&-focused:not(:hover):not(${treeCls}-active-focused)`]: _extends({}, genFocusOutline(token)),
  77. // =================== Virtual List ===================
  78. [`${treeCls}-list-holder-inner`]: {
  79. alignItems: 'flex-start'
  80. },
  81. [`&${treeCls}-block-node`]: {
  82. [`${treeCls}-list-holder-inner`]: {
  83. alignItems: 'stretch',
  84. // >>> Title
  85. [`${treeCls}-node-content-wrapper`]: {
  86. flex: 'auto'
  87. },
  88. // >>> Drag
  89. [`${treeNodeCls}.dragging`]: {
  90. position: 'relative',
  91. '&:after': {
  92. position: 'absolute',
  93. top: 0,
  94. insetInlineEnd: 0,
  95. bottom: treeNodePadding,
  96. insetInlineStart: 0,
  97. border: `1px solid ${token.colorPrimary}`,
  98. opacity: 0,
  99. animationName: treeNodeFX,
  100. animationDuration: token.motionDurationSlow,
  101. animationPlayState: 'running',
  102. animationFillMode: 'forwards',
  103. content: '""',
  104. pointerEvents: 'none'
  105. }
  106. }
  107. }
  108. },
  109. // ===================== TreeNode =====================
  110. [`${treeNodeCls}`]: {
  111. display: 'flex',
  112. alignItems: 'flex-start',
  113. padding: `0 0 ${treeNodePadding}px 0`,
  114. outline: 'none',
  115. '&-rtl': {
  116. direction: 'rtl'
  117. },
  118. // Disabled
  119. '&-disabled': {
  120. // >>> Title
  121. [`${treeCls}-node-content-wrapper`]: {
  122. color: token.colorTextDisabled,
  123. cursor: 'not-allowed',
  124. '&:hover': {
  125. background: 'transparent'
  126. }
  127. }
  128. },
  129. [`&-active ${treeCls}-node-content-wrapper`]: _extends({}, genFocusOutline(token)),
  130. [`&:not(${treeNodeCls}-disabled).filter-node ${treeCls}-title`]: {
  131. color: 'inherit',
  132. fontWeight: 500
  133. },
  134. '&-draggable': {
  135. [`${treeCls}-draggable-icon`]: {
  136. width: treeTitleHeight,
  137. lineHeight: `${treeTitleHeight}px`,
  138. textAlign: 'center',
  139. visibility: 'visible',
  140. opacity: 0.2,
  141. transition: `opacity ${token.motionDurationSlow}`,
  142. [`${treeNodeCls}:hover &`]: {
  143. opacity: 0.45
  144. }
  145. },
  146. [`&${treeNodeCls}-disabled`]: {
  147. [`${treeCls}-draggable-icon`]: {
  148. visibility: 'hidden'
  149. }
  150. }
  151. }
  152. },
  153. // >>> Indent
  154. [`${treeCls}-indent`]: {
  155. alignSelf: 'stretch',
  156. whiteSpace: 'nowrap',
  157. userSelect: 'none',
  158. '&-unit': {
  159. display: 'inline-block',
  160. width: treeTitleHeight
  161. }
  162. },
  163. // >>> Drag Handler
  164. [`${treeCls}-draggable-icon`]: {
  165. visibility: 'hidden'
  166. },
  167. // >>> Switcher
  168. [`${treeCls}-switcher`]: _extends(_extends({}, getSwitchStyle(prefixCls, token)), {
  169. position: 'relative',
  170. flex: 'none',
  171. alignSelf: 'stretch',
  172. width: treeTitleHeight,
  173. margin: 0,
  174. lineHeight: `${treeTitleHeight}px`,
  175. textAlign: 'center',
  176. cursor: 'pointer',
  177. userSelect: 'none',
  178. '&-noop': {
  179. cursor: 'default'
  180. },
  181. '&_close': {
  182. [`${treeCls}-switcher-icon`]: {
  183. svg: {
  184. transform: 'rotate(-90deg)'
  185. }
  186. }
  187. },
  188. '&-loading-icon': {
  189. color: token.colorPrimary
  190. },
  191. '&-leaf-line': {
  192. position: 'relative',
  193. zIndex: 1,
  194. display: 'inline-block',
  195. width: '100%',
  196. height: '100%',
  197. // https://github.com/ant-design/ant-design/issues/31884
  198. '&:before': {
  199. position: 'absolute',
  200. top: 0,
  201. insetInlineEnd: treeTitleHeight / 2,
  202. bottom: -treeNodePadding,
  203. marginInlineStart: -1,
  204. borderInlineEnd: `1px solid ${token.colorBorder}`,
  205. content: '""'
  206. },
  207. '&:after': {
  208. position: 'absolute',
  209. width: treeTitleHeight / 2 * 0.8,
  210. height: treeTitleHeight / 2,
  211. borderBottom: `1px solid ${token.colorBorder}`,
  212. content: '""'
  213. }
  214. }
  215. }),
  216. // >>> Checkbox
  217. [`${treeCls}-checkbox`]: {
  218. top: 'initial',
  219. marginInlineEnd: treeCheckBoxMarginHorizontal,
  220. marginBlockStart: treeCheckBoxMarginVertical
  221. },
  222. // >>> Title
  223. // add `${treeCls}-checkbox + span` to cover checkbox `${checkboxCls} + span`
  224. [`${treeCls}-node-content-wrapper, ${treeCls}-checkbox + span`]: {
  225. position: 'relative',
  226. zIndex: 'auto',
  227. minHeight: treeTitleHeight,
  228. margin: 0,
  229. padding: `0 ${token.paddingXS / 2}px`,
  230. color: 'inherit',
  231. lineHeight: `${treeTitleHeight}px`,
  232. background: 'transparent',
  233. borderRadius: token.borderRadius,
  234. cursor: 'pointer',
  235. transition: `all ${token.motionDurationMid}, border 0s, line-height 0s, box-shadow 0s`,
  236. '&:hover': {
  237. backgroundColor: token.controlItemBgHover
  238. },
  239. [`&${treeCls}-node-selected`]: {
  240. backgroundColor: token.controlItemBgActive
  241. },
  242. // Icon
  243. [`${treeCls}-iconEle`]: {
  244. display: 'inline-block',
  245. width: treeTitleHeight,
  246. height: treeTitleHeight,
  247. lineHeight: `${treeTitleHeight}px`,
  248. textAlign: 'center',
  249. verticalAlign: 'top',
  250. '&:empty': {
  251. display: 'none'
  252. }
  253. }
  254. },
  255. // https://github.com/ant-design/ant-design/issues/28217
  256. [`${treeCls}-unselectable ${treeCls}-node-content-wrapper:hover`]: {
  257. backgroundColor: 'transparent'
  258. },
  259. // ==================== Draggable =====================
  260. [`${treeCls}-node-content-wrapper`]: _extends({
  261. lineHeight: `${treeTitleHeight}px`,
  262. userSelect: 'none'
  263. }, getDropIndicatorStyle(prefixCls, token)),
  264. [`${treeNodeCls}.drop-container`]: {
  265. '> [draggable]': {
  266. boxShadow: `0 0 0 2px ${token.colorPrimary}`
  267. }
  268. },
  269. // ==================== Show Line =====================
  270. '&-show-line': {
  271. // ================ Indent lines ================
  272. [`${treeCls}-indent`]: {
  273. '&-unit': {
  274. position: 'relative',
  275. height: '100%',
  276. '&:before': {
  277. position: 'absolute',
  278. top: 0,
  279. insetInlineEnd: treeTitleHeight / 2,
  280. bottom: -treeNodePadding,
  281. borderInlineEnd: `1px solid ${token.colorBorder}`,
  282. content: '""'
  283. },
  284. '&-end': {
  285. '&:before': {
  286. display: 'none'
  287. }
  288. }
  289. }
  290. },
  291. // ============== Cover Background ==============
  292. [`${treeCls}-switcher`]: {
  293. background: 'transparent',
  294. '&-line-icon': {
  295. // https://github.com/ant-design/ant-design/issues/32813
  296. verticalAlign: '-0.15em'
  297. }
  298. }
  299. },
  300. [`${treeNodeCls}-leaf-last`]: {
  301. [`${treeCls}-switcher`]: {
  302. '&-leaf-line': {
  303. '&:before': {
  304. top: 'auto !important',
  305. bottom: 'auto !important',
  306. height: `${treeTitleHeight / 2}px !important`
  307. }
  308. }
  309. }
  310. }
  311. })
  312. };
  313. };
  314. // ============================ Directory =============================
  315. export const genDirectoryStyle = token => {
  316. const {
  317. treeCls,
  318. treeNodeCls,
  319. treeNodePadding
  320. } = token;
  321. return {
  322. [`${treeCls}${treeCls}-directory`]: {
  323. // ================== TreeNode ==================
  324. [treeNodeCls]: {
  325. position: 'relative',
  326. // Hover color
  327. '&:before': {
  328. position: 'absolute',
  329. top: 0,
  330. insetInlineEnd: 0,
  331. bottom: treeNodePadding,
  332. insetInlineStart: 0,
  333. transition: `background-color ${token.motionDurationMid}`,
  334. content: '""',
  335. pointerEvents: 'none'
  336. },
  337. '&:hover': {
  338. '&:before': {
  339. background: token.controlItemBgHover
  340. }
  341. },
  342. // Elements
  343. '> *': {
  344. zIndex: 1
  345. },
  346. // >>> Switcher
  347. [`${treeCls}-switcher`]: {
  348. transition: `color ${token.motionDurationMid}`
  349. },
  350. // >>> Title
  351. [`${treeCls}-node-content-wrapper`]: {
  352. borderRadius: 0,
  353. userSelect: 'none',
  354. '&:hover': {
  355. background: 'transparent'
  356. },
  357. [`&${treeCls}-node-selected`]: {
  358. color: token.colorTextLightSolid,
  359. background: 'transparent'
  360. }
  361. },
  362. // ============= Selected =============
  363. '&-selected': {
  364. [`
  365. &:hover::before,
  366. &::before
  367. `]: {
  368. background: token.colorPrimary
  369. },
  370. // >>> Switcher
  371. [`${treeCls}-switcher`]: {
  372. color: token.colorTextLightSolid
  373. },
  374. // >>> Title
  375. [`${treeCls}-node-content-wrapper`]: {
  376. color: token.colorTextLightSolid,
  377. background: 'transparent'
  378. }
  379. }
  380. }
  381. }
  382. };
  383. };
  384. // ============================== Merged ==============================
  385. export const genTreeStyle = (prefixCls, token) => {
  386. const treeCls = `.${prefixCls}`;
  387. const treeNodeCls = `${treeCls}-treenode`;
  388. const treeNodePadding = token.paddingXS / 2;
  389. const treeTitleHeight = token.controlHeightSM;
  390. const treeToken = mergeToken(token, {
  391. treeCls,
  392. treeNodeCls,
  393. treeNodePadding,
  394. treeTitleHeight
  395. });
  396. return [
  397. // Basic
  398. genBaseStyle(prefixCls, treeToken),
  399. // Directory
  400. genDirectoryStyle(treeToken)];
  401. };
  402. // ============================== Export ==============================
  403. export default genComponentStyleHook('Tree', (token, _ref) => {
  404. let {
  405. prefixCls
  406. } = _ref;
  407. return [{
  408. [token.componentCls]: getCheckboxStyle(`${prefixCls}-checkbox`, token)
  409. }, genTreeStyle(prefixCls, token), genCollapseMotion(token)];
  410. });