diff --git a/devui/tree/src/composables/use-toggle.ts b/devui/tree/src/composables/use-toggle.ts index 542ba2630ccf998b73a5d66aabbcb9b38a3ac672..f248002490ebde4fd7dd3f1b44fb78860ba95998 100644 --- a/devui/tree/src/composables/use-toggle.ts +++ b/devui/tree/src/composables/use-toggle.ts @@ -12,7 +12,8 @@ export default function useToggle(data: unknown): any { const openedData = ref(openedTree(data)) const toggle = (item) => { - console.log('toggle', item, item.id, item.open); + if (!item.children) return + item.open = !item.open openedData.value = openedTree(data) } diff --git a/devui/tree/src/tree.scss b/devui/tree/src/tree.scss index 84bcb33768b94b19c67558b4713a2349fc391093..113b3e35072c851f45a22b927d5ba544ad8888a6 100644 --- a/devui/tree/src/tree.scss +++ b/devui/tree/src/tree.scss @@ -1,3 +1,306 @@ -.devui-tree { - // +@import '../../style/theme/color'; +@import '../../style/theme/variables'; +@import '../../style/mixins/index'; +@import '../../style/theme/corner'; +@import '../../style/core/_font'; +@import '../../style/core/animation'; + +$keyframe-blue: #5e7ce0; + +.devui-text-ellipsis { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} + +.devui-tree-node { + color: $devui-text-weak; + line-height: 1.5; + white-space: nowrap; + position: relative; + + .devui-tree-node__content { + display: inline-flex; + align-items: center; + font-size: $devui-font-size; + padding-right: 10px; + width: 100%; + border-radius: $devui-border-radius; + padding-left: 6px; + + &.active { + background-color: $devui-list-item-selected-bg; + text-decoration: none; + border-color: transparent; + } + + &:not(.active):hover { + background-color: $devui-list-item-hover-bg; + } + } + + .devui-tree-node__content--value-wrapper { + display: inline-flex; + align-items: center; + height: 30px; + width: 100%; + } + + .devui-tree-node__children { + padding-left: 10px; + + &:first-child { + border-left-color: transparent; + } + + .devui-tree-node { + margin-left: 8px; + content: ''; + position: relative; + + &:last-child { + border-left-color: transparent; + } + } + } + + .devui-tree-node__title { + @extend .devui-text-ellipsis; + + margin-left: 5px; + display: inline-block; + border: 1px dashed transparent; + border-radius: $devui-border-radius; + max-width: 100%; + + &:not(.disabled) { + cursor: pointer; + } + } + + .devui-tree-node__edit { + margin-left: 0.4em; + padding: 0.1em; + + > .devui-input-sm { + height: 26px; + + &.error, + &.error:hover, + &.error:focus { + border-color: $devui-danger; + } + } + } + + .devui-tree-node__leaf { + &:not(.disabled) { + cursor: default; + } + + .devui-tree-node__leaf--default { + color: #f2a71f; + } + + .devui-leaf-icon-none { + display: inline-block; + width: 16px; + height: 16px; + } + } + + .devui-tree-node__folder { + display: inline-block; + vertical-align: middle; + user-select: none; + font-size: $devui-font-size-icon; + height: 16px; + line-height: 16px; + + .devui-tree-node__folder--icon { + display: inline-block; + height: 16px; + line-height: 16px; + + &:hover { + svg g path { + fill: $devui-icon-fill-active; + } + + svg g rect { + stroke: $devui-icon-fill-active; + } + } + } + + &:not(.disabled) { + cursor: pointer; + } + + .devui-tree-node__folder--default { + color: #f2b806; + } + } + + .devui-loading-children { + display: inline-block; + vertical-align: middle; + margin-left: 0.5em; + margin-top: 0.15em; + color: $devui-info; + font-style: italic; + font-size: 1em; + animation-name: devui-loading-children; + animation-duration: 2s; + animation-timing-function: ease-in-out; + animation-iteration-count: infinite; + } + @keyframes devui-loading-children { + 0% { + color: lighten($keyframe-blue, 0.95); + } + + 12.5% { + color: lighten($keyframe-blue, 0.85); + } + + 25% { + color: lighten($keyframe-blue, 0.75); + } + + 37.5% { + color: lighten($keyframe-blue, 0.65); + } + + 50% { + color: lighten($keyframe-blue, 0.55); + } + + 62.5% { + color: lighten($keyframe-blue, 0.45); + } + + 75% { + color: lighten($keyframe-blue, 0.35); + } + + 87.5% { + color: lighten($keyframe-blue, 0.1); + } + + 100% { + color: $keyframe-blue; + } + } + + svg.svg-icon path { + fill: $devui-icon-text; + } + + svg.svg-icon rect { + stroke: $devui-icon-text; + } + + &.devui-tree-node__open:not(.devui-tree-node__customIcon) { + & > .devui-tree-node__content svg.svg-icon path { + fill: $devui-icon-fill-active; + } + + & > .devui-tree-node__content svg.svg-icon rect { + stroke: $devui-icon-fill-active; + } + + & > .devui-tree-node__content svg.svg-icon.svg-icon-close rect:last-child { + stroke: none; + fill: $devui-icon-fill-active; + } + } + + svg.svg-icon.svg-icon-close rect:last-child { + stroke: none; + fill: $devui-icon-text; + } +} + +::ng-deep .devui-tree-mask { + background: $devui-list-item-hover-bg; +} + +/* 视觉融合灰线 */ +.devui-tree-node.devui-tree-without-virtual-scroll { + &.devui-tree-node__open { + & > .devui-tree-node__content { + position: relative; + } + } + + & > .devui-tree-node__children { + position: relative; + + &::before { + content: ''; + width: 1px; + height: calc(100% - 15px); // 父级总高度减去半个content的高度 + background-color: $devui-dividing-line; + position: absolute; + left: calc(10px - 1px); // 父级10px的padding减去自身1px宽度 + top: 0; + } + + .devui-tree-node__content { + // 只要是子级就都存在左边横线 + position: relative; + + &::before { + content: ''; + width: 8px; + height: 1px; + background-color: $devui-dividing-line; + position: absolute; + left: calc(-1px - 8px); // 对接左侧灰线,自身margin为1.2em加上1px的线宽 + top: 50%; + } + } + } +} + +.devui-tree-vertical-line { + width: 1px; + background-color: $devui-dividing-line; + position: absolute; +} + +.devui-tree-horizontal-line { + height: 1px; + background-color: $devui-dividing-line; + position: absolute; + top: 50%; + margin-left: -16px; +} + +.toggle-disabled { + cursor: not-allowed !important; + + svg.svg-icon rect { + stroke: $devui-disabled-text !important; + } + + svg.svg-icon.svg-icon-close rect:last-child { + stroke: none !important; + fill: $devui-disabled-text !important; + } + + svg.svg-icon path { + fill: $devui-disabled-text !important; + } +} + +.select-disabled { + color: $devui-disabled-text !important; + cursor: not-allowed !important; + background-color: transparent !important; +} + +.devui-tree-node__content { + transition: color $devui-animation-duration-fast $devui-animation-ease-in-smooth, background-color $devui-animation-duration-fast $devui-animation-ease-in-smooth; } diff --git a/devui/tree/src/tree.tsx b/devui/tree/src/tree.tsx index 99b4fcccac9de305baeac11d50856fd1f6623edb..bae27917e2c810023fcd47c70f3fd30798cd08f6 100644 --- a/devui/tree/src/tree.tsx +++ b/devui/tree/src/tree.tsx @@ -23,21 +23,26 @@ export default defineComponent({ const renderNode = (item) => { return (
toggle(item)} > - { - item.children - ? item.open ? : - : - } - { item.label } +
+
+ { + item.children + ? item.open ? : + : + } + { item.label } +
+
) } const renderTree = (tree) => { + return tree.map(item => { if (!item.children) { return renderNode(item) diff --git a/docs/components/tree/data.ts b/docs/components/tree/data.ts deleted file mode 100644 index c47ddfb16aad01726ac4f747d829f4e1ae5ce4f4..0000000000000000000000000000000000000000 --- a/docs/components/tree/data.ts +++ /dev/null @@ -1,35 +0,0 @@ -export default [{ - label: '一级 1', - children: [{ - label: '二级 1-1', - children: [{ - label: '三级 1-1-1' - }] - }] -}, { - label: '一级 2', - children: [{ - label: '二级 2-1', - children: [{ - label: '三级 2-1-1' - }] - }, { - label: '二级 2-2', - children: [{ - label: '三级 2-2-1' - }] - }] -}, { - label: '一级 3', - children: [{ - label: '二级 3-1', - children: [{ - label: '三级 3-1-1' - }] - }, { - label: '二级 3-2', - children: [{ - label: '三级 3-2-1' - }] - }] -}]; diff --git a/docs/components/tree/index.md b/docs/components/tree/index.md index 2369be78032a4260ef7e036166488503071a022f..5b76cc1b562d89dab310596ce3bffa646020270a 100644 --- a/docs/components/tree/index.md +++ b/docs/components/tree/index.md @@ -17,41 +17,149 @@ import { defineComponent, ref } from 'vue' export default defineComponent({ setup() { - const data = ref([{ - label: '一级 1', - children: [{ - label: '二级 1-1', - children: [{ - label: '三级 1-1-1' - }] - }] - }, { - label: '一级 2', - children: [{ - label: '二级 2-1', - children: [{ - label: '三级 2-1-1' - }] - }, { - label: '二级 2-2', - children: [{ - label: '三级 2-2-1' - }] - }] - }, { - label: '一级 3', - children: [{ - label: '二级 3-1', - children: [{ - label: '三级 3-1-1' - }] - }, { - label: '二级 3-2', - children: [{ - label: '三级 3-2-1' - }] - }] - }]) + const data = ref([ + { + label: 'parent node 1 - expanded', + open: true, + disabled: true, + level: 1, + children: [ + { + label: 'parent node 11 - folded', + level: 2, + children: [ + { + label: 'leaf node 111', + level: 3, + }, + { + label: 'leaf node 112', + level: 3, + }, + { + label: 'leaf node 113', + level: 3, + }, + { + label: 'leaf node 114', + level: 3, + } + ] + }, + { + label: 'parent node 12 - folded', + disableToggle: true, + level: 2, + children: [ + { + label: 'leaf node 121', + level: 3, + }, + { + label: 'leaf node 122', + level: 3, + }, + { + label: 'leaf node 123', + level: 3, + }, + { + label: 'leaf node 124', + level: 3, + } + ] + }, + { + label: 'parent node 13 - without children - dynamic loading', + isParent: true, + level: 2, + } + ] + }, + { + label: 'parent node 2 - folded', + level: 1, + children: [ + { + label: 'parent node 21 - expanded', + open: true, + level: 2, + children: [ + { + label: 'leaf node 211', + level: 3, + }, + { + label: 'leaf node 212', + level: 3, + }, + { + label: 'leaf node 213', + level: 3, + }, + { + label: 'leaf node 214', + level: 3, + } + ] + }, + { + label: 'parent node 22 - folded', + level: 2, + children: [ + { + label: 'leaf node 221', + level: 3, + }, + { + label: 'leaf node 222', + level: 3, + }, + { + label: 'leaf node 223', + level: 3, + }, + { + label: 'leaf node 224', + level: 3, + } + ] + }, + { + label: 'parent node 23 - folded', + level: 2, + children: [ + { + label: 'leaf node 231', + level: 3, + }, + { + label: 'leaf node 232', + level: 3, + }, + { + label: 'leaf node 233', + level: 3, + }, + { + label: 'leaf node 234', + level: 3, + } + ] + } + ] + }, + { + id: 'dynamicNode', + label: 'parent node 3 - without children - dynamic loading', + isParent: true, + level: 1, + data: { + id: 'newChildNode', + name: 'new child node' + } + } + ]) return { data