Skip to content
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
12 changes: 11 additions & 1 deletion CHANGELOG.en-US.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
# CHANGELOG

## NEXT_VERSION

`NEXT_VERSION`

### Features

- `n-config-provider` adds `render-empty` prop to globally customize the rendering of empty state

## 2.43.2

`2025-11-16`

### Fixes

- Fix seemly dependency version range allows incompatible versions.
- Fix `n-progress` style is incorrect after using the dashboard mode exceeding 100%, closes [#6627](https://github.com/tusen-ai/naive-ui/issues/6627)
- Fix `n-modal`'s outside content can't be interacted with `show-mask` is set to `false`.

### Feats
### Features

- `n-date-picker` prop `defaultTime` can also accept a function that will return a formatted string
- `n-steps` adds `content-placement` prop, closes [#7044](https://github.com/tusen-ai/naive-ui/issues/7044).
Expand Down
12 changes: 11 additions & 1 deletion CHANGELOG.zh-CN.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
# CHANGELOG

## NEXT_VERSION

`NEXT_VERSION`

### Features

- `n-config-provider` 新增 `render-empty` 属性,用于全局自定义空状态的渲染

## 2.43.2

`2025-11-16`

### Fixes

- 修复 seemly 依赖的版本未更新到最新
- 修复 `n-progress` 使用仪表盘模式超过 100% 之后样式不正确,关闭 [#6627](https://github.com/tusen-ai/naive-ui/issues/6627)
- 修复 `n-modal` 在 `show-mask` 为 `false` 的情况下,外部内容不能被操作

### Feats
### Features

- `n-date-picker` 的 `defaultTime` 属性可以接受返回格式化字符串的函数
- `n-steps` 增加 `content-placement` 属性,关闭 [#7044](https://github.com/tusen-ai/naive-ui/issues/7044)
Expand Down
22 changes: 15 additions & 7 deletions src/_internal/select-menu/src/SelectMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
computed,
defineComponent,
h,
inject,
nextTick,
onBeforeUnmount,
onMounted,
Expand All @@ -36,6 +37,7 @@ import { VirtualList } from 'vueuc'
import { useConfig, useRtl, useTheme, useThemeClass } from '../../../_mixins'
import { resolveSlot, resolveWrappedSlot, useOnResize } from '../../../_utils'
import { createKey } from '../../../_utils/cssr'
import { configProviderInjectionKey } from '../../../config-provider/src/context'
import { NEmpty } from '../../../empty'
import NFocusDetector from '../../focus-detector'
import NInternalLoading from '../../loading'
Expand Down Expand Up @@ -118,6 +120,7 @@ export default defineComponent({
},
setup(props) {
const { mergedClsPrefixRef, mergedRtlRef } = useConfig(props)
const NConfigProvider = inject(configProviderInjectionKey, null)
const rtlEnabledRef = useRtl(
'InternalSelectMenu',
mergedRtlRef,
Expand Down Expand Up @@ -425,6 +428,7 @@ export default defineComponent({
return {
mergedTheme: themeRef,
mergedClsPrefix: mergedClsPrefixRef,
mergedRenderEmpty: NConfigProvider?.mergedRenderEmptyRef.value,
rtlEnabled: rtlEnabledRef,
virtualListRef,
scrollbarRef,
Expand Down Expand Up @@ -583,13 +587,17 @@ export default defineComponent({
</NScrollbar>
) : (
<div class={`${clsPrefix}-base-select-menu__empty`} data-empty>
{resolveSlot($slots.empty, () => [
<NEmpty
theme={mergedTheme.peers.Empty}
themeOverrides={mergedTheme.peerOverrides.Empty}
size={this.size}
/>
])}
{resolveSlot($slots.empty, () => {
return [
this.mergedRenderEmpty?.('Select') || (
<NEmpty
theme={mergedTheme.peers.Empty}
themeOverrides={mergedTheme.peerOverrides.Empty}
size={this.size}
/>
)
]
})}
</div>
)}
{resolveWrappedSlot(
Expand Down
19 changes: 13 additions & 6 deletions src/cascader/src/CascaderMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
import { NBaseMenuMask } from '../../_internal'
import FocusDetector from '../../_internal/focus-detector'
import { resolveSlot, resolveWrappedSlot, useOnResize } from '../../_utils'
import { configProviderInjectionKey } from '../../config-provider/src/context'
import { NEmpty } from '../../empty'
import NCascaderSubmenu from './CascaderSubmenu'
import { cascaderInjectionKey } from './interface'
Expand Down Expand Up @@ -68,6 +69,7 @@ export default defineComponent({
mergedThemeRef,
getColumnStyleRef
} = inject(cascaderInjectionKey)!
const NConfigProvider = inject(configProviderInjectionKey, null)
const submenuInstRefs: CascaderSubmenuInstance[] = []
const maskInstRef = ref<MenuMaskRef | null>(null)
const selfElRef = ref<HTMLElement | null>(null)
Expand Down Expand Up @@ -112,6 +114,7 @@ export default defineComponent({
return {
isMounted: isMountedRef,
mergedClsPrefix: mergedClsPrefixRef,
mergedRenderEmpty: NConfigProvider?.mergedRenderEmptyRef.value,
selfElRef,
submenuInstRefs,
maskInstRef,
Expand Down Expand Up @@ -165,12 +168,16 @@ export default defineComponent({
</div>
) : (
<div class={`${mergedClsPrefix}-cascader-menu__empty`}>
{resolveSlot(this.$slots.empty, () => [
<NEmpty
theme={mergedTheme.peers.Empty}
themeOverrides={mergedTheme.peerOverrides.Empty}
/>
])}
{resolveSlot(this.$slots.empty, () => {
return [
this.mergedRenderEmpty?.('Cascader') || (
<NEmpty
theme={mergedTheme.peers.Empty}
themeOverrides={mergedTheme.peerOverrides.Empty}
/>
)
]
})}
</div>
)}
{resolveWrappedSlot(
Expand Down
1 change: 1 addition & 0 deletions src/config-provider/demos/enUS/index.demo-entry.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ inline-theme-disabled.vue
| locale | `Locale \| null` | `undefined` | The locale object to be consumed by its child. If set to `null` it will use the default `enUS` locale. If set to `undefined` it will inherit its parent `n-config-provider`. | |
| namespace | `string` | `undefined` | Class name of detached parts of components inside `n-config-provider` | |
| preflight-style-disabled | `boolean` | `false` | Whether to disabled preflight style of naive-ui. If you disable it, you can take control of all global css. Also you can use `n-global-style` to apply global style (which is recommend since global style will be reactive). | 2.29.0 |
| render-empty | `(componentName: 'Cascader' \| 'DataTable' \| 'Select' \| 'Transfer' \| 'Tree' \| 'TreeSelect') => VNodeChild` | `undefined` | The render function to be consumed by its child to render empty state. If set to `undefined` it will inherit its parent `n-config-provider`. | |
| style-mount-target | `ParentNode` | `undefined` | Mounting target of style elements of components. Note that this prop is not reactive. | 2.40.0 |
| tag | `string` | `'div'` | What tag `n-config-provider` will be rendered as | |
| theme | `Theme \| null` | `undefined` | The theme object to be consumed by its child. If set to `null` it will use the default light theme. If set to `undefined` it will inherit its parent `n-config-provider`. For more details please see [Customizing Theme](../docs/customize-theme). | |
Expand Down
1 change: 1 addition & 0 deletions src/config-provider/demos/zhCN/index.demo-entry.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ inline-theme-disabled.vue
| locale | `Locale \| null` | `undefined` | 对后代组件生效的语言对象,为 `null` 时会使用默认 `enUS`,为 `undefined` 时会继承上级 `n-config-provider` | |
| namespace | `string` | `undefined` | `n-config-provider` 内部组件被卸载于其他位置的 DOM 的类名 | |
| preflight-style-disabled | `boolean` | `false` | 是否禁用默认样式,如果你禁用了它,便可以完全控制全局样式。你也可以使用 `n-global-style` 去挂载全局样式(推荐,样式是响应式的) | 2.29.0 |
| render-empty | `(componentName: 'Cascader' \| 'DataTable' \| 'Select' \| 'Transfer' \| 'Tree' \| 'TreeSelect') => VNodeChild` | `undefined` | 对后代组件生效的空状态渲染函数,用于自定义空状态的显示内容。为 `undefined` 时会继承上级 `n-config-provider` | |
| style-mount-target | `ParentNode` | `undefined` | 组件样式的挂载位置。注意,该属性不是响应式的。 | 2.40.0 |
| tag | `string` | `'div'` | `n-config-provider` 被渲染成的元素 | |
| theme | `Theme \| null` | `undefined` | 对后代组件生效的主题对象,为 `null` 时会使用默认亮色,为 `undefined` 时会继承上级 `n-config-provider`。更多信息参见[调整主题](../docs/customize-theme) | |
Expand Down
13 changes: 12 additions & 1 deletion src/config-provider/src/ConfigProvider.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ComputedRef, ExtractPropTypes, PropType } from 'vue'
import type { ComputedRef, ExtractPropTypes, PropType, VNodeChild } from 'vue'
import type { Hljs } from '../../_mixins'
import type { NDateLocale, NLocale } from '../../locales'
import type {
Expand All @@ -9,6 +9,7 @@ import type {
} from './interface'
import type {
Breakpoints,
RenderEmptyComponentName,
RtlEnabledState,
RtlProp
} from './internal-interface'
Expand Down Expand Up @@ -49,6 +50,9 @@ export const configProviderProps = {
type: Boolean,
default: undefined
},
renderEmpty: Function as PropType<
(componentName: RenderEmptyComponentName) => VNodeChild
>,
// deprecated
as: {
type: String as PropType<string | undefined>,
Expand Down Expand Up @@ -125,6 +129,12 @@ export default defineComponent({
return componentOptions
return NConfigProvider?.mergedComponentPropsRef.value
})
const mergedRenderEmptyRef = computed(() => {
const { renderEmpty } = props
return renderEmpty === undefined
? NConfigProvider?.mergedRenderEmptyRef.value
: renderEmpty
})
const mergedClsPrefixRef = computed(() => {
const { clsPrefix } = props
if (clsPrefix !== undefined)
Expand Down Expand Up @@ -187,6 +197,7 @@ export default defineComponent({
mergedRtlRef,
mergedIconsRef,
mergedComponentPropsRef,
mergedRenderEmptyRef,
mergedBorderedRef,
mergedNamespaceRef,
mergedClsPrefixRef,
Expand Down
12 changes: 12 additions & 0 deletions src/config-provider/src/internal-interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,14 @@ export interface GlobalThemeWithoutCommon {
InputOtp?: InputOtpTheme
}

export type RenderEmptyComponentName
= | 'Cascader'
| 'DataTable'
| 'Select'
| 'Transfer'
| 'Tree'
| 'TreeSelect'

export interface GlobalComponentConfig {
Pagination?: {
inputSize?: InputSize
Expand All @@ -220,6 +228,7 @@ export interface GlobalComponentConfig {
buttonSize?: ButtonSize
}
Empty?: Pick<EmptyProps, 'description' | 'renderIcon'>
renderEmpty?: (componentName: RenderEmptyComponentName) => VNodeChild
}

export interface GlobalIconConfig {
Expand Down Expand Up @@ -267,6 +276,9 @@ export interface ConfigProviderInjection {
mergedKatexRef: Ref<Katex | undefined>
mergedComponentPropsRef: Ref<GlobalComponentConfig | undefined>
mergedIconsRef: Ref<GlobalIconConfig | undefined>
mergedRenderEmptyRef: Ref<
((componentName: RenderEmptyComponentName) => VNodeChild) | undefined
>
mergedThemeRef: Ref<GlobalTheme | undefined>
mergedThemeOverridesRef: Ref<GlobalThemeOverrides | undefined>
mergedRtlRef: Ref<RtlEnabledState | undefined>
Expand Down
17 changes: 11 additions & 6 deletions src/data-table/src/TableParts/Body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,7 @@ export default defineComponent({
summary: summaryRef,
mergedClsPrefix: mergedClsPrefixRef,
mergedTheme: mergedThemeRef,
mergedRenderEmpty: NConfigProvider?.mergedRenderEmptyRef.value,
scrollX: scrollXRef,
cols: colsRef,
loading: loadingRef,
Expand Down Expand Up @@ -1156,12 +1157,16 @@ export default defineComponent({
style={this.bodyStyle}
ref="emptyElRef"
>
{resolveSlot(this.dataTableSlots.empty, () => [
<NEmpty
theme={this.mergedTheme.peers.Empty}
themeOverrides={this.mergedTheme.peerOverrides.Empty}
/>
])}
{resolveSlot(this.dataTableSlots.empty, () => {
return [
this.mergedRenderEmpty?.('DataTable') || (
<NEmpty
theme={this.mergedTheme.peers.Empty}
themeOverrides={this.mergedTheme.peerOverrides.Empty}
/>
)
]
})}
</div>
)
if (this.shouldDisplaySomeTablePart) {
Expand Down
20 changes: 14 additions & 6 deletions src/legacy-transfer/src/TransferList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
} from 'vue'
import { VirtualList } from 'vueuc'
import { NScrollbar } from '../../_internal'
import { configProviderInjectionKey } from '../../config-provider/src/context'
import { NEmpty } from '../../empty'
import { transferInjectionKey } from './interface'
import NTransferListItem from './TransferListItem'
Expand Down Expand Up @@ -51,6 +52,7 @@ export default defineComponent({
},
setup() {
const { mergedThemeRef, mergedClsPrefixRef } = inject(transferInjectionKey)!
const NConfigProvider = inject(configProviderInjectionKey, null)
const scrollerInstRef = ref<ScrollbarInst | null>(null)
const vlInstRef = ref<VirtualListInst | null>(null)
function syncVLScroller(): void {
Expand All @@ -73,6 +75,7 @@ export default defineComponent({
return {
mergedTheme: mergedThemeRef,
mergedClsPrefix: mergedClsPrefixRef,
mergedRenderEmpty: NConfigProvider?.mergedRenderEmptyRef.value,
scrollerInstRef,
vlInstRef,
syncVLScroller,
Expand Down Expand Up @@ -152,13 +155,18 @@ export default defineComponent({
css={!this.isInputing}
>
{{
default: () =>
this.options.length ? null : (
<NEmpty
theme={mergedTheme.peers.Empty}
themeOverrides={mergedTheme.peerOverrides.Empty}
/>
default: () => {
if (this.options.length)
return null
return (
this.mergedRenderEmpty?.('Transfer') || (
<NEmpty
theme={mergedTheme.peers.Empty}
themeOverrides={mergedTheme.peerOverrides.Empty}
/>
)
)
}
}}
</Transition>
</>
Expand Down
13 changes: 9 additions & 4 deletions src/transfer/src/TransferList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { Option } from './interface'
import { defineComponent, h, inject, ref } from 'vue'
import { VirtualList } from 'vueuc'
import { NScrollbar } from '../../_internal'
import { configProviderInjectionKey } from '../../config-provider/src/context'
import { NEmpty } from '../../empty'
import { transferInjectionKey } from './interface'
import NTransferListItem from './TransferListItem'
Expand Down Expand Up @@ -32,6 +33,7 @@ export default defineComponent({
},
setup() {
const { mergedThemeRef, mergedClsPrefixRef } = inject(transferInjectionKey)!
const NConfigProvider = inject(configProviderInjectionKey, null)
const scrollerInstRef = ref<ScrollbarInst | null>(null)
const vlInstRef = ref<VirtualListInst | null>(null)
function syncVLScroller(): void {
Expand All @@ -54,6 +56,7 @@ export default defineComponent({
return {
mergedTheme: mergedThemeRef,
mergedClsPrefix: mergedClsPrefixRef,
mergedRenderEmpty: NConfigProvider?.mergedRenderEmptyRef.value,
scrollerInstRef,
vlInstRef,
syncVLScroller,
Expand All @@ -65,10 +68,12 @@ export default defineComponent({
const { mergedTheme, options } = this
if (options.length === 0) {
return (
<NEmpty
theme={mergedTheme.peers.Empty}
themeOverrides={mergedTheme.peerOverrides.Empty}
/>
this.mergedRenderEmpty?.('Transfer') || (
<NEmpty
theme={mergedTheme.peers.Empty}
themeOverrides={mergedTheme.peerOverrides.Empty}
/>
)
)
}
const { mergedClsPrefix, virtualScroll, source, disabled, syncVLScroller }
Expand Down
Loading
Loading