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(cascader): adds render-tag prop #6391

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
6 changes: 6 additions & 0 deletions CHANGELOG.en-US.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# CHANGELOG

### NEXT_VERSION

### Features

- `n-cascader` adds `render-tag` prop,closes [#6389](https://github.com/tusen-ai/naive-ui/issues/6389).

## 2.41.0

### Breaking Changes
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.zh-CN.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# CHANGELOG

### NEXT_VERSION

### Features

- `n-cascader` 新增 `render-tag` 属性,关闭 [#6389](https://github.com/tusen-ai/naive-ui/issues/6389)

## 2.41.0

`2025-01-05`
Expand Down
2 changes: 1 addition & 1 deletion src/cascader/demos/enUS/custom-render.demo.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<markdown>
# Customized rendering
# Customized option rendering

The `render-label` can be used to batch render cascader menu options.
</markdown>
Expand Down
2 changes: 2 additions & 0 deletions src/cascader/demos/enUS/index.demo-entry.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ virtual.vue
check-strategy.vue
custom-field.vue
custom-render.vue
render-tag.vue
focus.vue
status.vue
```
Expand Down Expand Up @@ -52,6 +53,7 @@ status.vue
| render-prefix | `(info: { option: CascaderOption, node: VNode \| null, checked: boolean }) => VNodeChild` | `undefined` | Render function of all the options' prefix. | 2.38.2 |
| render-label | `(option: CascaderOption, checked: boolean) => VNodeChild` | `undefined` | Render function for cascader menu option label. | 2.24.0 |
| render-suffix | `(info: { option: CascaderOption, node: VNode \| null, checked: boolean }) => VNodeChild` | `undefined` | Render function of all the options' suffix. | 2.38.2 |
| render-tag | `(props: { option: CascaderOption, handleClose: () => void }) => VNodeChild` | `undefined` | Render function for each option tag. | NEXT_VERSION |
| separator | `string` | `' / '` | Selected option path value separator (used with `show-path`). | |
| show | `boolean` | `undefined` | Whether to show the menu. | |
| show-path | `boolean` | `true` | Whether to show the selected options as a path. | |
Expand Down
68 changes: 68 additions & 0 deletions src/cascader/demos/enUS/render-tag.demo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<markdown>
# Customize tag rendering

Give the tag a little color.
</markdown>

<script setup lang="ts">
import { h } from 'vue'
import type { CascaderOption, CascaderRenderTag } from 'naive-ui'

Check failure on line 9 in src/cascader/demos/enUS/render-tag.demo.vue

View workflow job for this annotation

GitHub Actions / lint (22)

Expected "naive-ui" (type) to come before "vue" (external)
import { NTag } from 'naive-ui'

const tagTypes = ['success', 'warning', 'error'] as const
const renderTag: CascaderRenderTag = ({ option, handleClose }) => {
const { level, label } = option
return h(
NTag,
{
type: tagTypes[(level as number) - 1],
closable: (level as number) === 1,
onClose: (e: MouseEvent) => {
e.stopPropagation()
handleClose()
}
},
{ default: () => label }
)
}

const options = getOptions()

function getOptions(depth = 3, iterator = 1, prefix = '') {
const length = 12
const options: CascaderOption[] = []
for (let i = 1; i <= length; ++i) {
if (iterator === 1) {
options.push({
value: `v-${i}`,
label: `l-${i}`,
level: iterator,
disabled: i % 5 === 0,
children: getOptions(depth, iterator + 1, `${String(i)}`)
})
}
else if (iterator === depth) {
options.push({
value: `v-${prefix}-${i}`,
label: `l-${prefix}-${i}`,
level: iterator,
disabled: i % 5 === 0
})
}
else {
options.push({
value: `v-${prefix}-${i}`,
label: `l-${prefix}-${i}`,
disabled: i % 5 === 0,
level: iterator,
children: getOptions(depth, iterator + 1, `${prefix}-${i}`)
})
}
}
return options
}
</script>

<template>
<n-cascader multiple clearable :render-tag="renderTag" :options="options" />
</template>
2 changes: 1 addition & 1 deletion src/cascader/demos/zhCN/custom-render.demo.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<markdown>
# 自定义渲染
# 自定义选项渲染

使用 `render-label` 可以批量控制 cascader 菜单的选项渲染。
</markdown>
Expand Down
2 changes: 2 additions & 0 deletions src/cascader/demos/zhCN/index.demo-entry.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ virtual.vue
check-strategy.vue
custom-field.vue
custom-render.vue
render-tag.vue
focus.vue
status.vue
default-value-debug.vue
Expand Down Expand Up @@ -53,6 +54,7 @@ default-value-debug.vue
| render-prefix | `(info: { option: CascaderOption, node: VNode \| null, checked: boolean }) => VNodeChild` | `undefined` | 节点前缀的渲染函数 | 2.38.2 |
| render-label | `(option: CascaderOption, checked: boolean) => VNodeChild` | `undefined` | Cascader 菜单选项标签渲染函数 | 2.24.0 |
| render-suffix | `(info: { option: CascaderOption, checked: boolean }) => VNodeChild` | `undefined` | 节点后缀的渲染函数 | 2.38.2 |
| render-tag | `(props: { option: CascaderOption, handleClose: () => void }) => VNodeChild` | `undefined` | 标签的渲染函数 | NEXT_VERSION |
| separator | `string` | `' / '` | 数据分隔符 | |
| show | `boolean` | `undefined` | 是否打开菜单 | |
| show-path | `boolean` | `true` | 是否在选择器中显示选项路径 | |
Expand Down
68 changes: 68 additions & 0 deletions src/cascader/demos/zhCN/render-tag.demo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<markdown>
# 自定义标签渲染

给标签一点颜色看看。
</markdown>

<script setup lang="ts">
import { h } from 'vue'
import type { CascaderOption, CascaderRenderTag } from 'naive-ui'

Check failure on line 9 in src/cascader/demos/zhCN/render-tag.demo.vue

View workflow job for this annotation

GitHub Actions / lint (22)

Expected "naive-ui" (type) to come before "vue" (external)
import { NTag } from 'naive-ui'

const tagTypes = ['success', 'warning', 'error'] as const
const renderTag: CascaderRenderTag = ({ option, handleClose }) => {
const { level, label } = option
return h(
NTag,
{
type: tagTypes[(level as number) - 1],
closable: (level as number) === 1,
onClose: (e: MouseEvent) => {
e.stopPropagation()
handleClose()
}
},
{ default: () => label }
)
}

const options = getOptions()

function getOptions(depth = 3, iterator = 1, prefix = '') {
const length = 12
const options: CascaderOption[] = []
for (let i = 1; i <= length; ++i) {
if (iterator === 1) {
options.push({
value: `v-${i}`,
label: `l-${i}`,
level: iterator,
disabled: i % 5 === 0,
children: getOptions(depth, iterator + 1, `${String(i)}`)
})
}
else if (iterator === depth) {
options.push({
value: `v-${prefix}-${i}`,
label: `l-${prefix}-${i}`,
level: iterator,
disabled: i % 5 === 0
})
}
else {
options.push({
value: `v-${prefix}-${i}`,
label: `l-${prefix}-${i}`,
disabled: i % 5 === 0,
level: iterator,
children: getOptions(depth, iterator + 1, `${prefix}-${i}`)
})
}
}
return options
}
</script>

<template>
<n-cascader multiple clearable :render-tag="renderTag" :options="options" />
</template>
2 changes: 1 addition & 1 deletion src/cascader/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export { cascaderProps, default as NCascader } from './src/Cascader'
export type { CascaderProps, CascaderSlots } from './src/Cascader'
export type { CascaderInst, CascaderOption } from './src/interface'
export type { CascaderInst, CascaderOption, CascaderRenderTag } from './src/interface'
24 changes: 24 additions & 0 deletions src/cascader/src/Cascader.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { InternalSelectionInst } from '../../_internal'
import type { RenderTag } from '../../_internal/selection/src/interface'
import type { ThemeProps } from '../../_mixins'
import type { ExtractPublicPropTypes, MaybeArray } from '../../_utils'
import type { FormValidationStatus } from '../../form/src/interface'
Expand All @@ -9,6 +10,7 @@ import type {
CascaderInst,
CascaderMenuInstance,
CascaderOption,
CascaderRenderTag,
ExpandTrigger,
Filter,
Key,
Expand Down Expand Up @@ -160,6 +162,7 @@ export const cascaderProps = {
renderLabel: Function as PropType<
(option: CascaderOption, checked: boolean) => VNodeChild
>,
renderTag: Function as PropType<CascaderRenderTag>,
status: String as PropType<FormValidationStatus>,
'onUpdate:value': [Function, Array] as PropType<MaybeArray<OnUpdateValue>>,
onUpdateValue: [Function, Array] as PropType<MaybeArray<OnUpdateValue>>,
Expand Down Expand Up @@ -467,6 +470,25 @@ export default defineComponent({
hoverKeyRef.value = key
}
}
const cascaderRenderTagRef = computed<RenderTag | undefined>(() => {
const { renderTag } = props
if (!renderTag)
return undefined
const { getNode } = treeMateRef.value
return ({ option, handleClose }) => {
const { value } = option
if (value !== undefined) {
const tmNode = getNode(value)
if (tmNode) {
return renderTag({
option: tmNode.rawNode,
handleClose
})
}
}
return value
}
})
const selectedOptionsRef = computed(() => {
if (props.multiple) {
const { showPath, separator, labelField, cascade } = props
Expand Down Expand Up @@ -1063,6 +1085,7 @@ export default defineComponent({
selectedOptions: selectedOptionsRef,
adjustedTo: adjustedToRef,
menuModel: menuModelRef,
cascaderRenderTag: cascaderRenderTagRef,
handleMenuTabout,
handleMenuFocus,
handleMenuBlur,
Expand Down Expand Up @@ -1112,6 +1135,7 @@ export default defineComponent({
selectedOption={this.selectedOption}
selectedOptions={this.selectedOptions}
multiple={this.multiple}
renderTag={this.cascaderRenderTag}
filterable={this.filterable}
clearable={this.clearable}
disabled={this.mergedDisabled}
Expand Down
29 changes: 17 additions & 12 deletions src/cascader/src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,19 @@

export type OnUpdateValue = (
value: string &
number &
string[] &
number[] &
Array<string | number> &
(string | null) &
(number | null) &
(string[] | null) &
(number[] | null) &
(Array<string | number> | null),
number &

Check failure on line 35 in src/cascader/src/interface.ts

View workflow job for this annotation

GitHub Actions / lint (22)

Expected indentation of 4 spaces
string[] &

Check failure on line 36 in src/cascader/src/interface.ts

View workflow job for this annotation

GitHub Actions / lint (22)

Expected indentation of 4 spaces
number[] &

Check failure on line 37 in src/cascader/src/interface.ts

View workflow job for this annotation

GitHub Actions / lint (22)

Expected indentation of 4 spaces
Array<string | number> &

Check failure on line 38 in src/cascader/src/interface.ts

View workflow job for this annotation

GitHub Actions / lint (22)

Expected indentation of 4 spaces
(string | null) &

Check failure on line 39 in src/cascader/src/interface.ts

View workflow job for this annotation

GitHub Actions / lint (22)

Expected indentation of 4 spaces
(number | null) &

Check failure on line 40 in src/cascader/src/interface.ts

View workflow job for this annotation

GitHub Actions / lint (22)

Expected indentation of 4 spaces
(string[] | null) &

Check failure on line 41 in src/cascader/src/interface.ts

View workflow job for this annotation

GitHub Actions / lint (22)

Expected indentation of 4 spaces
(number[] | null) &

Check failure on line 42 in src/cascader/src/interface.ts

View workflow job for this annotation

GitHub Actions / lint (22)

Expected indentation of 4 spaces
(Array<string | number> | null),
option: null &
CascaderOption &
CascaderOption[] &
Array<CascaderOption | null>,
CascaderOption &
CascaderOption[] &
Array<CascaderOption | null>,
path: null & CascaderOption[] & Array<CascaderOption[] | null>
) => void

Expand Down Expand Up @@ -119,6 +119,11 @@
scroll: (index: number, elSize: number) => void
}

export type CascaderRenderTag = (props: {
option: CascaderOption
handleClose: () => void
}) => VNodeChild

export interface CascaderMenuExposedMethods {
scroll: (depth: number, index: number, elSize: number) => void
showErrorMessage: (label: string) => void
Expand Down