feat(menu): add node-props prop

This commit is contained in:
07akioni 2022-04-29 01:44:48 +08:00
parent 3ed47db97e
commit 373befb329
8 changed files with 92 additions and 70 deletions

View File

@ -7,6 +7,10 @@
- Fix `n-menu`'s `dropdown-props` prop can't override `n-dropdown`'s `size` prop, closes [#2868](https://github.com/TuSimple/naive-ui/issues/2868).
- Fix `n-switch` abnormal loading animation when switching state, closes [#2870](https://github.com/TuSimple/naive-ui/issues/2870)
### Feats
- `n-menu` adds `node-props` prop.
## 2.28.2
### Fixes

View File

@ -7,6 +7,10 @@
- 修复 `n-menu``dropdown-props` 无法覆盖 `n-dropdown``size` 属性,关闭 [#2868](https://github.com/TuSimple/naive-ui/issues/2868)
- 修复 `n-switch` 切换状态时 loading 动画异常,关闭 [#2870](https://github.com/TuSimple/naive-ui/issues/2870)
### Feats
- `n-menu` 新增 `node-props` 属性
## 2.28.2
### Fixes

View File

@ -25,35 +25,36 @@ expand-selected-option.vue
### Menu Props
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| accordion | `boolean` | `false` | Whether to use accordion mode. |
| children-field | `string` | `'children'` | Field name of children. |
| collapsed-icon-size | `number` | `24` | The icon size when menu is collapsed. If not set, menu will use `icon-size` in place of it. |
| collapsed-width | `number` | `48` | The menu width after collapsed. |
| collapsed | `boolean` | `false` | The collapsed status of menu, only works when menu is vertical. |
| default-expand-all | `boolean` | `false` | Whether to expand all menus. |
| default-expanded-keys | `Array<string>` | `[]` | The default expanded submenu keys of menu in uncontrolled manner. |
| default-value | `string \| null` | `null` | Whether selected by default in uncontrolled mode. |
| dropdown-placement | `'top-start' \| 'top' \| 'top-end' \| 'right-start' \| 'right' \| 'right-end' \| 'bottom-start' \| 'bottom' \| 'bottom-end' \| 'left-start' \| 'left' \| 'left-end' \| ` | `'top'` | Only effective in horizontal mode. |
| dropdown-props | `DropdownProps` | `undefined` | The dropdown's props when menu is collapsed or horizontal modeplease see [Dropdown Props](dropdown#Dropdown-Props) |
| expanded-keys | `Array<string>` | `undefined` | The expanded submenu keys. If set, menu will work in controlled manner and `default-expanded-names` won't work. |
| expand-icon | `(option: MenuOption) => VNodeChild` | `undefined` | Render function that renders all expand icon. |
| icon-size | `number` | `20` | The icon size when menu is not collapsed. |
| indent | `number` | `32` | The indent of menu. |
| inverted | `boolean` | `false` | Use inverted style. |
| key-field | `string` | `'key'` | Field name of key. |
| label-field | `string` | `'label'` | Field name of label. |
| options | `Array<MenuOption \| MenuDividerOption \| MenuGroupOption>` | `[]` | Items data of menu. |
| mode | `'vertical' \| 'horizontal'` | `'vertical'` | Menu layout. |
| render-extra | `(option: MenuOption \| MenuGroupOption) => VNodeChild` | `undefined` | Render function that renders all extras. |
| render-icon | `(option: MenuOption) => VNodeChild` | `undefined` | Render function that renders all icons. |
| render-label | `(option: MenuOption \| MenuGroupOption) => VNodeChild` | `undefined` | Render function that renders all labels. |
| root-indent | `number` | `undefined` | The indent of menu's first level children. If not set, menu will use `indent` in place of it. |
| value | `string \| null` | `undefined` | The selected item key of the menu. |
| watch-props | `Array<'defaultValue' \| 'defaultExpandedKeys'>` | `undefined` | Default prop names that needed to be watched. Components will be updated after the prop is changed. Note: the `watch-props` itself is not reactive. |
| on-update:expanded-keys | `(keys: string[]) => void` | `undefined` | `keys` is the array of expanded menu options' `key`. |
| on-update:value | `(key: string, item: MenuOption) => void` | `undefined` | Callback when select a menu item. `key` is the `key` of the selected menu item. `item` is then original data of the menu item. |
| Name | Type | Default | Description | Version |
| --- | --- | --- | --- | --- |
| accordion | `boolean` | `false` | Whether to use accordion mode. | |
| children-field | `string` | `'children'` | Field name of children. | |
| collapsed-icon-size | `number` | `24` | The icon size when menu is collapsed. If not set, menu will use `icon-size` in place of it. | |
| collapsed-width | `number` | `48` | The menu width after collapsed. | |
| collapsed | `boolean` | `false` | The collapsed status of menu, only works when menu is vertical. | |
| default-expand-all | `boolean` | `false` | Whether to expand all menus. | |
| default-expanded-keys | `Array<string>` | `[]` | The default expanded submenu keys of menu in uncontrolled manner. | |
| default-value | `string \| null` | `null` | Whether selected by default in uncontrolled mode. | |
| dropdown-placement | `'top-start' \| 'top' \| 'top-end' \| 'right-start' \| 'right' \| 'right-end' \| 'bottom-start' \| 'bottom' \| 'bottom-end' \| 'left-start' \| 'left' \| 'left-end' \| ` | `'top'` | Only effective in horizontal mode. | |
| dropdown-props | `DropdownProps` | `undefined` | The dropdown's props when menu is collapsed or horizontal modeplease see [Dropdown Props](dropdown#Dropdown-Props) | |
| expanded-keys | `Array<string>` | `undefined` | The expanded submenu keys. If set, menu will work in controlled manner and `default-expanded-names` won't work. | |
| expand-icon | `(option: MenuOption) => VNodeChild` | `undefined` | Render function that renders all expand icon. | |
| icon-size | `number` | `20` | The icon size when menu is not collapsed. | |
| indent | `number` | `32` | The indent of menu. | |
| inverted | `boolean` | `false` | Use inverted style. | |
| key-field | `string` | `'key'` | Field name of key. | |
| label-field | `string` | `'label'` | Field name of label. | |
| options | `Array<MenuOption \| MenuDividerOption \| MenuGroupOption>` | `[]` | Items data of menu. | |
| node-props | `() => (MenuOption \| MenuGroupOption)` | `undefined` | Node's DOM attrs generator. | NEXT_VERSION |
| mode | `'vertical' \| 'horizontal'` | `'vertical'` | Menu layout. | |
| render-extra | `(option: MenuOption \| MenuGroupOption) => VNodeChild` | `undefined` | Render function that renders all extras. | |
| render-icon | `(option: MenuOption) => VNodeChild` | `undefined` | Render function that renders all icons. | |
| render-label | `(option: MenuOption \| MenuGroupOption) => VNodeChild` | `undefined` | Render function that renders all labels. | |
| root-indent | `number` | `undefined` | The indent of menu's first level children. If not set, menu will use `indent` in place of it. | |
| value | `string \| null` | `undefined` | The selected item key of the menu. | |
| watch-props | `Array<'defaultValue' \| 'defaultExpandedKeys'>` | `undefined` | Default prop names that needed to be watched. Components will be updated after the prop is changed. Note: the `watch-props` itself is not reactive. | |
| on-update:expanded-keys | `(keys: string[]) => void` | `undefined` | `keys` is the array of expanded menu options' `key`. | |
| on-update:value | `(key: string, item: MenuOption) => void` | `undefined` | Callback when select a menu item. `key` is the `key` of the selected menu item. `item` is then original data of the menu item. | |
### MenuOption Properties

View File

@ -25,35 +25,36 @@ expand-selected-option.vue
### Menu Props
| 名称 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| accordion | `boolean` | `false` | 是否使用手风琴模式 |
| children-field | `string` | `'children'` | children 的字段名 |
| collapsed-icon-size | `number` | `24` | 菜单折叠时图标的大小,如果未设定则使用 `icon-size` 代替 |
| collapsed-width | `number` | `48` | 折叠后菜单的宽度 |
| collapsed | `boolean` | `false` | 菜单是否折叠,值在菜单为垂直时有用 |
| default-expand-all | `boolean` | `false` | 是否展开全部菜单 |
| default-expanded-keys | `Array<string>` | `[]` | 在非受控状态下默认展开的子菜单标识符数组 |
| default-value | `string \| null` | `null` | 非受控模式下的默认值 |
| dropdown-placement | `'top-start' \| 'top' \| 'top-end' \| 'right-start' \| 'right' \| 'right-end' \| 'bottom-start' \| 'bottom' \| 'bottom-end' \| 'left-start' \| 'left' \| 'left-end' \| ` | `'top'` | 仅在 `mode='horizontal'` 模式下生效 |
| dropdown-props | `DropdownProps` | `undefined` | 菜单折叠或 `mode='horizontal'` 模式时 Dropdown 的 props请参考 [Dropdown Props](dropdown#Dropdown-Props) |
| expanded-keys | `Array<string>` | `undefined` | 展开的子菜单标识符数组,如果设定了,菜单的展开将会进入受控状态,`default-expanded-keys` 不会生效 |
| expand-icon | `(option: MenuOption) => VNodeChild` | `undefined` | 批量处理菜单展开图标的渲染 |
| icon-size | `number` | `20` | 菜单未折叠时图标的大小 |
| indent | `number` | `32` | 菜单每级的缩进 |
| inverted | `boolean` | `false` | 使用反转样式 |
| key-field | `string` | `'key'` | key 的字段名 |
| label-field | `string` | `'label'` | label 的字段名 |
| options | `Array<MenuOption \| MenuDividerOption \| MenuGroupOption>` | `[]` | 菜单的数据 |
| mode | `'vertical' \| 'horizontal'` | `'vertical'` | 菜单的布局方式 |
| render-extra | `(option: MenuOption \| MenuGroupOption) => VNodeChild` | `undefined` | 批量处理菜单额外部分渲染 |
| render-icon | `(option: MenuOption) => VNodeChild` | `undefined` | 批量处理菜单图标渲染 |
| render-label | `(option: MenuOption \| MenuGroupOption) => VNodeChild` | `undefined` | 批量处理菜单标签渲染 |
| root-indent | `number` | `32` | 菜单第一级的缩进,如果没有设定,使用 `indent` 代替 |
| value | `string \| null` | `undefined` | 菜单当前的选中值 |
| watch-props | `Array<'defaultValue' \| 'defaultExpandedKeys'>` | `undefined` | 需要检测变更的默认属性,检测后组件状态会更新。注意:`watch-props` 本身不是响应式的 |
| on-update:expanded-keys | `(keys: string[]) => void` | `undefined` | `keys` 是展开菜单项的 `key` 的数组 |
| on-update:value | `(key: string, item: MenuOption) => void` | `undefined` | 选中菜单的回调,`key` 是选中菜单项的 `key``item` 是菜单项原始数据 |
| 名称 | 类型 | 默认值 | 说明 | 版本 |
| --- | --- | --- | --- | --- |
| accordion | `boolean` | `false` | 是否使用手风琴模式 | |
| children-field | `string` | `'children'` | children 的字段名 | |
| collapsed-icon-size | `number` | `24` | 菜单折叠时图标的大小,如果未设定则使用 `icon-size` 代替 | |
| collapsed-width | `number` | `48` | 折叠后菜单的宽度 | |
| collapsed | `boolean` | `false` | 菜单是否折叠,值在菜单为垂直时有用 | |
| default-expand-all | `boolean` | `false` | 是否展开全部菜单 | |
| default-expanded-keys | `Array<string>` | `[]` | 在非受控状态下默认展开的子菜单标识符数组 | |
| default-value | `string \| null` | `null` | 非受控模式下的默认值 | |
| dropdown-placement | `'top-start' \| 'top' \| 'top-end' \| 'right-start' \| 'right' \| 'right-end' \| 'bottom-start' \| 'bottom' \| 'bottom-end' \| 'left-start' \| 'left' \| 'left-end' \| ` | `'top'` | 仅在 `mode='horizontal'` 模式下生效 | |
| dropdown-props | `DropdownProps` | `undefined` | 菜单折叠或 `mode='horizontal'` 模式时 Dropdown 的 props请参考 [Dropdown Props](dropdown#Dropdown-Props) | |
| expanded-keys | `Array<string>` | `undefined` | 展开的子菜单标识符数组,如果设定了,菜单的展开将会进入受控状态,`default-expanded-keys` 不会生效 | |
| expand-icon | `(option: MenuOption) => VNodeChild` | `undefined` | 批量处理菜单展开图标的渲染 | |
| icon-size | `number` | `20` | 菜单未折叠时图标的大小 | |
| indent | `number` | `32` | 菜单每级的缩进 | |
| inverted | `boolean` | `false` | 使用反转样式 | |
| key-field | `string` | `'key'` | key 的字段名 | |
| label-field | `string` | `'label'` | label 的字段名 | |
| options | `Array<MenuOption \| MenuDividerOption \| MenuGroupOption>` | `[]` | 菜单的数据 | |
| node-props | `() => (MenuOption \| MenuGroupOption)` | `undefined` | 节点的 DOM 属性生成函数 | NEXT_VERSION |
| mode | `'vertical' \| 'horizontal'` | `'vertical'` | 菜单的布局方式 | |
| render-extra | `(option: MenuOption \| MenuGroupOption) => VNodeChild` | `undefined` | 批量处理菜单额外部分渲染 | |
| render-icon | `(option: MenuOption) => VNodeChild` | `undefined` | 批量处理菜单图标渲染 | |
| render-label | `(option: MenuOption \| MenuGroupOption) => VNodeChild` | `undefined` | 批量处理菜单标签渲染 | |
| root-indent | `number` | `32` | 菜单第一级的缩进,如果没有设定,使用 `indent` 代替 | |
| value | `string \| null` | `undefined` | 菜单当前的选中值 | |
| watch-props | `Array<'defaultValue' \| 'defaultExpandedKeys'>` | `undefined` | 需要检测变更的默认属性,检测后组件状态会更新。注意:`watch-props` 本身不是响应式的 | |
| on-update:expanded-keys | `(keys: string[]) => void` | `undefined` | `keys` 是展开菜单项的 `key` 的数组 | |
| on-update:value | `(key: string, item: MenuOption) => void` | `undefined` | 选中菜单的回调,`key` 是选中菜单项的 `key``item` 是菜单项原始数据 | |
#### MenuOption Properties

View File

@ -4,5 +4,6 @@ export type {
MenuOption,
MenuGroupOption,
MenuDividerOption,
MenuNodeProps,
MenuInst
} from './src/interface'

View File

@ -33,7 +33,8 @@ import {
OnUpdateKeys,
OnUpdateValueImpl,
OnUpdateKeysImpl,
MenuInst
MenuInst,
MenuNodeProps
} from './interface'
import { useCheckDeprecated } from './useCheckDeprecated'
import { menuInjectionKey } from './context'
@ -109,13 +110,9 @@ const menuProps = {
renderExtra: Function as PropType<
(option: MenuOption | MenuGroupOption) => VNodeChild
>,
/** TODO: deprecate it */
dropdownPlacement: {
type: String as PropType<FollowerPlacement>,
default: 'bottom'
},
dropdownProps: Object as PropType<DropdownProps>,
accordion: Boolean,
nodeProps: Function as PropType<MenuNodeProps>,
// deprecated
items: Array as PropType<Array<MenuOption | MenuGroupOption>>,
onOpenNamesChange: [Function, Array] as PropType<MaybeArray<OnUpdateKeys>>,
@ -124,7 +121,11 @@ const menuProps = {
MaybeArray<OnUpdateKeys>
>,
expandedNames: Array as PropType<Key[]>,
defaultExpandedNames: Array as PropType<Key[]>
defaultExpandedNames: Array as PropType<Key[]>,
dropdownPlacement: {
type: String as PropType<FollowerPlacement>,
default: 'bottom'
}
} as const
export type MenuSetupProps = ExtractPropTypes<typeof menuProps>

View File

@ -64,12 +64,17 @@ export default defineComponent({
const {
clsPrefix,
tmNode,
menuProps: { renderIcon, renderLabel, renderExtra, expandIcon }
menuProps: { renderIcon, renderLabel, renderExtra, expandIcon, nodeProps }
} = this
const icon = renderIcon ? renderIcon(tmNode.rawNode) : render(this.icon)
const attrs = nodeProps?.(tmNode.rawNode)
return (
<div
onClick={this.onClick}
{...attrs}
onClick={(e) => {
attrs?.onClick?.(e)
this.onClick?.(e)
}}
role="none"
class={[
`${clsPrefix}-menu-item-content`,
@ -79,9 +84,10 @@ export default defineComponent({
[`${clsPrefix}-menu-item-content--child-active`]: this.childActive,
[`${clsPrefix}-menu-item-content--disabled`]: this.disabled,
[`${clsPrefix}-menu-item-content--hover`]: this.hover
}
},
attrs?.class
]}
style={this.style}
style={[this.style, attrs?.style || '']}
>
{icon && (
<div
@ -89,7 +95,7 @@ export default defineComponent({
style={this.iconStyle}
role="none"
>
{[icon]}
{icon}
</div>
)}
<div class={`${clsPrefix}-menu-item-content-header`} role="none">

View File

@ -76,6 +76,10 @@ export type OnUpdateKeysImpl = (
keys: string[] | number[] | Array<string | number>
) => void
export type MenuNodeProps = (
option: MenuOption | MenuGroupOption
) => HTMLAttributes
export interface MenuInst {
showOption: (key?: Key) => void
}