Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(comp:menu): add overlayDelay prop and menu item support custom suffix #1300

Merged
merged 1 commit into from
Nov 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
.@{collapse-transition-prefix} {

&-enter-active,
&-leave-active {
overflow: hidden;
transition: height @transition-duration-base @ease-in-out, width @transition-duration-base @ease-in-out,
opacity @transition-duration-base @ease-in-out;
transition: height var(--ix-transition-duration-medium) var(--ix-ease-in-out),
width var(--ix-transition-duration-medium) var(--ix-ease-in-out),
opacity var(--ix-transition-duration-medium) var(--ix-ease-in-out);
}
}
4 changes: 2 additions & 2 deletions packages/components/config/src/defaultConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,8 @@ export const defaultConfig: GlobalConfig = {
},
menu: {
getKey: 'key',
indent: 24,
offset: [0, 4],
indent: 16,
offset: [0, 8],
suffix: 'right',
theme: 'light',
},
Expand Down
2 changes: 1 addition & 1 deletion packages/components/config/src/seerConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const seerConfig: DeepPartialGlobalConfig = {
labelAlign: 'start',
},
menu: {
indent: 16,
offset: [0, 4],
},
modal: {
centered: true,
Expand Down
2 changes: 0 additions & 2 deletions packages/components/dropdown/style/index.less
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
}

.@{menu-prefix} {
border-radius: @dropdown-overlay-border-radius;

&&-dropdown {
&.@{menu-prefix}-vertical,
&.@{menu-prefix}-inline {
Expand Down
16 changes: 11 additions & 5 deletions packages/components/menu/__tests__/__snapshots__/menu.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@

exports[`Menu > render work 1`] = `
"<ul class=\\"ix-menu ix-menu-light ix-menu-vertical\\">
<li class=\\"ix-menu-item\\" aria-selected=\\"false\\" role=\\"menuitem\\"><i class=\\"ix-icon ix-icon-home\\" role=\\"img\\" aria-label=\\"home\\"></i><span><a>Item 1</a></span></li>
<li class=\\"ix-menu-item\\" aria-label=\\"Item 2\\" aria-selected=\\"false\\" role=\\"menuitem\\"><i class=\\"ix-icon ix-icon-mail\\" role=\\"img\\" aria-label=\\"mail\\"></i><span>Item 2</span></li>
<li class=\\"ix-menu-item ix-menu-item-disabled\\" aria-label=\\"Item 3\\" aria-selected=\\"false\\" role=\\"menuitem\\"><i class=\\"ix-icon ix-icon-appstore\\" role=\\"img\\" aria-label=\\"appstore\\"></i><span>Item 3</span></li>
<li class=\\"ix-menu-item ix-menu-level-1\\" aria-selected=\\"false\\" role=\\"menuitem\\"><i class=\\"ix-icon ix-icon-home\\" role=\\"img\\" aria-label=\\"home\\"></i><span><a>Item 1</a></span>
<!---->
</li>
<li class=\\"ix-menu-item ix-menu-level-1\\" aria-label=\\"Item 2\\" aria-selected=\\"false\\" role=\\"menuitem\\"><i class=\\"ix-icon ix-icon-mail\\" role=\\"img\\" aria-label=\\"mail\\"></i><span>Item 2</span>
<!---->
</li>
<li class=\\"ix-menu-item ix-menu-level-1 ix-menu-item-disabled\\" aria-label=\\"Item 3\\" aria-selected=\\"false\\" role=\\"menuitem\\"><i class=\\"ix-icon ix-icon-appstore\\" role=\\"img\\" aria-label=\\"appstore\\"></i><span>Item 3</span>
<!---->
</li>
<li class=\\"ix-menu-divider\\"></li>
<li class=\\"ix-menu-sub ix-menu-sub-vertical\\" aria-expanded=\\"false\\" aria-haspopup=\\"true\\" role=\\"menuitem\\">
<li class=\\"ix-menu-sub ix-menu-level-1\\" aria-expanded=\\"false\\" aria-haspopup=\\"true\\" role=\\"menuitem\\">
<div class=\\"ix-menu-sub-label\\"><i class=\\"ix-icon ix-icon-setting\\" role=\\"img\\" aria-label=\\"setting\\"></i><span>Sub Menu 1</span><span class=\\"ix-menu-sub-label-suffix\\"><i class=\\"ix-icon ix-icon-right\\" style=\\"transform: rotate(0deg);\\" role=\\"img\\" aria-label=\\"right\\"></i></span></div>
<!---->
</li>
<li class=\\"ix-menu-sub ix-menu-sub-disabled ix-menu-sub-vertical\\" aria-expanded=\\"false\\" aria-haspopup=\\"true\\" role=\\"menuitem\\">
<li class=\\"ix-menu-sub ix-menu-level-1 ix-menu-sub-disabled\\" aria-expanded=\\"false\\" aria-haspopup=\\"true\\" role=\\"menuitem\\">
<div class=\\"ix-menu-sub-label\\"><i class=\\"ix-icon ix-icon-github\\" role=\\"img\\" aria-label=\\"github\\"></i><span>Menu Sub 4</span><span class=\\"ix-menu-sub-label-suffix\\"><i class=\\"ix-icon ix-icon-right\\" style=\\"transform: rotate(0deg);\\" role=\\"img\\" aria-label=\\"right\\"></i></span></div>
<!---->
</li>
Expand Down
12 changes: 11 additions & 1 deletion packages/components/menu/demo/StateSwitching.vue
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,21 @@ const dataSource: MenuData[] = [
key: 'sub4',
icon: 'github',
label: 'Menu Sub 4',
disabled: true,
children: [
{ key: 'item10', label: 'Item 10' },
{ key: 'item11', label: 'Item 11' },
],
},
{
type: 'sub',
key: 'sub5',
icon: 'gitlab',
label: 'Menu Sub 5',
disabled: true,
children: [
{ key: 'item12', label: 'Item 12' },
{ key: 'item13', label: 'Item 13' },
],
},
]
</script>
7 changes: 5 additions & 2 deletions packages/components/menu/docs/Api.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
| `customAdditional` | 自定义下拉选项的额外属性 | `MenuCustomAdditional` | - | - | 例如 `class`, 或者原生事件 |
| `dataSource` | 菜单数据数组 | `MenuData[]` | - | - | 优先级高于 `default` 插槽 |
| `getKey` | 获取数据的唯一标识 | `string \| (data: MenuData) => VKey` | `key` | ✅ | - |
| `indent` | `inline` 模式时的菜单缩进宽度 | `string \| number` | `24` | ✅ | `seer` 主题下默认为 `16` |
| `indent` | `inline` 模式时的菜单缩进宽度 | `string \| number` | `16` | ✅ | - |
| `mode` | 菜单模式,现在支持垂直、水平和内嵌 | `'vertical' \| 'horizontal' \| 'inline'` | `'vertical'` | - | - |
| `multiple` | 是否支持多选 | `boolean` | `false` | - | - |
| `overlayClassName` | 悬浮层的自定义 `class` | `string` | - | - | `inline` 模式时无效 |
| `overlayContainer` | 自定义菜单容器节点 | `string \| HTMLElement \| () => string \| HTMLElement` | - | ✅ | `inline` 模式时无效 |
| `overlayDelay` | 浮层的打开和关闭延迟 | `number \| [number | null, number | null]` | `[0, 100]` | - | 为数组时,第一个元素是延迟显示的时间,第二个元素是延迟隐藏的时间 |
| `selectable` | 是否允许选中 | `boolean` | `true` | - | - |
| `theme` | 主题颜色 | `'light' \| 'dark'` | `'light'` | ✅ | - |
| `onClick` | 点击菜单后的回调 | `(options: MenuClickOptions) => void` | - | - |
Expand All @@ -41,8 +42,10 @@ export type MenuCustomAdditional = (options: { data: MenuData; index: number })
| `disabled` | 是否禁用 | `boolean` | - | - | - |
| `icon` | 菜单图标| `string \| VNode` | - | - |
| `label` | 菜单文本 | `string` | - | - |
| `suffix` | 后缀图标 | `string` | - | - | - |
| `customIcon` | 自定义图标 | `string \| ((data: MenuItemProps & { selected: boolean }) => VNodeChild)` | `'itemIcon'` | - | 类型为 `string` 时,对应插槽名 |
| `customLabel` | 自定义文本 | `string \| ((data: MenuItemProps & { selected: boolean }) => VNodeChild)` | `'itemLabel'` | - | 类型为 `string` 时,对应插槽名 |
| `customSuffix` | 自定义文本 | `string \| ((data: MenuItemProps & { selected: boolean }) => VNodeChild)` | `'itemLabel'` | - | 类型为 `string` 时,对应插槽名 |

#### MenuItemGroupProps

Expand All @@ -67,7 +70,7 @@ export type MenuCustomAdditional = (options: { data: MenuData; index: number })
| `icon` | 菜单图标| `string \| VNode` | - | - |
| `label` | 菜单文本 | `string` | - | - |
| `offset` | 浮层偏移量 | `[number, number]` | `[0, 4]` | ✅ | `inline` 模式时无效 |
| `suffix` | 后缀图标 | `string` | `right` | ✅ | - |
| `suffix` | 后缀图标 | `string` | `right` | ✅ | `horizontal` 模式下全局配置不生效 |
| `customIcon` | 自定义图标 | `string \| ((data: MenuSubProps & { expanded: boolean; selected: boolean }) => VNodeChild)` | `'subIcon'` | - | 类型为 `string` 时,对应插槽名 |
| `customLabel` | 自定义文本 | `string \| ((data: MenuSubProps & { expanded: boolean; selected: boolean }) => VNodeChild)` | `'subLabel'` | - | 类型为 `string` 时,对应插槽名 |
| `customSuffix` | 自定义后缀图标 | `string \| ((data: MenuSubProps & { expanded: boolean; selected: boolean }) => VNodeChild)` | `'subSuffix'` | - | 类型为 `string` 时,对应插槽名 |
Expand Down
2 changes: 1 addition & 1 deletion packages/components/menu/docs/Index.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ category: components
type: 导航
title: Menu
subtitle: 导航菜单
order: 0
theme: true
---

60 changes: 26 additions & 34 deletions packages/components/menu/docs/Theme.zh.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,31 @@
| 名称 | default | seer | 备注 |
| --- | --- | --- | --- |
| `@menu-text-color` | `@text-color` | - | - |
| `@menu-background-color` | `@background-color-component` | - | - |
| `@menu-highlight-color` | `@color-primary` | - | - |
| `@menu-highlight-background-color` | `~colorPalette('@{color-primary}', -50) ` | - | - |
| `@menu-disabled-color` | `@disabled-color` | - | - |
| `@menu-disabled-background-color` | `transparent` | - | - |
| `@menu-border-width` | `@border-width-sm` | - | - |
| `@menu-border-style` | `@border-style` | - | - |
| `@menu-border-color` | `@border-color-split` | - | - |
| `@menu-font-size` | `@font-size-md` | - | - |
| `@menu-vertical-padding` | `4px 8px` | - | - |
| `@menu-vertical-font-size` | `@font-size-md` | - | - |
| `@menu-item-height` | `@height-lg` | `44px` | - |
| `@menu-item-padding-left` | `@spacing-md` | - | - |
| `@menu-item-padding-right` | `@spacing-xl` | - | - |
| `@menu-item-margin` | `@spacing-xs 0` | - | - |
| `@menu-item-icon-margin-right` | `@spacing-sm` | - | - |
| `@menu-item-border-right-width` | `@border-width-lg` | - | - |
| `@menu-item-border-bottom-width` | `@border-width-md` | - | - |
| `@menu-item-group-text-color` | `@text-color-secondary` | - | - |
| `@menu-item-group-content-padding-left` | `@spacing-xl` | - | - |
| `@menu-item-horizontal-padding` | `0 @spacing-xs` | - | - |
| `@menu-item-divider-margin` | `@spacing-xs` | - | - |
| `@menu-sub-suffix-icon-right` | `8px` | - | - |
| `@menu-text-color` | `var(--ix-text-color)` | - | - |
| `@menu-text-color-hover` | `var(--ix-text-color)` | - | - |
| `@menu-text-color-active` | `var(--ix-color-primary)` | - | - |
| `@menu-text-color-disabled` | `var(--ix-text-color-disabled)` | - | - |
| `@menu-background-color` | `var(--ix-background-color)` | - | - |
| `@menu-background-color-hover` | `var(--ix-background-color-middle)` | - | - |
| `@menu-background-color-active` | `var(--ix-color-primary-l50)` | - | - |
| `@menu-background-color-disabled` | `var(--ix-background-color)` | - | - |
| `@menu-horizontal-background-color-active` | `var(--ix-background-color-light)` | - | - |
| `@menu-border-color` | `var(--ix-border-color)` | - | - |
| `@menu-height` | `var(--ix-height-md)` | `36px` | - |
| `@menu-border-radius` | `var(--ix-border-radius-md)` | `0` | - |
| `@menu-font-size` | `var(--ix-font-size-md)` | `var(--ix-font-size-sm)` | - |
| `@menu-icon-font-size` | `var(--ix-font-size-lg)` | - | - |
| `@menu-item-group-text-color` | `var(--ix-text-color-info)` | - | - |
| `@menu-overlay-min-width` | `128px` | - | - |
| `@menu-overlay-border-radius` | `@border-radius-md` | `@border-radius-sm` | - |
| `@menu-overlay-box-shadow` | `@shadow-bottom-md` | - | - |
| `@menu-dark-disabled-color` | `@disabled-color-dark` | - | - |
| `@menu-dark-color` | `@text-color-dark` | `@color-graphite-l30` | - |
| `@menu-dark-background-color` | `@background-color-component-dark` | `@color-graphite-d40` | - |
| `@menu-dark-highlight-background-color` | `fade(@color-white, 6%)` | `@color-graphite-d30` | - |
| `@menu-dark-highlight-color` | `@color-primary` | `@color-graphite-l30` | - |
| `@menu-dark-group-label-color` | `@color-graphite-d10` | - | - |
| `@menu-collapsed-font-size` | `@font-size-lg` | - | - |
| `@menu-collapsed-width` | `64px` | `44px` | - |
| `@menu-sub-inline-font-size` | `@font-size-md` | - | - |
| `@menu-icon-font-size` | `@font-size-lg` | - | - |
| `@menu-collapsed-width` | `48px` | `44px` | - |
| `@menu-dark-text-color` | `var(--ix-text-color-inverse)` | - | - |
| `@menu-dark-text-color-hover` | `var(--ix-color-primary)` | `var(--ix-text-color-inverse)` | - |
| `@menu-dark-text-color-active` | `var(--ix-color-primary)` | `var(--ix-text-color-inverse)` | - |
| `@menu-dark-text-color-disabled` | `var(--ix-text-color-inverse-disabled)` | - | - |
| `@menu-dark-background-color` | `var(--ix-background-color-inverse)` | - | - |
| `@menu-dark-background-color-hover` | `transparent` | `@color-graphite-d50` | - |
| `@menu-dark-background-color-active` | `@color-black` | `var(--ix-color-primary)` | - |
| `@menu-dark-background-color-disabled` | `transparent` | - | - |
| `@menu-dark-horizontal-background-color-active` | `@color-grey-d30` | `@color-graphite-d30` | - |
| `@menu-dark-item-group-text-color` | `@color-grey-d10` | `@color-graphite-d10` | - |
17 changes: 11 additions & 6 deletions packages/components/menu/src/contents/MenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,20 @@ export default defineComponent({
} = inject(menuToken)!
const menuSubContext = inject(menuSubToken, null)
const menuItemGroupContext = inject(menuItemGroupToken, false)
const level = menuSubContext ? menuSubContext.level + 1 : 1

const isSelected = computed(() => selectedKeys.value.includes(key))

const classes = computed(() => {
const prefixCls = `${mergedPrefixCls.value}-item`
const prefixCls = mergedPrefixCls.value
return normalizeClass({
[prefixCls]: true,
[`${prefixCls}-disabled`]: props.data.disabled,
[`${prefixCls}-selected`]: isSelected.value,
[`${prefixCls}-item`]: true,
[`${prefixCls}-level-${level}`]: true,
[`${prefixCls}-item-disabled`]: props.data.disabled,
[`${prefixCls}-item-selected`]: isSelected.value,
})
})

const level = menuSubContext ? menuSubContext.level + 1 : 1
const mode = computed(() => menuProps.mode)
const paddingLeft = usePaddingLeft(menuProps, mode, indent, level, menuItemGroupContext)
const style = computed(() => {
Expand All @@ -60,19 +61,22 @@ export default defineComponent({
}

return () => {
const { disabled, icon, label, customIcon, customLabel } = props.data
const { disabled, icon, label, customIcon, customLabel, customSuffix } = props.data

const iconRender = customIcon ?? 'itemIcon'
const iconSlot = isString(iconRender) ? menuSlots[iconRender] : iconRender
const labelRender = customLabel ?? 'itemLabel'
const labelSlot = isString(labelRender) ? menuSlots[labelRender] : labelRender
const suffixRender = customSuffix ?? 'itemSuffix'
const suffixSlot = isString(suffixRender) ? menuSlots[suffixRender] : suffixRender

const slotProps = iconSlot || labelSlot ? { ...props.data, selected: isSelected.value } : undefined
const iconNode = coverIcon(iconSlot, slotProps!, icon)
const labelNode = labelSlot ? labelSlot(slotProps!) : label
const customAdditional = menuProps.customAdditional
? menuProps.customAdditional({ data: props.data, index: props.index })
: undefined
const suffixNode = coverIcon(suffixSlot, slotProps!, props.data.suffix)
return (
<li
class={classes.value}
Expand All @@ -85,6 +89,7 @@ export default defineComponent({
>
{iconNode}
<span>{labelNode}</span>
{suffixNode && <span class={`${mergedPrefixCls.value}-item-suffix`}>{suffixNode}</span>}
</li>
)
}
Expand Down
12 changes: 10 additions & 2 deletions packages/components/menu/src/contents/MenuItemGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

import { computed, defineComponent, inject, provide } from 'vue'
import { computed, defineComponent, inject, normalizeClass, provide } from 'vue'

import { isString } from 'lodash-es'

Expand Down Expand Up @@ -41,6 +41,14 @@ export default defineComponent({
const paddingLeft = usePaddingLeft(menuProps, mode, indent, level, !!menuItemGroupContext)
const labelStyle = computed(() => ({ paddingLeft: paddingLeft.value }))

const classes = computed(() => {
const prefixCls = mergedPrefixCls.value
return normalizeClass({
[`${prefixCls}-item-group`]: true,
[`${prefixCls}-level-${level}`]: true,
})
})

const onClick = (evt: Event) => {
handleClick(key, 'itemGroup', evt)
}
Expand All @@ -62,7 +70,7 @@ export default defineComponent({
? menuProps.customAdditional({ data: props.data, index: props.index })
: undefined
return (
<li class={prefixCls} aria-label={label} {...customAdditional}>
<li class={classes.value} aria-label={label} {...customAdditional}>
<div class={`${prefixCls}-label`} style={labelStyle.value} onClick={onClick}>
{iconNode}
<span>{labelNode}</span>
Expand Down
11 changes: 9 additions & 2 deletions packages/components/menu/src/contents/menu-sub/Label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,14 @@ export default defineComponent({
const { props, key, isExpanded, isSelected, changeExpanded, handleMouseEvent, mode, paddingLeft } =
inject(menuSubToken)!

const suffix = computed(() => props.data.suffix ?? config.suffix)
const mergedSuffix = computed(() => {
const { suffix } = props.data
if (suffix) {
return suffix
}
return mode.value !== 'horizontal' ? config.suffix : undefined
})

const rotate = computed(() => {
if (mode.value === 'inline') {
return isExpanded.value ? -90 : 90
Expand Down Expand Up @@ -66,7 +73,7 @@ export default defineComponent({
: undefined
const iconNode = coverIcon(iconSlot, slotProps!, icon)
const labelNode = labelSlot ? labelSlot(slotProps!) : label
const suffixNode = coverIcon(suffixSlot, slotProps!, suffix.value, rotate.value)
const suffixNode = coverIcon(suffixSlot, slotProps!, mergedSuffix.value, rotate.value)

const prefixCls = `${mergedPrefixCls.value}-sub-label`
return (
Expand Down
16 changes: 7 additions & 9 deletions packages/components/menu/src/contents/menu-sub/MenuSub.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ import InlineContent from './InlineContent'
import Label from './Label'
import OverlayContent from './OverlayContent'

const defaultDelay: [number, number] = [0, 100]

export default defineComponent({
name: 'MenuSub',
props: menuSubProps,
Expand Down Expand Up @@ -85,13 +83,13 @@ export default defineComponent({
const placement = computed(() => (mode.value === 'vertical' ? 'rightStart' : 'bottomStart'))

const classes = computed(() => {
const prefixCls = `${mergedPrefixCls.value}-sub`
const prefixCls = mergedPrefixCls.value
return normalizeClass({
[prefixCls]: true,
[`${prefixCls}-disabled`]: props.data.disabled,
[`${prefixCls}-expanded`]: isExpanded.value,
[`${prefixCls}-selected`]: isSelected.value,
[`${prefixCls}-${mode.value}`]: true,
[`${prefixCls}-sub`]: true,
[`${prefixCls}-level-${level}`]: true,
[`${prefixCls}-sub-disabled`]: props.data.disabled,
[`${prefixCls}-sub-expanded`]: isExpanded.value,
[`${prefixCls}-sub-selected`]: isSelected.value,
})
})

Expand Down Expand Up @@ -121,7 +119,7 @@ export default defineComponent({
autoAdjust
container={mergedOverlayContainer.value}
destroyOnHide={false}
delay={defaultDelay}
delay={menuProps.overlayDelay}
disabled={disabled}
offset={offset.value}
placement={placement.value}
Expand Down
6 changes: 6 additions & 0 deletions packages/components/menu/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ export const menuProps = {
type: [String, HTMLElement, Function] as PropType<PortalTargetType>,
default: undefined,
},
overlayDelay: {
type: [Number, Array] as PropType<number | [number | null, number | null]>,
default: [0, 100],
},
selectable: {
type: Boolean,
default: true,
Expand All @@ -72,8 +76,10 @@ export interface MenuItemProps<K = VKey> {
disabled?: boolean
icon?: string | VNode
label?: string
suffix?: string
customIcon?: string | ((data: MenuItemProps<K> & { selected: boolean }) => VNodeChild)
customLabel?: string | ((data: MenuItemProps<K> & { selected: boolean }) => VNodeChild)
customSuffix?: string | ((data: MenuItemProps<K> & { selected: boolean }) => VNodeChild)
}
export type MenuItemPublicProps = Omit<MenuItemProps, 'type'>
export type MenuItemComponent = FunctionalComponent<
Expand Down
Loading