tdesign-react
Version:
TDesign Component for React
448 lines (375 loc) • 9.61 kB
text/less
// 组件允许单个组件打包,因此默认引入公共基础样式
@import "../../base.less";
@import "./_var.less";
@import "./_mixin.less";
@import "../../mixins/_reset.less";
@import "../../mixins/_text.less";
// <name> 替换为组件名
.@{prefix}-tree {
.reset;
font: @tree-font;
color: @tree-node-text-color;
position: relative;
// 禁用态颜色处理
&.@{prefix}-is-disabled {
color: @tree-disabled-color;
.t-icon {
color: @tree-disabled-color;
}
.@{prefix}-tree__item {
&.@{prefix}-is-active {
background-color: @tree-node-bg-hover-color;
color: @tree-disabled-color;
}
.t-icon {
color: @tree-icon-disabled-color;
}
}
}
&__empty {
color: @tree-node-empty-text-color;
}
&__branch {
display: block;
}
&__item {
// 用于树结构缩进计算
--level: 0;
// 用于多行 label 计算高度
// 如果使用了多行 label 或者 label 内容高于 34px
// 业务方可以增大这个值来让高度动画完全伸展
// 值预期为 Math.max(实际最大高度 / 34, 1)
--hscale: 2;
will-change: opacity, max-height;
position: relative;
display: flex;
flex-wrap: nowrap;
align-items: center;
padding: 0 0 0 @tree-node-item-padding-left;
cursor: default;
transform: translateZ(0); // 开启硬件加速
backface-visibility: hidden; // 防止Chrome、Safari中,使用 transforms/animations,可能造成的页面闪烁
perspective: 1000; // 防止Chrome、Safari中,使用 transforms/animations,可能造成的页面闪烁
.t-icon,
.@{prefix}-loading {
display: inline-block;
position: relative;
z-index: 2;
font-size: @tree-node-icon-size;
}
.t-icon {
color: @tree-node-icon-color;
}
.@{prefix}-checkbox {
align-items: center;
font-size: 0;
&__input {
flex-shrink: 0;
}
&__label {
overflow: hidden;
text-overflow: ellipsis;
}
}
.@{prefix}-tree__icon--default {
.t-icon {
transform: rotate(0);
}
}
&--open {
.t-icon {
color: @tree-node-icon-active-color;
}
.@{prefix}-tree__icon--default {
.t-icon {
transform: rotate(90deg);
}
}
}
// 允许点击
&--clickable {
cursor: pointer;
}
// 过滤时被命中为路径节点
&--locked {
color: @tree-disabled-color;
}
// 过滤时被命中
&--matched {
color: inherit;
}
&--draggable {
cursor: pointer;
&:hover {
background-color: @tree-node-bg-hover-color;
background-clip: content-box;
}
&::after {
position: absolute;
top: -(@tree-node-drag-tip-height / 2);
right: 0;
left: 0;
display: block;
height: @tree-node-drag-tip-height;
border-radius: (@tree-node-drag-tip-height / 2);
content: "";
padding: inherit;
background-clip: content-box;
}
}
&--tip {
&-top::after {
background-color: @tree-node-drag-tip-bg;
}
&-bottom::after {
top: unset;
bottom: -(@tree-node-drag-tip-height / 2);
background-color: @tree-node-drag-tip-bg;
}
&-highlight {
background-color: @tree-node-drag-bg-highlight;
background-clip: content-box;
}
}
}
// 用于撑开节点高度
// 比起使用 padding , 更有利于动画展现
&__item::before {
content: "";
display: block;
width: 0;
flex: 0 0 auto;
height: @tree-node-item-height;
}
&--block-node &__label {
flex: 1;
}
&--hoverable &__label:not(.@{prefix}-is-active):not(.@{prefix}-is-checked):hover {
background-color: @tree-node-bg-hover-color;
}
&__line {
--level: 0;
--color: @tree-node-icon-line-color;
--space: @tree-node-padding-basic;
--iconSize: @icon-default;
position: absolute;
left: @tree-line-position-left;
bottom: @tree-line-position-bottom;
width: @tree-line-width;
height: @tree-node-item-height;
pointer-events: none;
}
&__line::before {
content: "";
position: absolute;
bottom: 0;
left: 0;
display: block;
height: @tree-node-item-height;
width: @tree-line-before-width;
border-left: 1px solid var(--color);
border-bottom: 1px solid var(--color);
}
&__line--first::before {
height: @tree-line-first-height;
}
&__line--leaf::before {
width: @tree-line-leaf-width;
}
// 默认图标
&__icon {
position: relative;
flex: none;
display: inline-flex;
align-items: center;
// 图标居中
text-align: center;
width: @tree-node-icon-size;
// 当子元素只有一个且为image类型时,会有隐藏占位,因此将font-size设0
font-size: 0;
user-select: none;
cursor: pointer;
}
// svg 动画与 icon 背景进行隔离
// :after 仅用于增大点击范围
&__icon::after {
content: "";
display: block;
position: absolute;
left: -2px;
top: -2px;
width: calc(@tree-node-icon-size + 4px);
height: calc(@tree-node-icon-size + 4px);
border-radius: @border-radius-default;
}
// 仅在有图标时呈现背景
// 注意这里背景样式不要加给 ::after
// ::after 仅用于增大点击范围
&__icon:not(:empty):hover {
background-color: @tree-node-bg-hover-color;
}
// 没有图标时不呈现指针
&__icon:empty {
cursor: initial;
}
&__label {
--ripple-color: @bg-color-container-active;
flex-wrap: nowrap;
// resoved style issues of tree component does not handle content exceedance
flex: 1;
padding: @tree-label-padding;
margin-left: @tree-label-margin-left;
border-radius: @border-radius-default;
cursor: pointer;
.text-ellipsis();
&.@{prefix}-is-checked {
font-weight: 500;
color: @tree-node-text-active-color;
background-color: @tree-node-bg-active-color;
}
&::selection {
background-color: transparent;
}
}
.@{prefix}-is-active &__label {
font-weight: 500;
color: @tree-node-text-active-color;
background-color: @tree-node-bg-active-color;
}
&__space {
display: block;
flex: 1 0 auto;
}
&__operations {
display: flex;
flex: 0 0 auto;
justify-content: flex-end;
align-items: center;
margin-left: auto;
}
&__operations .t-icon {
cursor: pointer;
}
&__item.@{prefix}-is-disabled {
color: @tree-disabled-color;
cursor: default;
.@{prefix}-checkbox {
cursor: default;
}
}
}
.@{prefix}-tree {
&__item--hidden {
display: none;
}
}
// 节点动画
.@{prefix}-tree--transition {
// 标签动画
.@{prefix}-tree__label {
transition: background-color @anim-duration-moderate @anim-time-fn-easing;
}
// 默认图标
.@{prefix}-tree__icon {
transition: color, transform @anim-duration-moderate @anim-time-fn-easing;
}
.@{prefix}-tree__icon::after {
transition: @anim-duration-base linear;
}
.@{prefix}-tree__icon:not(:empty):hover {
transition: @anim-duration-base linear;
}
// 图标动画
.@{prefix}-tree__icon--default {
.t-icon {
transition: color, transform @anim-time-fn-easing @anim-duration-base;
}
}
// 节点展示动画
.@{prefix}-tree__item--visible {
display: flex;
max-height: @tree-node-item-origin-height;
opacity: 1;
transition: opacity @tree-node-transition-time linear
@tree-node-transition-time,
max-height @tree-node-transition-time linear 0s;
}
// 节点隐藏动画
.@{prefix}-tree__item--hidden {
display: flex;
max-height: 0;
opacity: 0;
overflow: hidden;
pointer-events: none;
user-select: none;
animation: initial;
transition: opacity @tree-node-transition-time linear 0s,
max-height @tree-node-transition-time linear @tree-node-transition-time;
}
// 节点插入动画
.@{prefix}-tree__item--enter-active {
animation: t-tree-toggle @tree-node-animation-time linear;
}
// 节点移除动画
.@{prefix}-tree__item--leave-active {
animation: t-tree-toggle @tree-node-animation-time reverse linear forwards;
}
}
// 虚拟滚动样式
.@{prefix}-tree__vscroll {
overflow-y: auto;
}
// 虚拟滚动延迟加载模式
.@{prefix}-tree__lazyload {
overflow-y: auto;
}
// 虚拟滚动游标
.@{prefix}-tree__vscroll-cursor {
position: absolute;
width: 1px;
height: 1px;
transition: transform @anim-duration-base;
}
.@{prefix}-tree--scrolling {
.@{prefix}-tree__item {
will-change: initial;
}
.v-enter,
.v-leave,
.@{prefix}-tree__item--visible,
.@{prefix}-tree__item--hidden,
.@{prefix}-tree__item--enter,
.@{prefix}-tree__item--enter-active,
.@{prefix}-tree__item--enter-to,
.@{prefix}-tree__item--leave,
.@{prefix}-tree__item--leave-active
.@{prefix}-tree__item--leave-to {
animation: none;
transition: none;
}
.@{prefix}-tree__item--visible {
max-height: initial;
}
.@{prefix}-tree__item--enter-to,
.@{prefix}-tree__item--enter-active {
max-height: initial;
}
.@{prefix}-tree__item--leave-to,
.@{prefix}-tree__item--leave-active {
max-height: 0;
}
}
@keyframes t-tree-toggle {
0% {
opacity: 0;
max-height: 0;
}
50% {
opacity: 0;
max-height: @tree-node-item-origin-height;
}
100% {
opacity: 1;
max-height: @tree-node-item-origin-height;
}
}