diff --git a/examples/sites/demos/apis/tree-menu.js b/examples/sites/demos/apis/tree-menu.js
index eb36cf68fb..180dc68fcf 100644
--- a/examples/sites/demos/apis/tree-menu.js
+++ b/examples/sites/demos/apis/tree-menu.js
@@ -342,6 +342,29 @@ export default {
mode: ['pc'],
pcDemo: 'show-expand'
},
+ {
+ name: 'expand-menu-popable',
+ type: 'boolean',
+ defaultValue: 'false',
+ desc: {
+ 'zh-CN': '启用一键展开/收起功能下。是否支持悬浮展示子菜单',
+ 'en-US':
+ 'when the one click expand/collapse function enabled. whether to support hovering to display submenus'
+ },
+ mode: ['pc'],
+ pcDemo: 'pop-sub-menu'
+ },
+ {
+ name: 'popper-class',
+ type: 'string',
+ defaultValue: '',
+ desc: {
+ 'zh-CN': '悬浮展示子菜单时,弹窗的类名',
+ 'en-US': 'when hovering to display submenus, the class name of the pop-up window'
+ },
+ mode: ['pc'],
+ pcDemo: 'pop-sub-menu'
+ },
{
name: 'show-filter',
type: 'boolean',
diff --git a/examples/sites/demos/pc/app/tree-menu/pop-sub-menu-composition-api.vue b/examples/sites/demos/pc/app/tree-menu/pop-sub-menu-composition-api.vue
new file mode 100644
index 0000000000..63c1d609c8
--- /dev/null
+++ b/examples/sites/demos/pc/app/tree-menu/pop-sub-menu-composition-api.vue
@@ -0,0 +1,123 @@
+
+
折叠模式下,支持弹出子菜单列表。
\n', + 'en-US': 'support pop sub menus when collapsed.
\n' + }, + codeFiles: ['pop-sub-menu.vue'] + }, { demoId: 'custom-icon', name: { diff --git a/packages/renderless/src/tree-menu/vue.ts b/packages/renderless/src/tree-menu/vue.ts index bdd89a6c6c..3edf0d9829 100644 --- a/packages/renderless/src/tree-menu/vue.ts +++ b/packages/renderless/src/tree-menu/vue.ts @@ -77,7 +77,7 @@ export const api = [ export const renderless = ( props: ITreeMenuProps, - { computed, watch, reactive, onMounted }: ISharedRenderlessFunctionParams, + { computed, watch, reactive, onMounted, provide }: ISharedRenderlessFunctionParams, { t, service, emit, vm }: ISharedRenderlessParamUtils ) => { service = service || { base: {} } @@ -128,6 +128,8 @@ export const renderless = ( computedTreeStyle: computedTreeStyle({ props }) }) + provide('tree-menu', vm) + watch( () => props.data, (value) => (state.data = value), diff --git a/packages/theme/src/tree-menu/index.less b/packages/theme/src/tree-menu/index.less index b1ff031518..32f6f3df9d 100644 --- a/packages/theme/src/tree-menu/index.less +++ b/packages/theme/src/tree-menu/index.less @@ -17,6 +17,8 @@ @tree-node-prefix-cls: ~'@{css-prefix}tree-node'; @input-prefix-cls: ~'@{css-prefix}input'; @tree-menu-prefix-cls: ~'@{css-prefix}tree-menu'; +@tree-pop-menu-prefix-cls: ~'@{css-prefix}tree-menu-pop-menu'; +@tree-pop-menu-panel-prefix-cls: ~'@{css-prefix}tree-menu-pop-menu-panel'; .@{tree-menu-prefix-cls} { .inject-TreeMenu-vars(); @@ -212,6 +214,7 @@ .tree-node-name { align-items: center; padding: 0 var(--tv-TreeMenu-node-body-text-padding-x); + display: flex; &:hover { font-weight: var(--tv-TreeMenu-node-name-hover-font-weight); @@ -220,6 +223,7 @@ svg { margin-right: var(--tv-TreeMenu-prefix-icon-margin-right); + flex-shrink: 0; } } } @@ -337,4 +341,73 @@ } } } + + .@{tree-pop-menu-prefix-cls} { + line-height: initial; + } +} + +.@{tree-pop-menu-panel-prefix-cls} { + .inject-TreeMenu-vars(); + padding: var(--tv-TreeMenu-pop-padding) !important; + border-radius: var(--tv-TreeMenu-pop-radius) !important; + box-shadow: var(--tv-TreeMenu-pop-shadow) !important; + width: var(--tv-TreeMenu-pop-width); + transform: translateX(var(--tv-TreeMenu-pop-panel-margin-left)); + + .tree-menu-pop-menu__list { + width: 100%; + + .tiny-tree-menu-pop-menu { + width: 100%; + } + + .reference-wrapper { + display: block; + } + + &-item { + width: 100%; + height: var(--tv-TreeMenu-pop-item-height); + display: flex; + align-items: center; + + .tree-node-name { + svg { + margin-right: var(--tv-TreeMenu-prefix-icon-margin-right); + } + } + + &.hover, + &:hover, + &:active { + background-color: var(--tv-TreeMenu-pop-item-active-bg); + color: var(--tv-TreeMenu-pop-item-active-text-color); + } + + &.has-current { + background-color: var(--tv-TreeMenu-pop-item-active-bg); + color: var(--tv-TreeMenu-pop-item-active-text-color); + } + + &.is-current { + background-color: var(--tv-TreeMenu-pop-item-selected-bg); + color: var(--tv-TreeMenu-pop-item-selected-text-color); + } + + .tree-node { + padding-left: var(--tv-TreeMenu-pop-item-padding-left); + display: flex; + align-items: center; + + &-body { + color: inherit; + } + } + } + } + + &__first { + transform: translateX(var(--tv-TreeMenu-pop-panel-first-margin-left)); + } } diff --git a/packages/theme/src/tree-menu/vars.less b/packages/theme/src/tree-menu/vars.less index 0757c18942..191ab87bcf 100644 --- a/packages/theme/src/tree-menu/vars.less +++ b/packages/theme/src/tree-menu/vars.less @@ -81,4 +81,29 @@ --tv-TreeMenu-node-body-selected-color: var(--tv-color-border-active, #191919); // hover字体颜色 --tv-TreeMenu-node-name-hover-color: var(--tv-color-border-hover, #191919); + + // 弹出面板 边距 + --tv-TreeMenu-pop-padding: var(--tv-space-base); + // 弹出面板 圆角 + --tv-TreeMenu-pop-radius: var(--tv-border-radius-sm); + // 弹出面板 圆角 + --tv-TreeMenu-pop-shadow: var(--tv-shadow-4-down); + // 弹出面板 菜单高度 + --tv-TreeMenu-pop-item-height: 36px; + // 弹出面板 宽度 + --tv-TreeMenu-pop-width: 160px; + // 弹出面板 菜单悬浮、激活背景 + --tv-TreeMenu-pop-item-active-bg: transparent; + // 弹出面板 菜单悬浮、激活文本色 + --tv-TreeMenu-pop-item-active-text-color: var(--tv-base-color-brand); + // 弹出面板 选中背景色 + --tv-TreeMenu-pop-item-selected-bg: transparent; + // 弹出面板 选中文本色 + --tv-TreeMenu-pop-item-selected-text-color: var(--tv-base-color-brand); + // 弹出面板 选中文本色 + --tv-TreeMenu-pop-item-padding-left: 16px; + // 弹出面板 左侧边距 + --tv-TreeMenu-pop-panel-margin-left: -2px; + // 弹出面板 第一层左侧边距 + --tv-TreeMenu-pop-panel-first-margin-left: -38px; } diff --git a/packages/vue/src/tree-menu/src/menu-node.vue b/packages/vue/src/tree-menu/src/menu-node.vue new file mode 100644 index 0000000000..f316c86c84 --- /dev/null +++ b/packages/vue/src/tree-menu/src/menu-node.vue @@ -0,0 +1,50 @@ + + + + +