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:dropdown): support hideOnClick #715

Merged
merged 1 commit into from
Jan 12, 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
1 change: 1 addition & 0 deletions packages/components/dropdown/docs/Index.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ order: 0
| `autoAdjust` | 悬浮层被遮挡时自动调整位置 | `boolean` | `true` | ✅ | - |
| `destroyOnHide` | 隐藏时是否销毁浮层 | `boolean` | `false` | ✅ | - |
| `disabled` | 菜单是否禁用 | `boolean` | `false` | - | - |
| `hideOnClick` | 点击后是否隐藏菜单 | `boolean` | `true` | - | - |
| `offset` | 悬浮层位置偏移量 | `[number, number]` | `[0,8]` | ✅ | - |
| `placement` | 悬浮层的对齐方式 | `PopperPlacement` | `bottomStart` | ✅ | - |
| `showArrow` | 是否显示箭头 | `boolean` | `false` | ✅ | - |
Expand Down
12 changes: 4 additions & 8 deletions packages/components/dropdown/src/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,14 @@
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

import type { DropdownProps } from './types'
import type { DropdownConfig } from '@idux/components/config'
import type { ComputedRef } from 'vue'

import { computed, defineComponent, provide } from 'vue'
import { type ComputedRef, computed, defineComponent, provide, toRef } from 'vue'

import { useControlledProp } from '@idux/cdk/utils'
import { ɵOverlay } from '@idux/components/_private/overlay'
import { useGlobalConfig } from '@idux/components/config'
import { type DropdownConfig, useGlobalConfig } from '@idux/components/config'

import { dropdownToken } from './token'
import { dropdownProps } from './types'
import { type DropdownProps, dropdownProps } from './types'

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

Expand All @@ -29,7 +25,7 @@ export default defineComponent({
const config = useGlobalConfig('dropdown')
const [visibility, setVisibility] = useControlledProp(props, 'visible', false)
const configProps = useConfigProps(props, config, mergedPrefixCls, setVisibility)
provide(dropdownToken, { setVisibility })
provide(dropdownToken, { hideOnClick: toRef(props, 'hideOnClick'), setVisibility })

return () => {
return (
Expand Down
3 changes: 2 additions & 1 deletion packages/components/dropdown/src/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

import { InjectionKey } from 'vue'
import { type InjectionKey, type Ref } from 'vue'

export interface DropdownContext {
hideOnClick: Ref<boolean>
setVisibility: (visible: boolean) => void
}

Expand Down
1 change: 1 addition & 0 deletions packages/components/dropdown/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const dropdownProps = {
autoAdjust: IxPropTypes.bool,
destroyOnHide: IxPropTypes.bool,
disabled: IxPropTypes.bool.def(false),
hideOnClick: IxPropTypes.bool.def(true),
offset: IxPropTypes.array() as unknown as VueTypeDef<[number, number]>,
placement: ɵOverlayPlacementDef,
showArrow: IxPropTypes.bool,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

exports[`Menu render work 1`] = `
"<ul class=\\"ix-menu ix-menu-light ix-menu-vertical\\">
<li class=\\"ix-menu-item\\"><span class=\\"ix-menu-item-icon\\"><i class=\\"ix-icon ix-icon-home\\" role=\\"img\\" aria-label=\\"home\\"></i></span><span><a>Item 1</a></span></li>
<li class=\\"ix-menu-item\\"><span class=\\"ix-menu-item-icon\\"><i class=\\"ix-icon ix-icon-mail\\" role=\\"img\\" aria-label=\\"mail\\"></i></span><span>Item 2</span></li>
<li class=\\"ix-menu-item ix-menu-item-disabled\\"><span class=\\"ix-menu-item-icon\\"><i class=\\"ix-icon ix-icon-appstore\\" role=\\"img\\" aria-label=\\"appstore\\"></i></span><span>Item 3</span></li>
<li class=\\"ix-menu-item\\"><span class=\\"ix-menu-item-icon\\"><i class=\\"ix-icon ix-icon-home\\" role=\\"img\\" aria-label=\\"home\\"></i></span><span class=\\"ix-menu-item-content\\"><a>Item 1</a></span></li>
<li class=\\"ix-menu-item\\"><span class=\\"ix-menu-item-icon\\"><i class=\\"ix-icon ix-icon-mail\\" role=\\"img\\" aria-label=\\"mail\\"></i></span><span class=\\"ix-menu-item-content\\">Item 2</span></li>
<li class=\\"ix-menu-item ix-menu-item-disabled\\"><span class=\\"ix-menu-item-icon\\"><i class=\\"ix-icon ix-icon-appstore\\" role=\\"img\\" aria-label=\\"appstore\\"></i></span><span class=\\"ix-menu-item-content\\">Item 3</span></li>
<li class=\\"ix-menu-divider\\"></li>
<li class=\\"ix-menu-sub ix-menu-sub-vertical\\">
<div class=\\"ix-menu-sub-title\\"><span class=\\"ix-menu-sub-title-icon\\"><i class=\\"ix-icon ix-icon-setting\\" role=\\"img\\" aria-label=\\"setting\\"></i></span><span>Sub Menu 1</span><span class=\\"ix-menu-sub-title-suffix\\"><i class=\\"ix-icon ix-icon-right\\" role=\\"img\\" aria-label=\\"right\\"></i></span></div>
<div class=\\"ix-menu-sub-title\\"><span class=\\"ix-menu-sub-title-icon\\"><i class=\\"ix-icon ix-icon-setting\\" role=\\"img\\" aria-label=\\"setting\\"></i></span><span class=\\"ix-menu-sub-title-content\\">Sub Menu 1</span><span class=\\"ix-menu-sub-title-suffix\\"><i class=\\"ix-icon ix-icon-right\\" role=\\"img\\" aria-label=\\"right\\"></i></span></div>
<!---->
</li>
<li class=\\"ix-menu-sub ix-menu-sub-disabled ix-menu-sub-vertical\\">
<div class=\\"ix-menu-sub-title\\"><span class=\\"ix-menu-sub-title-icon\\"><i class=\\"ix-icon ix-icon-github\\" role=\\"img\\" aria-label=\\"github\\"></i></span><span>Menu Sub 4</span><span class=\\"ix-menu-sub-title-suffix\\"><i class=\\"ix-icon ix-icon-right\\" role=\\"img\\" aria-label=\\"right\\"></i></span></div>
<div class=\\"ix-menu-sub-title\\"><span class=\\"ix-menu-sub-title-icon\\"><i class=\\"ix-icon ix-icon-github\\" role=\\"img\\" aria-label=\\"github\\"></i></span><span class=\\"ix-menu-sub-title-content\\">Menu Sub 4</span><span class=\\"ix-menu-sub-title-suffix\\"><i class=\\"ix-icon ix-icon-right\\" role=\\"img\\" aria-label=\\"right\\"></i></span></div>
<!---->
</li>
</ul>"
Expand Down
8 changes: 2 additions & 6 deletions packages/components/menu/__tests__/menu.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ import { h } from 'vue'
import { renderWork, wait } from '@tests'

import Menu from '../src/Menu'
// import MenuDivider from '../src/MenuDivider'
import MenuItem from '../src/contents/MenuItem'
// import MenuItemGroup from '../src/MenuItemGroup'
import MenuSub from '../src/contents/menu-sub/MenuSub'
import { MenuData, MenuProps } from '../src/types'

const dataSource: MenuData[] = [
Expand Down Expand Up @@ -88,7 +84,7 @@ describe('Menu', () => {
props: { expandedKeys: ['sub1'], 'onUpdate:expandedKeys': onUpdateExpandedKeys, mode: 'inline' },
})

const subs = wrapper.findAllComponents(MenuSub)
const subs = wrapper.findAll('.ix-menu-sub')
expect(subs.length).toBe(4)
expect(subs[0].classes()).toContain('ix-menu-sub-expanded')
expect(subs[1].classes()).not.toContain('ix-menu-sub-expanded')
Expand All @@ -113,7 +109,7 @@ describe('Menu', () => {
const onUpdateSelectedKeys = jest.fn()
const wrapper = MenuMount({ props: { selectedKeys: ['item1'], 'onUpdate:selectedKeys': onUpdateSelectedKeys } })

const items = wrapper.findAllComponents(MenuItem)
const items = wrapper.findAll('.ix-menu-item')
expect(items.length).toBe(3)
expect(items[0].classes()).toContain('ix-menu-item-selected')
expect(items[1].classes()).not.toContain('ix-menu-item-selected')
Expand Down
142 changes: 77 additions & 65 deletions packages/components/menu/docs/Index.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,99 +19,99 @@ order: 0
| `collapsed` | 菜单收起状态 | `boolean` | `false` | - | - |
| `dataSource` | 菜单数据数组 | `MenuData[]` | - | - | 优先级高于 `default` 插槽 |
| `indent` | `inline` 模式时的菜单缩进宽度 | `string \| number` | `24` | ✅ | 仅支持 `inline` 模式 |
| `overlayClassName` | 悬浮层的自定义 `class` | `string` | - | - | - |
| `overlayClassName` | 悬浮层的自定义 `class` | `string` | - | - | `inline` 模式时无效 |
| `mode` | 菜单模式,现在支持垂直、水平和内嵌 | `'vertical' \| 'horizontal' \| 'inline'` | `'vertical'` | - | - |
| `multiple` | 是否支持多选 | `boolean` | `false` | - | - |
| `selectable` | 是否允许选中 | `boolean` | - | - | 在 `IxDropdown` 中默认为 `false`, 其他情况默认为 `true` |
| `target` | 自定义菜单容器节点 | `string \| HTMLElement \| () => string \| HTMLElement` | - | ✅ | `inline` 模式时无效 |
| `theme` | 主题颜色 | `'light' \| 'dark'` | `'light'` | ✅ | - |
| `onClick` | 点击 `IxMenuItem` 或 `IxMenuSub` 后的回调 | `(options: MenuClickOptions) => void>` | - | - |
| `onClick` | 点击菜单后的回调 | `(options: MenuClickOptions) => void>` | - | - |

```ts
export type MenuData = MenuItem | MenuItemGroup | MenuSub | MenuDivider

export interface MenuCommon {
type?: 'item' | 'itemGroup' | 'sub' | 'divider'
additional?: {
class?: any
style?: any
[key: string]: unknown
}
export type MenuData = MenuItemProps | MenuItemGroupProps | MenuSubProps | MenuDividerProps

export interface MenuClickOptions {
event: Event
key: VKey
slots?: unknown
type: 'item' | 'itemGroup' | 'sub'
}
```

export interface MenuItemSlots {
icon?: string | ((data: MenuItem & { selected: boolean }) => VNodeChild)
label?: string | ((data: MenuItem & { selected: boolean }) => VNodeChild)
}
export interface MenuItem extends MenuItemPublicProps, MenuCommon {
type?: 'item'
slots?: MenuItemSlots
}
#### MenuCommonProps

export interface MenuItemGroupSlots {
icon?: string | ((data: MenuItemGroup) => VNodeChild)
label?: string | ((data: MenuItemGroup) => VNodeChild)
}
export interface MenuItemGroup extends MenuItemGroupPublicProps, MenuCommon {
type: 'itemGroup'
slots?: MenuItemGroupSlots
}
`MenuData` 的通用属性

export interface MenuSubSlots {
icon?: string | ((data: MenuSub & { expanded: boolean; selected: boolean }) => VNodeChild)
label?: string | ((data: MenuSub & { expanded: boolean; selected: boolean }) => VNodeChild)
suffix?: string | ((data: MenuSub & { expanded: boolean; selected: boolean }) => VNodeChild)
}
export interface MenuSub extends MenuSubPublicProps, MenuCommon {
type: 'sub'
additional?: {
class?: any
style?: any
[key: string]: unknown
}
slots?: MenuSubSlots
}
| 名称 | 说明 | 类型 | 默认值 | 全局配置 | 备注 |
| --- | --- | --- | --- | --- | --- |
| `type` | 菜单类型 | `'item' \| 'itemGroup' \| 'sub' \| 'divider'` | `'item'` | - | - |
| `key` | 唯一标识 | `VKey` | - | - | 必传 |
| `additional` | 菜单的额外配置 | `object` | - | - | 可以传入 `class`, `style` 等原生 DOM 属性 |

#### MenuItemProps

菜单项的配置,继承自 `MenuCommonProps`

| 名称 | 说明 | 类型 | 默认值 | 全局配置 | 备注 |
| --- | --- | --- | --- | --- | --- |
| `type` | 菜单类型 | `'item'` | `'item'` | - | - |
| `disabled` | 是否禁用 | `boolean` | - | - | - |
| `icon` | 菜单图标| `string \| VNode` | - | - |
| `label` | 菜单文本 | `string` | - | - |
| `slots` | 自定义菜单内容 | `MenuItemSlots` | - | - |

export interface MenuDivider {
type: 'divider'
additional?: {
class?: any
style?: any
[key: string]: unknown
}
key?: VKey
```ts
export interface MenuItemSlots {
/**
* 如果类型为 `string`, 会根据该字符串去 `IxMenu` 的插槽中获取
*/
icon?: string | ((data: MenuItem & { selected: boolean }) => VNodeChild)
label?: string | ((data: MenuItem & { selected: boolean }) => VNodeChild)
}
```

### IxMenuItem
#### MenuItemGroupProps

#### MenuItemProps
菜单组的配置,继承自 `MenuCommonProps`

| 名称 | 说明 | 类型 | 默认值 | 全局配置 | 备注 |
| --- | --- | --- | --- | --- | --- |
| `key` | 唯一标识 | `VKey` | - | - | 必传 |
| `disabled` | 是否禁用 | `boolean` | `false` | - | - |
| `icon` | 菜单图标| `string \| VNode \| #icon` | - | - |
| `type` | 菜单类型 | `'itemGroup'` | - | - | 必传 |
| `children` | 子菜单数据 | `MenuData[]` | - | - | - |
| `icon` | 菜单图标| `string \| VNode \| #icon` | - | - |
| `label` | 菜单文本 | `string \| #label` | - | - |
| `slots` | 自定义菜单内容 | `MenuItemGroupSlots` | - | - |

### IxMenuSub
```ts
export interface MenuItemGroupSlots {
icon?: string | ((data: MenuItemGroupProps) => VNodeChild)
label?: string | ((data: MenuItemGroupProps) => VNodeChild)
}
```

#### MenuSubProps

子菜单的配置,继承自 `MenuCommonProps`

| 名称 | 说明 | 类型 | 默认值 | 全局配置 | 备注 |
| --- | --- | --- | --- | --- | --- |
| `key` | 唯一标识 | `VKey` | - | - | 必传 |
| `children` | 子菜单数据 | `MenuData[] \| #default` | - | - | - |
| `disabled` | 是否禁用 | `boolean` | `false` | - | - |
| `icon` | 菜单图标| `string \| VNode \| #icon` | - | - | - |
| `label` | 菜单文本 | `string \| #label` | - | - |
| `suffix` | 后缀图标 | `string \| #suffix` | `right` | ✅ | - |
| `type` | 菜单类型 | `'sub'` | - | - | 必传 |
| `children` | 子菜单数据 | `MenuData[]` | - | - | - |
| `disabled` | 是否禁用 | `boolean` | - | - | - |
| `icon` | 菜单图标| `string \| VNode` | - | - |
| `label` | 菜单文本 | `string` | - | - |
| `offset` | 浮层偏移量 | `[number, number]` | `[0, 8]` | ✅ | `inline` 模式时无效 |
| `suffix` | 后缀图标 | `string` | `right` | ✅ | - |
| `slots` | 自定义菜单内容 | `MenuSubSlots` | - | - |

### IxMenuItemGroup
```ts
export interface MenuSubSlots {
icon?: string | ((data: MenuSubProps & { expanded: boolean; selected: boolean }) => VNodeChild)
label?: string | ((data: MenuSubProps & { expanded: boolean; selected: boolean }) => VNodeChild)
suffix?: string | ((data: MenuSubProps & { expanded: boolean; selected: boolean }) => VNodeChild)
}
```

#### MenuItemGroupProps
#### MenuDividerProps

| 名称 | 说明 | 类型 | 默认值 | 全局配置 | 备注 |
| --- | --- | --- | --- | --- | --- |
Expand All @@ -120,6 +120,18 @@ export interface MenuDivider {
| `icon` | 菜单图标| `string \| VNode \| #icon` | - | - |
| `label` | 菜单文本 | `string \| #label` | - | - |

### IxMenuItem

在 `template` 中设置 `MenuItemProps`。

### IxMenuSub

在 `template` 中设置 `MenuSubProps`。

### IxMenuItemGroup

在 `template` 中设置 `MenuItemGroupProps`。

### IxMenuDivider

菜单分割线
在 `template` 中设置 `MenuDividerProps`
7 changes: 0 additions & 7 deletions packages/components/menu/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,15 @@ export type {
MenuInstance,
MenuComponent,
MenuPublicProps as MenuProps,
MenuItemInstance,
MenuItemComponent,
MenuItemPublicProps as MenuItemProps,
MenuItemGroupInstance,
MenuItemGroupComponent,
MenuItemGroupPublicProps as MenuItemGroupProps,
MenuSubInstance,
MenuSubComponent,
MenuSubPublicProps as MenuSubProps,
MenuDividerComponent,
MenuMode,
MenuTheme,
MenuClickOptions,
MenuData,
MenuItem,
MenuItemGroup,
MenuSub,
MenuDivider,
} from './src/types'
6 changes: 2 additions & 4 deletions packages/components/menu/src/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,16 @@
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

import type { VKey } from '@idux/cdk/utils'

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

import { callEmit } from '@idux/cdk/utils'
import { type VKey, callEmit } from '@idux/cdk/utils'
import { useGlobalConfig } from '@idux/components/config'
import { ɵDropdownToken } from '@idux/components/dropdown'

import { coverChildren } from './children/Utils'
import { useDataSource } from './composables/useDataSource'
import { useExpanded } from './composables/useExpanded'
import { useSelected } from './composables/useSelected'
import { coverChildren } from './contents/Utils'
import { menuToken } from './token'
import { menuProps } from './types'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

import type { FunctionalComponent, HTMLAttributes } from 'vue'

import { inject } from 'vue'
import { type FunctionalComponent, type HTMLAttributes, inject } from 'vue'

import { menuToken } from '../token'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { useKey } from '@idux/components/utils'

import { usePaddingLeft } from '../composables/usePaddingLeft'
import { menuItemGroupToken, menuSubToken, menuToken } from '../token'
import { MenuItem, menuItemProps } from '../types'
import { menuItemProps } from '../types'
import { coverIcon } from './Utils'

export default defineComponent({
Expand All @@ -40,7 +40,7 @@ export default defineComponent({
const prefixCls = `${mergedPrefixCls.value}-item`
return normalizeClass({
[prefixCls]: true,
[`${prefixCls}-disabled`]: props.disabled,
[`${prefixCls}-disabled`]: props.data.disabled,
[`${prefixCls}-selected`]: isSelected.value,
})
})
Expand All @@ -59,27 +59,23 @@ export default defineComponent({
}

return () => {
const { disabled, icon, label } = props
const slots = props.slots || {}
const { additional, disabled, icon, label, slots = {} } = props.data
const iconSlot = isString(slots.icon) ? menuSlots[slots.icon] : slots.icon
// <IxMenuItem key="key">label</IxMenuItem>
let labelSlot = slots.label ?? slots.default
if (isString(labelSlot)) {
labelSlot = menuSlots[labelSlot]
}

const slotProps =
iconSlot || labelSlot
? ({ ...props, key, selected: isSelected.value } as MenuItem & { selected: boolean })
: undefined
const slotProps = iconSlot || labelSlot ? { ...props.data, selected: isSelected.value } : undefined
const iconNode = coverIcon(iconSlot, slotProps!, icon)
const labelNode = labelSlot ? labelSlot(slotProps) : label

const prefixCls = `${mergedPrefixCls.value}-item`
return (
<li class={classes.value} style={style.value} onClick={disabled ? undefined : onClick}>
<li class={classes.value} style={style.value} {...additional} onClick={disabled ? undefined : onClick}>
{iconNode && <span class={`${prefixCls}-icon`}>{iconNode}</span>}
<span>{labelNode}</span>
<span class={`${prefixCls}-content`}>{labelNode}</span>
</li>
)
}
Expand Down
Loading