Skip to content

Commit

Permalink
feat(cascader): adds render-prefix & render-suffix props
Browse files Browse the repository at this point in the history
  • Loading branch information
07akioni committed Apr 23, 2024
1 parent 4845729 commit d1d306c
Show file tree
Hide file tree
Showing 14 changed files with 215 additions and 138 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
- `n-scrollbar` adds `content-style` and `content-class` props, closes [#4497](https://github.com/tusen-ai/naive-ui/issues/4497).
- `n-image` adds `render-toolbar` prop.
- `n-cascader` adds `get-column-style` prop.
- `n-cascader` adds `get-render-prefix` prop.
- `n-cascader` adds `get-render-suffix` prop.
- `n-image` optimizes download icon style.

## 2.38.1
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
- `n-scrollbar` 新增 `content-style``content-class` 属性,关闭 [#4497](https://github.com/tusen-ai/naive-ui/issues/4497)
- `n-image` 新增 `render-toolbar` 属性
- `n-cascader` 新增 `get-column-width` 属性
- `n-cascader` 新增 `render-prefix` 属性
- `n-cascader` 新增 `render-suffix` 属性
- `n-image` 优化下载按钮图标

## 2.38.1
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 @@ -49,7 +49,9 @@ status.vue
| placeholder | `string` | `'Please Select'` | Placeholder text. | |
| placement | `'top-start' \| 'top' \| 'top-end' \| 'right-start' \| 'right' \| 'right-end' \| 'bottom-start' \| 'bottom' \| 'bottom-end' \| 'left-start' \| 'left' \| 'left-end'` | `'bottom-start'` | Cascader placement. | 2.25.0 |
| remote | `boolean` | `false` | Whether to obtain data remotely. | |
| render-prefix | `(info: { option: CascaderOption, node: VNode \| null, checked: boolean }) => VNodeChild` | `undefined` | Render function of all the options' prefix. | NEXT_VERSION |
| 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. | 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
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 @@ -50,7 +50,9 @@ default-value-debug.vue
| placeholder | `string` | `'请选择'` | 提示信息 | |
| placement | `'top-start' \| 'top' \| 'top-end' \| 'right-start' \| 'right' \| 'right-end' \| 'bottom-start' \| 'bottom' \| 'bottom-end' \| 'left-start' \| 'left' \| 'left-end'` | `'bottom-start'` | 弹出位置 | 2.25.0 |
| remote | `boolean` | `false` | 是否远程获取数据 | |
| render-prefix | `(info: { option: CascaderOption, node: VNode \| null, checked: boolean }) => VNodeChild` | `undefined` | 节点前缀的渲染函数 | NEXT_VERSION |
| render-label | `(option: CascaderOption, checked: boolean) => VNodeChild` | `undefined` | Cascader 菜单选项标签渲染函数 | 2.24.0 |
| render-suffix | `(info: { option: CascaderOption, checked: boolean }) => VNodeChild` | `undefined` | 节点后缀的渲染函数 | NEXT_VERSION |
| separator | `string` | `' / '` | 数据分隔符 | |
| show | `boolean` | `undefined` | 是否打开菜单 | |
| show-path | `boolean` | `true` | 是否在选择器中显示选项路径 | |
Expand Down
19 changes: 18 additions & 1 deletion src/cascader/src/Cascader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import {
watchEffect,
type VNodeChild,
type HTMLAttributes,
nextTick
nextTick,
type VNode
} from 'vue'
import {
createTreeMate,
Expand Down Expand Up @@ -172,6 +173,20 @@ export const cascaderProps = {
getColumnStyle: Function as PropType<
(detail: { level: number }) => string | CSSProperties
>,
renderPrefix: Function as PropType<
(props: {
option: CascaderOption
checked: boolean
node: VNode | null
}) => VNodeChild
>,
renderSuffix: Function as PropType<
(props: {
option: CascaderOption
checked: boolean
node: VNode | null
}) => VNodeChild
>,
// deprecated
onChange: [Function, Array] as PropType<MaybeArray<OnUpdateValue> | undefined>
} as const
Expand Down Expand Up @@ -877,6 +892,8 @@ export default defineComponent({
labelFieldRef: toRef(props, 'labelField'),
renderLabelRef: toRef(props, 'renderLabel'),
getColumnStyleRef: toRef(props, 'getColumnStyle'),
renderPrefixRef: toRef(props, 'renderPrefix'),
renderSuffixRef: toRef(props, 'renderSuffix'),
syncCascaderMenuPosition,
syncSelectMenuPosition,
updateKeyboardKey,
Expand Down
168 changes: 102 additions & 66 deletions src/cascader/src/CascaderOption.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import {
inject,
defineComponent,
type PropType,
Transition
Transition,
type VNode
} from 'vue'
import { useMemo } from 'vooks'
import { NCheckbox } from '../../checkbox'
Expand Down Expand Up @@ -39,6 +40,8 @@ export default defineComponent({
mergedThemeRef,
labelFieldRef,
showCheckboxRef,
renderPrefixRef,
renderSuffixRef,
updateHoverKey,
updateKeyboardKey,
addLoadingKey,
Expand Down Expand Up @@ -171,88 +174,121 @@ export default defineComponent({
handleCheckboxUpdateValue,
mergedHandleMouseEnter: mergedHandleMouseEnterRef,
mergedHandleMouseMove: mergedHandleMouseMoveRef,
renderLabel: renderLabelRef
renderLabel: renderLabelRef,
renderPrefix: renderPrefixRef,
renderSuffix: renderSuffixRef
}
},
render () {
const { mergedClsPrefix, renderLabel } = this
const {
mergedClsPrefix,
showCheckbox,
renderLabel,
renderPrefix,
renderSuffix
} = this

let prefixNode: VNode | null = null
if (showCheckbox || renderPrefix) {
const originalNode = this.showCheckbox ? (
<NCheckbox
focusable={false}
data-checkbox
disabled={this.disabled}
checked={this.checked}
indeterminate={this.indeterminate}
theme={this.mergedTheme.peers.Checkbox}
themeOverrides={this.mergedTheme.peerOverrides.Checkbox}
onUpdateChecked={this.handleCheckboxUpdateValue}
/>
) : null
prefixNode = (
<div class={`${mergedClsPrefix}-cascader-option__prefix`}>
{renderPrefix
? renderPrefix({
option: this.tmNode.rawNode,
checked: this.checked,
node: originalNode
})
: originalNode}
</div>
)
}
let suffixNode: VNode | null = null
const originalSuffixChild = (
<div class={`${mergedClsPrefix}-cascader-option-icon-placeholder`}>
{!this.isLeaf ? (
<NBaseLoading
clsPrefix={mergedClsPrefix}
scale={0.85}
strokeWidth={24}
show={this.isLoading}
class={`${mergedClsPrefix}-cascader-option-icon`}
>
{{
default: () => (
<NBaseIcon
clsPrefix={mergedClsPrefix}
key="arrow"
class={`${mergedClsPrefix}-cascader-option-icon ${mergedClsPrefix}-cascader-option-icon--arrow`}
>
{{
default: () => <ChevronRightIcon />
}}
</NBaseIcon>
)
}}
</NBaseLoading>
) : this.checkStrategy === 'child' &&
!(this.multiple && this.cascade) ? (
<Transition name="fade-in-scale-up-transition">
{{
default: () =>
this.checked ? (
<NBaseIcon
clsPrefix={mergedClsPrefix}
class={`${mergedClsPrefix}-cascader-option-icon ${mergedClsPrefix}-cascader-option-icon--checkmark`}
>
{{ default: () => <CheckmarkIcon /> }}
</NBaseIcon>
) : null
}}
</Transition>
) : null}
</div>
)
suffixNode = (
<div class={`${mergedClsPrefix}-cascader-option__suffix`}>
{renderSuffix
? renderSuffix({
option: this.tmNode.rawNode,
checked: this.checked,
node: originalSuffixChild
})
: originalSuffixChild}
</div>
)
return (
<div
class={[
`${mergedClsPrefix}-cascader-option`,
{
[`${mergedClsPrefix}-cascader-option--pending`]:
this.keyboardPending || this.hoverPending,
[`${mergedClsPrefix}-cascader-option--disabled`]: this.disabled,
[`${mergedClsPrefix}-cascader-option--show-prefix`]:
this.showCheckbox
}
this.keyboardPending ||
(this.hoverPending &&
`${mergedClsPrefix}-cascader-option--pending`),
this.disabled && `${mergedClsPrefix}-cascader-option--disabled`,
this.showCheckbox && `${mergedClsPrefix}-cascader-option--show-prefix`
]}
onMouseenter={this.mergedHandleMouseEnter}
onMousemove={this.mergedHandleMouseMove}
onClick={this.handleClick}
>
{this.showCheckbox ? (
<div class={`${mergedClsPrefix}-cascader-option__prefix`}>
<NCheckbox
focusable={false}
data-checkbox
disabled={this.disabled}
checked={this.checked}
indeterminate={this.indeterminate}
theme={this.mergedTheme.peers.Checkbox}
themeOverrides={this.mergedTheme.peerOverrides.Checkbox}
onUpdateChecked={this.handleCheckboxUpdateValue}
/>
</div>
) : null}
{prefixNode}
<span class={`${mergedClsPrefix}-cascader-option__label`}>
{renderLabel
? renderLabel(this.tmNode.rawNode, this.checked)
: this.label}
</span>
<div class={`${mergedClsPrefix}-cascader-option__suffix`}>
<div class={`${mergedClsPrefix}-cascader-option-icon-placeholder`}>
{!this.isLeaf ? (
<NBaseLoading
clsPrefix={mergedClsPrefix}
scale={0.85}
strokeWidth={24}
show={this.isLoading}
class={`${mergedClsPrefix}-cascader-option-icon`}
>
{{
default: () => (
<NBaseIcon
clsPrefix={mergedClsPrefix}
key="arrow"
class={`${mergedClsPrefix}-cascader-option-icon ${mergedClsPrefix}-cascader-option-icon--arrow`}
>
{{
default: () => <ChevronRightIcon />
}}
</NBaseIcon>
)
}}
</NBaseLoading>
) : this.checkStrategy === 'child' &&
!(this.multiple && this.cascade) ? (
<Transition name="fade-in-scale-up-transition">
{{
default: () =>
this.checked ? (
<NBaseIcon
clsPrefix={mergedClsPrefix}
class={`${mergedClsPrefix}-cascader-option-icon ${mergedClsPrefix}-cascader-option-icon--checkmark`}
>
{{ default: () => <CheckmarkIcon /> }}
</NBaseIcon>
) : null
}}
</Transition>
) : null}
</div>
</div>
{suffixNode}
</div>
)
}
Expand Down
18 changes: 17 additions & 1 deletion src/cascader/src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { CheckStrategy, TreeNode } from 'treemate'
import type { MergedTheme } from '../../_mixins'
import type { NLocale } from '../../locales'
import type { CascaderTheme } from '../styles'
import type { CSSProperties, Ref, Slots, VNodeChild } from 'vue'
import type { CSSProperties, Ref, Slots, VNode, VNodeChild } from 'vue'
import { createInjectionKey } from '../../_utils'

export type ValueAtom = string | number
Expand Down Expand Up @@ -82,6 +82,22 @@ export interface CascaderInjection {
getColumnStyleRef: Ref<
((detail: { level: number }) => string | CSSProperties) | undefined
>
renderPrefixRef: Ref<
| ((info: {
option: CascaderOption
checked: boolean
node: VNode | null
}) => VNodeChild)
| undefined
>
renderSuffixRef: Ref<
| ((info: {
option: CascaderOption
checked: boolean
node: VNode | null
}) => VNodeChild)
| undefined
>
syncCascaderMenuPosition: () => void
syncSelectMenuPosition: () => void
updateKeyboardKey: (value: Key | null) => void
Expand Down
Loading

0 comments on commit d1d306c

Please sign in to comment.