refactor: impl slots type in a correct way

This commit is contained in:
07akioni 2025-01-02 01:18:33 +08:00
parent c5c419d75d
commit 3cb6a61ebf
89 changed files with 552 additions and 395 deletions

View File

@ -2,13 +2,15 @@
## NEXT_VERSION
### Features
### Breaking Changes
- Add slot type for all components.
- (**Vue 3.3+ required**) Add slot type for all components.
### Fixes
- Fix `n-data-table` may have multiple expand trigger with tree data.
- Fix `n-date-picker`'s `confirm`, `now`, `clear` slots doesn't work with `'month'`, `'monthrange'`, `'quarter'`, `'quarterrange'`, `'year'` and `'yearrange'` type.
- Fix `n-input`'s `render-count` prop doesn't work when type is not `'textarea'`.
## 2.40.4

View File

@ -2,13 +2,15 @@
## NEXT_VERSION
### Features
### Breaking Changes
- 为所有的组件增加插槽类型
- (需要 Vue 3.3+为所有的组件增加插槽类型标注
### Fixes
- 修复 `n-data-table` 在使用树形数据的时候出现多个展开 icon
- 修复 `n-date-picker``confirm``now``clear` 插槽对 `'month'``'monthrange'``'quarter'``'quarterrange'``'year'``'yearrange'` 类型不生效
- 修复 `n-input``render-count` 属性在类型非 `'textarea'` 时不生效
## 2.40.4

View File

@ -25,6 +25,7 @@ export {
createRefSetter,
flatten,
getFirstSlotVNode,
getFirstSlotVNodeWithTypedProps,
getSlot,
getVNodeChildren,
isNodeVShowFalse,
@ -36,6 +37,7 @@ export {
render,
resolveSlot,
resolveSlotWithProps,
resolveSlotWithTypedProps,
resolveWrappedSlot,
resolveWrappedSlotWithProps,
Wrapper

View File

@ -22,3 +22,19 @@ export function getFirstSlotVNode(
return null
}
}
export function getFirstSlotVNodeWithTypedProps<T>(
slotName: string,
slot: (props: T) => VNode[],
props: T
): VNode | null {
const slotContent = flatten(slot(props))
// vue will normalize the slot, so slot must be an array
if (slotContent.length === 1) {
return slotContent[0]
}
else {
warn('getFirstSlotVNode', `slot[${slotName}] should have exactly one child`)
return null
}
}

View File

@ -4,7 +4,10 @@ export { createDataKey } from './create-data-key'
export { createInjectionKey } from './create-injection-key'
export { createRefSetter } from './create-ref-setter'
export { flatten } from './flatten'
export { getFirstSlotVNode } from './get-first-slot-vnode'
export {
getFirstSlotVNode,
getFirstSlotVNodeWithTypedProps
} from './get-first-slot-vnode'
export { getSlot } from './get-slot'
export { getVNodeChildren } from './get-v-node-children'
export { isNodeVShowFalse } from './is-node-v-show-false'
@ -17,6 +20,7 @@ export {
isSlotEmpty,
resolveSlot,
resolveSlotWithProps,
resolveSlotWithTypedProps,
resolveWrappedSlot,
resolveWrappedSlotWithProps
} from './resolve-slot'

View File

@ -47,6 +47,14 @@ export function resolveSlotWithProps<T>(
return (slot && ensureValidVNode(slot(props))) || fallback(props)
}
export function resolveSlotWithTypedProps<T>(
slot: Slot<T> | undefined,
props: T,
fallback: (props: T) => VNodeArrayChildren
): VNodeArrayChildren {
return (slot && ensureValidVNode(slot(props))) || fallback(props)
}
/**
* Resolve slot with wrapper if content exists, no fallback
*/

View File

@ -11,6 +11,7 @@ import {
type PropType,
ref,
type SlotsType,
type VNode,
watchEffect
} from 'vue'
import { NBaseClose, NBaseIcon, NFadeInExpandTransition } from '../../_internal'
@ -58,9 +59,9 @@ export const alertProps = {
export type AlertProps = ExtractPublicPropTypes<typeof alertProps>
export interface AlertSlots {
default?: any
icon?: any
header?: any
default?: () => VNode[]
icon?: () => VNode[]
header?: () => VNode[]
}
export default defineComponent({

View File

@ -1,7 +1,7 @@
export { autoCompleteProps, default as NAutoComplete } from './src/AutoComplete'
export type { AutoCompleteProps, AutoCompleteSlots } from './src/AutoComplete'
export type {
AutoCompleteDefaultSlotOptions,
AutoCompleteDefaultSlotProps,
AutoCompleteGroupOption,
AutoCompleteInst,
AutoCompleteOption

View File

@ -12,7 +12,7 @@ import type {
} from '../../select/src/interface'
import type { AutoCompleteTheme } from '../styles'
import type {
AutoCompleteDefaultSlotOptions,
AutoCompleteDefaultSlotProps,
AutoCompleteInst,
AutoCompleteOption,
AutoCompleteOptions,
@ -37,6 +37,7 @@ import {
type SlotsType,
toRef,
Transition,
type VNode,
watchEffect,
withDirectives
} from 'vue'
@ -49,7 +50,7 @@ import { useConfig, useFormItem, useTheme, useThemeClass } from '../../_mixins'
import {
call,
type ExtractPublicPropTypes,
getFirstSlotVNode,
getFirstSlotVNodeWithTypedProps,
type MaybeArray,
useAdjustedTo,
warnOnce
@ -117,10 +118,10 @@ export const autoCompleteProps = {
export type AutoCompleteProps = ExtractPublicPropTypes<typeof autoCompleteProps>
export interface AutoCompleteSlots {
default?: (options: AutoCompleteDefaultSlotOptions) => any
empty?: any
prefix?: any
suffix?: any
default?: (options: AutoCompleteDefaultSlotProps) => VNode[]
empty?: () => VNode[]
prefix?: () => VNode[]
suffix?: () => VNode[]
}
export default defineComponent({
@ -373,12 +374,16 @@ export default defineComponent({
default: () => {
const defaultSlot = this.$slots.default
if (defaultSlot) {
return getFirstSlotVNode(this.$slots, 'default', {
handleInput: this.handleInput,
handleFocus: this.handleFocus,
handleBlur: this.handleBlur,
value: this.mergedValue
} as AutoCompleteDefaultSlotOptions)
return getFirstSlotVNodeWithTypedProps(
'default',
defaultSlot,
{
handleInput: this.handleInput,
handleFocus: this.handleFocus,
handleBlur: this.handleBlur,
value: this.mergedValue
}
)
}
const { mergedTheme } = this
return (

View File

@ -23,10 +23,9 @@ export interface AutoCompleteInst {
blur: () => void
}
export interface AutoCompleteDefaultSlotOptions {
export interface AutoCompleteDefaultSlotProps {
handleInput: (value: string) => void
handleFocus: (e: FocusEvent) => void
handleBlur: (e: FocusEvent) => void
value: string
theme: string | null
value: string | null
}

View File

@ -1,6 +1,10 @@
export { avatarGroupProps, default as NAvatarGroup } from './src/AvatarGroup'
export type { AvatarGroupOption, AvatarGroupProps } from './src/AvatarGroup'
export type {
AvatarGroupAvatarSlotOptions,
AvatarGroupRestSlotOptions
AvatarGroupOption,
AvatarGroupProps,
AvatarGroupSlots
} from './src/AvatarGroup'
export type {
AvatarGroupAvatarSlotProps,
AvatarGroupRestSlotProps
} from './src/interface'

View File

@ -3,8 +3,8 @@ import type { ExtractPublicPropTypes } from '../../_utils'
import type { Size } from '../../avatar/src/interface'
import type { AvatarGroupTheme } from '../styles'
import type {
AvatarGroupAvatarSlotOptions,
AvatarGroupRestSlotOptions
AvatarGroupAvatarSlotProps,
AvatarGroupRestSlotProps
} from './interface'
import {
computed,
@ -13,7 +13,8 @@ import {
h,
type PropType,
provide,
type SlotsType
type SlotsType,
type VNode
} from 'vue'
import { useConfig, useTheme } from '../../_mixins'
import { useRtl } from '../../_mixins/use-rtl'
@ -46,9 +47,9 @@ export const avatarGroupProps = {
export type AvatarGroupProps = ExtractPublicPropTypes<typeof avatarGroupProps>
export interface AvatarGroupSlots {
avatar?: (info: AvatarGroupAvatarSlotOptions) => any
rest?: (info: AvatarGroupRestSlotOptions) => any
default?: any
avatar?: (props: AvatarGroupAvatarSlotProps) => VNode[]
rest?: (props: AvatarGroupRestSlotProps) => VNode[]
default?: () => VNode[]
}
export default defineComponent({

View File

@ -1,8 +1,10 @@
export interface AvatarGroupAvatarSlotOptions {
option: Record<string, any>
import type { AvatarGroupOption } from './AvatarGroup'
export interface AvatarGroupAvatarSlotProps {
option: AvatarGroupOption
}
export interface AvatarGroupRestSlotOptions {
options: Array<any>
export interface AvatarGroupRestSlotProps {
options: Array<AvatarGroupOption>
rest: number
}

View File

@ -13,6 +13,7 @@ import {
type PropType,
ref,
type SlotsType,
type VNode,
type VNodeChild,
watch,
watchEffect
@ -67,9 +68,9 @@ export const avatarProps = {
export type AvatarProps = ExtractPublicPropTypes<typeof avatarProps>
export interface AvatarSlots {
default: any
placeholder: any
fallback: any
default?: () => VNode[]
placeholder?: () => VNode[]
fallback?: () => VNode[]
}
export default defineComponent({

View File

@ -5,7 +5,8 @@ import {
h,
inject,
type PropType,
type SlotsType
type SlotsType,
type VNode
} from 'vue'
import { resolveSlot, warn } from '../../_utils'
import { useBrowserLocation } from '../../_utils/composable/use-browser-location'
@ -26,8 +27,8 @@ export type BreadcrumbItemProps = Partial<
>
export interface BreadcrumbItemSlots {
default?: any
separator?: any
default?: () => VNode[]
separator?: () => VNode[]
}
export default defineComponent({

View File

@ -16,6 +16,7 @@ import {
type PropType,
ref,
type SlotsType,
type VNode,
type VNodeChild,
watchEffect
} from 'vue'
@ -97,8 +98,8 @@ export const buttonProps = {
export type ButtonProps = ExtractPublicPropTypes<typeof buttonProps>
export interface ButtonSlots {
default?: any
icon?: any
default?: () => VNode[]
icon?: () => VNode[]
}
const Button = defineComponent({

View File

@ -2,8 +2,8 @@ import type { ThemeProps } from '../../_mixins'
import type { ExtractPublicPropTypes, MaybeArray } from '../../_utils'
import type { CalendarTheme } from '../styles'
import type {
CalendarDefaultSlotOptions,
CalendarHeaderSlotOptions,
CalendarDefaultSlotProps,
CalendarHeaderSlotProps,
DateItem,
OnPanelChange,
OnUpdateValue
@ -26,12 +26,13 @@ import {
type PropType,
ref,
type SlotsType,
toRef
toRef,
type VNode
} from 'vue'
import { NBaseIcon } from '../../_internal'
import { ChevronLeftIcon, ChevronRightIcon } from '../../_internal/icons'
import { useConfig, useLocale, useTheme, useThemeClass } from '../../_mixins'
import { call, resolveSlotWithProps } from '../../_utils'
import { call, resolveSlotWithTypedProps } from '../../_utils'
import { NButton } from '../../button'
import { NButtonGroup } from '../../button-group'
import { dateArray } from '../../date-picker/src/utils'
@ -54,8 +55,8 @@ export const calendarProps = {
export type CalendarProps = ExtractPublicPropTypes<typeof calendarProps>
export interface CalendarSlots {
default?: (props: CalendarDefaultSlotOptions) => any
header?: (props: CalendarHeaderSlotOptions) => any
default?: (props: CalendarDefaultSlotProps) => VNode[]
header?: (props: CalendarHeaderSlotProps) => VNode[]
}
export default defineComponent({
@ -230,7 +231,7 @@ export default defineComponent({
>
<div class={`${mergedClsPrefix}-calendar-header`}>
<div class={`${mergedClsPrefix}-calendar-header__title`}>
{resolveSlotWithProps(
{resolveSlotWithTypedProps(
$slots.header,
{ year, month: calendarMonth },
() => {

View File

@ -8,13 +8,13 @@ export interface DateItem {
export type OnPanelChange = (info: { year: number, month: number }) => void
export interface CalendarDefaultSlotOptions {
export interface CalendarDefaultSlotProps {
year: number
month: number
date: number
}
export interface CalendarHeaderSlotOptions {
export interface CalendarHeaderSlotProps {
year: number
month: number
}

View File

@ -9,6 +9,7 @@ import {
h,
type PropType,
type SlotsType,
type VNode,
type VNodeChild
} from 'vue'
import { NBaseClose } from '../../_internal'
@ -73,12 +74,12 @@ export const cardProps = {
export type CardProps = ExtractPublicPropTypes<typeof cardProps>
export interface CardSlots {
default?: any
cover?: any
header?: any
'header-extra'?: any
footer?: any
action?: any
default?: () => VNode[]
cover?: () => VNode[]
header?: () => VNode[]
'header-extra'?: () => VNode[]
footer?: () => VNode[]
action?: () => VNode[]
}
export default defineComponent({

View File

@ -2,7 +2,7 @@ export { carouselProps, default as NCarousel } from './src/Carousel'
export type { CarouselProps, CarouselSlots } from './src/Carousel'
export { default as NCarouselItem } from './src/CarouselItem'
export type {
CarouselArrowSlotOptions,
CarouselDotSlotOptions,
CarouselArrowSlotProps,
CarouselDotSlotProps,
CarouselInst
} from './src/interface'

View File

@ -11,8 +11,8 @@ import type { ExtractPublicPropTypes } from '../../_utils'
import type { CarouselTheme } from '../styles'
import type {
ArrowScopedSlotProps,
CarouselArrowSlotOptions,
CarouselDotSlotOptions,
CarouselArrowSlotProps,
CarouselDotSlotProps,
CarouselInst,
DotScopedSlotProps,
Size
@ -40,7 +40,7 @@ import {
} from 'vue'
import { VResizeObserver } from 'vueuc'
import { useConfig, useTheme, useThemeClass } from '../../_mixins'
import { flatten, keep, resolveSlotWithProps } from '../../_utils'
import { flatten, keep, resolveSlotWithTypedProps } from '../../_utils'
import { carouselLight } from '../styles'
import NCarouselArrow from './CarouselArrow'
import {
@ -149,9 +149,9 @@ export const carouselProps = {
export type CarouselProps = ExtractPublicPropTypes<typeof carouselProps>
export interface CarouselSlots {
default?: () => any
arrow?: (info: CarouselArrowSlotOptions) => any
dots?: (info: CarouselDotSlotOptions) => any
default?: () => VNode[]
arrow?: (props: CarouselArrowSlotProps) => VNode[]
dots?: (props: CarouselDotSlotProps) => VNode[]
}
// only one carousel is allowed to trigger touch globally
@ -1041,7 +1041,7 @@ export default defineComponent({
</VResizeObserver>
{this.showDots
&& dotSlotProps.total > 1
&& resolveSlotWithProps(dotsSlot, dotSlotProps, () => [
&& resolveSlotWithTypedProps(dotsSlot, dotSlotProps, () => [
<NCarouselDots
key={dotType + dotPlacement}
total={dotSlotProps.total}
@ -1052,7 +1052,7 @@ export default defineComponent({
/>
])}
{showArrow
&& resolveSlotWithProps(arrowSlot, arrowSlotProps, () => [
&& resolveSlotWithTypedProps(arrowSlot, arrowSlotProps, () => [
<NCarouselArrow />
])}
</div>

View File

@ -26,7 +26,7 @@ export interface Size {
height: number
}
export interface CarouselArrowSlotOptions {
export interface CarouselArrowSlotProps {
total: number
currentIndex: number
to: (index: number) => void
@ -34,7 +34,7 @@ export interface CarouselArrowSlotOptions {
next: () => void
}
export interface CarouselDotSlotOptions {
export interface CarouselDotSlotProps {
total: number
currentIndex: number
to: (index: number) => void

View File

@ -195,10 +195,10 @@ export const cascaderProps = {
export type CascaderProps = ExtractPublicPropTypes<typeof cascaderProps>
export interface CascaderSlots {
action?: any
arrow?: any
empty?: any
'not-found'?: any
action?: () => VNode[]
arrow?: () => VNode[]
empty?: () => VNode[]
'not-found'?: () => VNode[]
}
export default defineComponent({

View File

@ -46,14 +46,15 @@ trigger-areas.vue
| Name | Parameters | Description |
| --- | --- | --- |
| default | `()` | The contents of the collapsible panel. |
| arrow | `(props: { collapsed: boolean })` | Custom icons for folding panels. |
| default | `()` | The contents of the collapsible panel. |
| header | `(props: { collapsed: boolean })` | The content of the header of the collapsed panel node. |
### CollapseItem Slots
| Name | Parameters | Description |
| --- | --- | --- |
| arrow | `(props: { collapsed: boolean })` | The custom icon of the node header of the collapsible panel. |
| default | `()` | The contents of the collapsible panel node. |
| header | `(props: { collapsed: boolean })` | The content of the header of the collapsed panel node. |
| header-extra | `(props: { collapsed: boolean })` | The extra content of the header of the collapsed panel node. |
| arrow | `(props: { collapsed: boolean })` | The custom icon of the node header of the collapsible panel. |

View File

@ -45,16 +45,17 @@ rtl-debug.vue
### Collapse Slots
| 名称 | 参数 | 说明 |
| ------- | --------------------------------- | -------------------- |
| default | `()` | 折叠面板的内容 |
| arrow | `(props: { collapsed: boolean })` | 折叠面板的自定义图标 |
| 名称 | 参数 | 说明 |
| --- | --- | --- |
| arrow | `(props: { collapsed: boolean })` | 折叠面板的自定义图标 |
| default | `()` | 折叠面板的内容 |
| header-extra | `(props: { collapsed: boolean })` | 折叠面板节点头部的额外内容 |
### CollapseItem Slots
| 名称 | 参数 | 说明 |
| --- | --- | --- |
| arrow | `(props: { collapsed: boolean })` | 折叠面板节点头部的自定义图标 |
| default | `()` | 折叠面板节点的内容 |
| header | `(props: { collapsed: boolean })` | 折叠面板节点头部的内容 |
| header-extra | `(props: { collapsed: boolean })` | 折叠面板节点头部的额外内容 |
| arrow | `(props: { collapsed: boolean })` | 折叠面板节点头部的自定义图标 |

View File

@ -3,8 +3,8 @@ export type { CollapseProps, CollapseSlots } from './src/Collapse'
export { collapseItemProps, default as NCollapseItem } from './src/CollapseItem'
export type { CollapseItemProps, CollapseItemSlots } from './src/CollapseItem'
export type {
CollapseArrowSlotOptions,
CollapseItemArrowSlotOptions,
CollapseItemHeaderExtraSlotOptions,
CollapseItemHeaderSlotOptions
CollapseArrowSlotProps,
CollapseItemArrowSlotProps,
CollapseItemHeaderExtraSlotProps,
CollapseItemHeaderSlotProps
} from './src/interface'

View File

@ -1,7 +1,8 @@
import type { ThemeProps } from '../../_mixins'
import type { ExtractPublicPropTypes, MaybeArray } from '../../_utils'
import type {
CollapseArrowSlotOptions,
CollapseArrowSlotProps,
CollapseItemHeaderExtraSlotProps,
HeaderClickInfo,
OnItemHeaderClick,
OnItemHeaderClickImpl,
@ -19,8 +20,8 @@ import {
provide,
type Ref,
ref,
type Slots,
type SlotsType
type SlotsType,
type VNode
} from 'vue'
import { useConfig, useTheme, useThemeClass } from '../../_mixins'
import { useRtl } from '../../_mixins/use-rtl'
@ -85,15 +86,16 @@ export const collapseProps = {
export type CollapseProps = ExtractPublicPropTypes<typeof collapseProps>
export interface CollapseSlots {
default?: any
arrow?: (props: CollapseArrowSlotOptions) => any
default?: () => VNode[]
arrow?: (props: CollapseArrowSlotProps) => VNode[]
'header-extra'?: (props: CollapseItemHeaderExtraSlotProps) => VNode[]
}
export interface NCollapseInjection {
props: ExtractPropTypes<typeof collapseProps>
expandedNamesRef: Ref<string | number | Array<string | number> | null>
mergedClsPrefixRef: Ref<string>
slots: Slots
slots: CollapseSlots
toggleItem: (
collapse: boolean,
name: string | number,

View File

@ -1,12 +1,20 @@
import type { ExtractPublicPropTypes } from '../../_utils'
import type {
CollapseItemArrowSlotOptions,
CollapseItemHeaderExtraSlotOptions,
CollapseItemHeaderSlotOptions
CollapseItemArrowSlotProps,
CollapseItemHeaderExtraSlotProps,
CollapseItemHeaderSlotProps
} from './interface'
import { createId, happensIn } from 'seemly'
import { useMemo } from 'vooks'
import { computed, defineComponent, h, inject, type PropType, toRef } from 'vue'
import {
computed,
defineComponent,
h,
inject,
type PropType,
toRef,
type VNode
} from 'vue'
import { NBaseIcon } from '../../_internal'
import {
ChevronLeftIcon as ArrowLeftIcon,
@ -32,10 +40,10 @@ export const collapseItemProps = {
export type CollapseItemProps = ExtractPublicPropTypes<typeof collapseItemProps>
export interface CollapseItemSlots {
default?: any
header?: (props: CollapseItemHeaderSlotOptions) => any
'header-extra'?: (props: CollapseItemHeaderExtraSlotOptions) => any
arrow?: (props: CollapseItemArrowSlotOptions) => any
default?: () => VNode[]
header?: (props: CollapseItemHeaderSlotProps) => VNode[]
'header-extra'?: (props: CollapseItemHeaderExtraSlotProps) => VNode[]
arrow?: (props: CollapseItemArrowSlotProps) => VNode[]
}
export default defineComponent({
@ -160,14 +168,8 @@ export default defineComponent({
{resolveSlotWithProps(arrowSlot, { collapsed }, () => [
<NBaseIcon clsPrefix={mergedClsPrefix}>
{{
default:
collapseSlots.expandIcon
?? (() =>
this.rtlEnabled ? (
<ArrowLeftIcon />
) : (
<ArrowRightIcon />
))
default: () =>
this.rtlEnabled ? <ArrowLeftIcon /> : <ArrowRightIcon />
}}
</NBaseIcon>
])}

View File

@ -37,18 +37,18 @@ export interface HeaderClickInfo<T> {
event: MouseEvent
}
export interface CollapseArrowSlotOptions {
export interface CollapseArrowSlotProps {
collapsed: boolean
}
export interface CollapseItemHeaderSlotOptions {
export interface CollapseItemHeaderSlotProps {
collapsed: boolean
}
export interface CollapseItemHeaderExtraSlotOptions {
export interface CollapseItemHeaderExtraSlotProps {
collapsed: boolean
}
export interface CollapseItemArrowSlotOptions {
export interface CollapseItemArrowSlotProps {
collapsed: boolean
}

View File

@ -126,9 +126,9 @@ export const colorPickerProps = {
export type ColorPickerProps = ExtractPublicPropTypes<typeof colorPickerProps>
export interface ColorPickerSlots {
default?: any
label?: (color: string | null) => any
action?: any
default?: () => VNode[]
label?: (color: string | null) => VNode[]
action?: () => VNode[]
}
export default defineComponent({
@ -709,7 +709,7 @@ export default defineComponent({
}
},
render() {
const { $slots, mergedClsPrefix, onRender } = this
const { mergedClsPrefix, onRender } = this
onRender?.()
return (
<div
@ -729,11 +729,7 @@ export default defineComponent({
hsla={this.hsla}
disabled={this.mergedDisabled}
onClick={this.handleTriggerClick}
>
{{
label: $slots.label
}}
</ColorPickerTrigger>
/>
)
}}
</VTarget>,

View File

@ -1,9 +1,10 @@
import { type HSLA, toHslaString } from 'seemly'
import { defineComponent, h, inject, type PropType } from 'vue'
import { defineComponent, h, inject, type PropType, type SlotsType } from 'vue'
import { colorPickerInjectionKey } from './context'
export default defineComponent({
name: 'ColorPickerTrigger',
slots: Object as SlotsType<Record<string, never>>,
props: {
clsPrefix: {
type: String,

View File

@ -1,11 +1,12 @@
import type { ComputedRef, Ref, Slots } from 'vue'
import type { ComputedRef, Ref } from 'vue'
import type { MergedTheme } from '../../_mixins'
import type { ColorPickerTheme } from '../styles'
import type { ColorPickerSlots } from './ColorPicker'
import type { RenderLabel } from './interface'
import { createInjectionKey } from '../../_utils'
export const colorPickerInjectionKey = createInjectionKey<{
themeRef: ComputedRef<MergedTheme<ColorPickerTheme>>
colorPickerSlots: Slots
colorPickerSlots: ColorPickerSlots
renderLabelRef: Ref<RenderLabel | undefined>
}>('n-color-picker')

View File

@ -5,7 +5,7 @@ import type {
HTMLAttributes,
PropType,
Ref,
Slots,
VNode,
VNodeChild
} from 'vue'
import type { VirtualListInst } from 'vueuc'
@ -179,9 +179,9 @@ export const dataTableProps = {
} as const
export interface DataTableSlots {
default?: any
empty?: any
loading?: any
default?: () => VNode[]
empty?: () => VNode[]
loading?: () => VNode[]
}
export type FilterOptionValue = string | number
@ -363,7 +363,7 @@ export type DataTableSelectionOptions<T = InternalRowData> = Array<
>
export interface DataTableInjection {
props: DataTableSetupProps
slots: Slots
slots: DataTableSlots
indentRef: Ref<number>
childTriggerColIndexRef: Ref<number>
componentId: string

View File

@ -220,9 +220,9 @@ panel.vue
| 名称 | 参数 | 说明 | 版本 |
| --- | --- | --- | --- |
| now | `(props: { onNow: () => void, text: string })` | Now button of the panel. | 2.40.0 |
| clear | `(props: { onClear: () => void, text: string })` | Clear button of the panel. | 2.40.0 |
| confirm | `(props: { onConfirm: () => void, disabled: boolean, text: string })` | Confirm button of the panel. | 2.40.0 |
| now | `(props: { onNow: () => void, text: string })` | Now button of the panel. | 2.40.0 |
### DatePicker Methods

View File

@ -220,9 +220,9 @@ form-debug.vue
| 名称 | 参数 | 说明 | 版本 |
| --- | --- | --- | --- |
| now | `(props: { onNow: () => void, text: string })` | 面板的此刻按钮 | 2.40.0 |
| clear | `(props: { onClear: () => void, text: string })` | 面板的清除按钮 | 2.40.0 |
| confirm | `(props: { onConfirm: () => void, disabled: boolean, text: string })` | 面板的确认按钮 | 2.40.0 |
| now | `(props: { onNow: () => void, text: string })` | 面板的此刻按钮 | 2.40.0 |
### DatePicker Methods

View File

@ -70,13 +70,20 @@ import {
export type DatePickerSetupProps = ExtractPropTypes<typeof datePickerProps>
export interface DatePickerSlots {
'date-icon'?: any
footer?: any
'next-month'?: any
'next-year'?: any
'prev-month'?: any
'prev-year'?: any
separator?: any
'date-icon'?: () => VNode[]
footer?: () => VNode[]
'next-month'?: () => VNode[]
'next-year'?: () => VNode[]
'prev-month'?: () => VNode[]
'prev-year'?: () => VNode[]
separator?: () => VNode[]
confirm?: (props: {
onConfirm: () => void
disabled: boolean
text: string
}) => VNode[]
clear?: (props: { onClear: () => void, text: string }) => VNode[]
now?: (props: { onNow: () => void, text: string }) => VNode[]
}
export default defineComponent({

View File

@ -1,4 +1,4 @@
import type { Ref, Slots, UnwrapNestedRefs } from 'vue'
import type { Ref, UnwrapNestedRefs } from 'vue'
import type { VirtualListInst } from 'vueuc'
import type { ScrollbarInst } from '../../_internal'
import type { MergedTheme } from '../../_mixins'
@ -11,6 +11,7 @@ import type {
} from '../../time-picker/src/interface'
import type { TimePickerProps } from '../../time-picker/src/TimePicker'
import type { DatePickerTheme } from '../styles/light'
import type { DatePickerSlots } from './DatePicker'
import type {
dualCalendarValidation,
uniCalendarValidation
@ -135,7 +136,7 @@ export type DatePickerInjection = {
monthFormatRef: Ref<string>
yearFormatRef: Ref<string>
quarterFormatRef: Ref<string>
datePickerSlots: Slots
datePickerSlots: DatePickerSlots
yearRangeRef: Ref<[number, number]>
} & ReturnType<typeof uniCalendarValidation> &
ReturnType<typeof dualCalendarValidation>

View File

@ -44,8 +44,14 @@ export default defineComponent({
return useCalendar(props, props.type)
},
render() {
const { mergedClsPrefix, mergedTheme, shortcuts, onRender, $slots, type }
= this
const {
mergedClsPrefix,
mergedTheme,
shortcuts,
onRender,
datePickerSlots,
type
} = this
onRender?.()
return (
<div
@ -66,13 +72,17 @@ export default defineComponent({
class={`${mergedClsPrefix}-date-panel-month__fast-prev`}
onClick={this.prevYear}
>
{resolveSlot($slots['prev-year'], () => [<FastBackwardIcon />])}
{resolveSlot(datePickerSlots['prev-year'], () => [
<FastBackwardIcon />
])}
</div>
<div
class={`${mergedClsPrefix}-date-panel-month__prev`}
onClick={this.prevMonth}
>
{resolveSlot($slots['prev-month'], () => [<BackwardIcon />])}
{resolveSlot(datePickerSlots['prev-month'], () => [
<BackwardIcon />
])}
</div>
<PanelHeader
monthYearSeparator={this.calendarHeaderMonthYearSeparator}
@ -87,13 +97,17 @@ export default defineComponent({
class={`${mergedClsPrefix}-date-panel-month__next`}
onClick={this.nextMonth}
>
{resolveSlot($slots['next-month'], () => [<ForwardIcon />])}
{resolveSlot(datePickerSlots['next-month'], () => [
<ForwardIcon />
])}
</div>
<div
class={`${mergedClsPrefix}-date-panel-month__fast-next`}
onClick={this.nextYear}
>
{resolveSlot($slots['next-year'], () => [<FastForwardIcon />])}
{resolveSlot(datePickerSlots['next-year'], () => [
<FastForwardIcon />
])}
</div>
</div>
<div class={`${mergedClsPrefix}-date-panel-weekdays`}>

View File

@ -32,7 +32,13 @@ export default defineComponent({
return useDualCalendar(props, 'daterange')
},
render() {
const { mergedClsPrefix, mergedTheme, shortcuts, onRender, $slots } = this
const {
mergedClsPrefix,
mergedTheme,
shortcuts,
onRender,
datePickerSlots
} = this
onRender?.()
return (
@ -57,13 +63,17 @@ export default defineComponent({
class={`${mergedClsPrefix}-date-panel-month__fast-prev`}
onClick={this.startCalendarPrevYear}
>
{resolveSlot($slots['prev-year'], () => [<FastBackwardIcon />])}
{resolveSlot(datePickerSlots['prev-year'], () => [
<FastBackwardIcon />
])}
</div>
<div
class={`${mergedClsPrefix}-date-panel-month__prev`}
onClick={this.startCalendarPrevMonth}
>
{resolveSlot($slots['prev-month'], () => [<BackwardIcon />])}
{resolveSlot(datePickerSlots['prev-month'], () => [
<BackwardIcon />
])}
</div>
<PanelHeader
monthYearSeparator={this.calendarHeaderMonthYearSeparator}
@ -78,13 +88,17 @@ export default defineComponent({
class={`${mergedClsPrefix}-date-panel-month__next`}
onClick={this.startCalendarNextMonth}
>
{resolveSlot($slots['next-month'], () => [<ForwardIcon />])}
{resolveSlot(datePickerSlots['next-month'], () => [
<ForwardIcon />
])}
</div>
<div
class={`${mergedClsPrefix}-date-panel-month__fast-next`}
onClick={this.startCalendarNextYear}
>
{resolveSlot($slots['next-year'], () => [<FastForwardIcon />])}
{resolveSlot(datePickerSlots['next-year'], () => [
<FastForwardIcon />
])}
</div>
</div>
<div class={`${mergedClsPrefix}-date-panel-weekdays`}>
@ -148,13 +162,17 @@ export default defineComponent({
class={`${mergedClsPrefix}-date-panel-month__fast-prev`}
onClick={this.endCalendarPrevYear}
>
{resolveSlot($slots['prev-year'], () => [<FastBackwardIcon />])}
{resolveSlot(datePickerSlots['prev-year'], () => [
<FastBackwardIcon />
])}
</div>
<div
class={`${mergedClsPrefix}-date-panel-month__prev`}
onClick={this.endCalendarPrevMonth}
>
{resolveSlot($slots['prev-month'], () => [<BackwardIcon />])}
{resolveSlot(datePickerSlots['prev-month'], () => [
<BackwardIcon />
])}
</div>
<PanelHeader
monthYearSeparator={this.calendarHeaderMonthYearSeparator}
@ -169,13 +187,17 @@ export default defineComponent({
class={`${mergedClsPrefix}-date-panel-month__next`}
onClick={this.endCalendarNextMonth}
>
{resolveSlot($slots['next-month'], () => [<ForwardIcon />])}
{resolveSlot(datePickerSlots['next-month'], () => [
<ForwardIcon />
])}
</div>
<div
class={`${mergedClsPrefix}-date-panel-month__fast-next`}
onClick={this.endCalendarNextYear}
>
{resolveSlot($slots['next-year'], () => [<FastForwardIcon />])}
{resolveSlot(datePickerSlots['next-year'], () => [
<FastForwardIcon />
])}
</div>
</div>
<div class={`${mergedClsPrefix}-date-panel-weekdays`}>
@ -262,7 +284,7 @@ export default defineComponent({
<div class={`${mergedClsPrefix}-date-panel-actions__suffix`}>
{this.actions?.includes('clear')
? resolveSlotWithProps(
$slots.clear,
datePickerSlots.clear,
{
onClear: this.handleClearClick,
text: this.locale.clear
@ -281,7 +303,7 @@ export default defineComponent({
: null}
{this.actions?.includes('confirm')
? resolveSlotWithProps(
$slots.confirm,
datePickerSlots.confirm,
{
onConfirm: this.handleConfirmClick,
disabled: this.isRangeInvalid || this.isSelecting,

View File

@ -36,8 +36,8 @@ export default defineComponent({
mergedTheme,
shortcuts,
timePickerProps,
onRender,
$slots
datePickerSlots,
onRender
} = this
onRender?.()
@ -91,13 +91,17 @@ export default defineComponent({
class={`${mergedClsPrefix}-date-panel-month__fast-prev`}
onClick={this.prevYear}
>
{resolveSlot($slots['prev-year'], () => [<FastBackwardIcon />])}
{resolveSlot(datePickerSlots['prev-year'], () => [
<FastBackwardIcon />
])}
</div>
<div
class={`${mergedClsPrefix}-date-panel-month__prev`}
onClick={this.prevMonth}
>
{resolveSlot($slots['prev-month'], () => [<BackwardIcon />])}
{resolveSlot(datePickerSlots['prev-month'], () => [
<BackwardIcon />
])}
</div>
<PanelHeader
monthYearSeparator={this.calendarHeaderMonthYearSeparator}
@ -112,13 +116,17 @@ export default defineComponent({
class={`${mergedClsPrefix}-date-panel-month__next`}
onClick={this.nextMonth}
>
{resolveSlot($slots['next-month'], () => [<ForwardIcon />])}
{resolveSlot(datePickerSlots['next-month'], () => [
<ForwardIcon />
])}
</div>
<div
class={`${mergedClsPrefix}-date-panel-month__fast-next`}
onClick={this.nextYear}
>
{resolveSlot($slots['next-year'], () => [<FastForwardIcon />])}
{resolveSlot(datePickerSlots['next-year'], () => [
<FastForwardIcon />
])}
</div>
</div>
<div class={`${mergedClsPrefix}-date-panel-weekdays`}>
@ -199,7 +207,7 @@ export default defineComponent({
<div class={`${mergedClsPrefix}-date-panel-actions__suffix`}>
{this.actions?.includes('clear')
? resolveSlotWithProps(
this.$slots.clear,
this.datePickerSlots.clear,
{
onClear: this.clearSelectedDateTime,
text: this.locale.clear
@ -218,7 +226,7 @@ export default defineComponent({
: null}
{this.actions?.includes('now')
? resolveSlotWithProps(
$slots.now,
datePickerSlots.now,
{
onNow: this.handleNowClick,
text: this.locale.now
@ -237,7 +245,7 @@ export default defineComponent({
: null}
{this.actions?.includes('confirm')
? resolveSlotWithProps(
$slots.confirm,
datePickerSlots.confirm,
{
onConfirm: this.handleConfirmClick,
disabled: this.isDateInvalid,

View File

@ -40,7 +40,7 @@ export default defineComponent({
shortcuts,
timePickerProps,
onRender,
$slots
datePickerSlots
} = this
onRender?.()
@ -132,13 +132,17 @@ export default defineComponent({
class={`${mergedClsPrefix}-date-panel-month__fast-prev`}
onClick={this.startCalendarPrevYear}
>
{resolveSlot($slots['prev-year'], () => [<FastBackwardIcon />])}
{resolveSlot(datePickerSlots['prev-year'], () => [
<FastBackwardIcon />
])}
</div>
<div
class={`${mergedClsPrefix}-date-panel-month__prev`}
onClick={this.startCalendarPrevMonth}
>
{resolveSlot($slots['prev-month'], () => [<BackwardIcon />])}
{resolveSlot(datePickerSlots['prev-month'], () => [
<BackwardIcon />
])}
</div>
<PanelHeader
monthYearSeparator={this.calendarHeaderMonthYearSeparator}
@ -153,13 +157,17 @@ export default defineComponent({
class={`${mergedClsPrefix}-date-panel-month__next`}
onClick={this.startCalendarNextMonth}
>
{resolveSlot($slots['next-month'], () => [<ForwardIcon />])}
{resolveSlot(datePickerSlots['next-month'], () => [
<ForwardIcon />
])}
</div>
<div
class={`${mergedClsPrefix}-date-panel-month__fast-next`}
onClick={this.startCalendarNextYear}
>
{resolveSlot($slots['next-year'], () => [<FastForwardIcon />])}
{resolveSlot(datePickerSlots['next-year'], () => [
<FastForwardIcon />
])}
</div>
</div>
<div class={`${mergedClsPrefix}-date-panel-weekdays`}>
@ -233,13 +241,17 @@ export default defineComponent({
class={`${mergedClsPrefix}-date-panel-month__fast-prev`}
onClick={this.endCalendarPrevYear}
>
{resolveSlot($slots['prev-year'], () => [<FastBackwardIcon />])}
{resolveSlot(datePickerSlots['prev-year'], () => [
<FastBackwardIcon />
])}
</div>
<div
class={`${mergedClsPrefix}-date-panel-month__prev`}
onClick={this.endCalendarPrevMonth}
>
{resolveSlot($slots['prev-month'], () => [<BackwardIcon />])}
{resolveSlot(datePickerSlots['prev-month'], () => [
<BackwardIcon />
])}
</div>
<PanelHeader
monthBeforeYear={this.calendarMonthBeforeYear}
@ -254,13 +266,17 @@ export default defineComponent({
class={`${mergedClsPrefix}-date-panel-month__next`}
onClick={this.endCalendarNextMonth}
>
{resolveSlot($slots['next-month'], () => [<ForwardIcon />])}
{resolveSlot(datePickerSlots['next-month'], () => [
<ForwardIcon />
])}
</div>
<div
class={`${mergedClsPrefix}-date-panel-month__fast-next`}
onClick={this.endCalendarNextYear}
>
{resolveSlot($slots['next-year'], () => [<FastForwardIcon />])}
{resolveSlot(datePickerSlots['next-year'], () => [
<FastForwardIcon />
])}
</div>
</div>
<div class={`${mergedClsPrefix}-date-panel-weekdays`}>
@ -357,7 +373,7 @@ export default defineComponent({
<div class={`${mergedClsPrefix}-date-panel-actions__suffix`}>
{this.actions?.includes('clear')
? resolveSlotWithProps(
$slots.clear,
datePickerSlots.clear,
{
onClear: this.handleClearClick,
text: this.locale.clear
@ -376,7 +392,7 @@ export default defineComponent({
: null}
{this.actions?.includes('confirm')
? resolveSlotWithProps(
$slots.confirm,
datePickerSlots.confirm,
{
onConfirm: this.handleConfirmClick,
disabled: this.isRangeInvalid || this.isSelecting,

View File

@ -8,7 +8,7 @@ import { defineComponent, h, onMounted, type PropType, type VNode } from 'vue'
import { VirtualList } from 'vueuc'
import { NBaseFocusDetector, NScrollbar } from '../../../_internal'
import { useLocale } from '../../../_mixins'
import { resolveSlotWithProps } from '../../../_utils'
import { resolveSlotWithTypedProps, resolveWrappedSlot } from '../../../_utils'
import { NButton, NxButton } from '../../../button'
import { MONTH_ITEM_HEIGHT } from '../config'
import {
@ -212,13 +212,11 @@ export default defineComponent({
</div>
) : null}
</div>
{this.datePickerSlots.footer ? (
<div class={`${mergedClsPrefix}-date-panel-footer`}>
{{
default: this.datePickerSlots.footer
}}
</div>
) : null}
{resolveWrappedSlot(this.datePickerSlots.footer, (children) => {
return children ? (
<div class={`${mergedClsPrefix}-date-panel-footer`}>{children}</div>
) : null
})}
{actions?.length || shortcuts ? (
<div class={`${mergedClsPrefix}-date-panel-actions`}>
<div class={`${mergedClsPrefix}-date-panel-actions__prefix`}>
@ -245,8 +243,8 @@ export default defineComponent({
</div>
<div class={`${mergedClsPrefix}-date-panel-actions__suffix`}>
{actions?.includes('clear')
? resolveSlotWithProps(
this.$slots.now,
? resolveSlotWithTypedProps(
this.datePickerSlots.clear,
{
onClear: this.handleClearClick,
text: this.locale.clear
@ -264,8 +262,8 @@ export default defineComponent({
)
: null}
{actions?.includes('now')
? resolveSlotWithProps(
this.$slots.now,
? resolveSlotWithTypedProps(
this.datePickerSlots.now,
{
onNow: this.handleNowClick,
text: this.locale.now
@ -283,8 +281,8 @@ export default defineComponent({
)
: null}
{actions?.includes('confirm')
? resolveSlotWithProps(
this.$slots.confirm,
? resolveSlotWithTypedProps(
this.datePickerSlots.confirm,
{
onConfirm: this.handleConfirmClick,
disabled: this.isDateInvalid,

View File

@ -7,14 +7,17 @@ import {
h,
onMounted,
type PropType,
renderSlot,
type VNode,
watchEffect
} from 'vue'
import { VirtualList } from 'vueuc'
import { NBaseFocusDetector, NScrollbar } from '../../../_internal'
import { useLocale } from '../../../_mixins'
import { resolveSlotWithProps, warnOnce } from '../../../_utils'
import {
resolveSlotWithTypedProps,
resolveWrappedSlot,
warnOnce
} from '../../../_utils'
import { NxButton } from '../../../button'
import { MONTH_ITEM_HEIGHT } from '../config'
import {
@ -270,11 +273,11 @@ export default defineComponent({
) : null}
</div>
</div>
{this.datePickerSlots.footer ? (
<div class={`${mergedClsPrefix}-date-panel-footer`}>
{renderSlot(this.datePickerSlots, 'footer')}
</div>
) : null}
{resolveWrappedSlot(this.datePickerSlots.footer, (children) => {
return children ? (
<div class={`${mergedClsPrefix}-date-panel-footer`}>{children}</div>
) : null
})}
{this.actions?.length || shortcuts ? (
<div class={`${mergedClsPrefix}-date-panel-actions`}>
<div class={`${mergedClsPrefix}-date-panel-actions__prefix`}>
@ -302,8 +305,8 @@ export default defineComponent({
</div>
<div class={`${mergedClsPrefix}-date-panel-actions__suffix`}>
{this.actions?.includes('clear')
? resolveSlotWithProps(
this.$slots.clear,
? resolveSlotWithTypedProps(
this.datePickerSlots.clear,
{
onClear: this.handleClearClick,
text: this.locale.clear
@ -321,8 +324,8 @@ export default defineComponent({
)
: null}
{this.actions?.includes('confirm')
? resolveSlotWithProps(
this.$slots.confirm,
? resolveSlotWithTypedProps(
this.datePickerSlots.confirm,
{
disabled: this.isRangeInvalid,
onConfirm: this.handleConfirmClick,

View File

@ -60,8 +60,8 @@ export type DescriptionsProps = ExtractPublicPropTypes<typeof descriptionsProps>
export type DescriptionProps = DescriptionsProps
export interface DescriptionsSlots {
default?: any
header?: any
default?: () => VNode[]
header?: () => VNode[]
}
export default defineComponent({

View File

@ -3,7 +3,8 @@ import {
type CSSProperties,
defineComponent,
type PropType,
type SlotsType
type SlotsType,
type VNode
} from 'vue'
import { DESCRIPTION_ITEM_FLAG } from './utils'
@ -24,8 +25,8 @@ export type DescriptionItemProps = ExtractPublicPropTypes<
>
export interface DescriptionItemSlots {
default?: any
label?: any
default?: () => VNode[]
label?: () => VNode[]
}
export default defineComponent({

View File

@ -6,7 +6,8 @@ import {
type CSSProperties,
defineComponent,
h,
type SlotsType
type SlotsType,
type VNode
} from 'vue'
import { NBaseClose, NBaseIcon } from '../../_internal'
import {
@ -36,11 +37,11 @@ const iconRenderMap = {
}
export interface DialogSlots {
action?: any
default?: any
header?: any
icon?: any
close?: any
action?: () => VNode[]
default?: () => VNode[]
header?: () => VNode[]
icon?: () => VNode[]
close?: () => VNode[]
}
export const NDialog = defineComponent({

View File

@ -20,7 +20,7 @@ export default defineComponent({
</n-button>
<n-drawer v-model:show="modalActive" width="800">
<n-popover trigger="click">
<template #activator>
<template #trigger>
<n-button style="margin: 0">
悬浮
</n-button>

View File

@ -6,7 +6,8 @@ import {
h,
inject,
type PropType,
type SlotsType
type SlotsType,
type VNode
} from 'vue'
import { NBaseClose, NScrollbar } from '../../_internal'
import { throwError } from '../../_utils'
@ -32,9 +33,9 @@ export type DrawerContentProps = ExtractPublicPropTypes<
>
export interface DrawerContentSlots {
default?: any
header?: any
footer?: any
default?: () => VNode[]
header?: () => VNode[]
footer?: () => VNode[]
}
export default defineComponent({

View File

@ -1,6 +1,6 @@
export { dynamicInputProps, default as NDynamicInput } from './src/DynamicInput'
export type { DynamicInputProps, DynamicInputSlots } from './src/DynamicInput'
export type {
DynamicInputActionSlotOptions,
DynamicInputDefaultSlotOptions
DynamicInputActionSlotProps,
DynamicInputDefaultSlotProps
} from './src/interface'

View File

@ -3,8 +3,8 @@ import type { ExtractPublicPropTypes, MaybeArray } from '../../_utils'
import type { ButtonProps } from '../../button'
import type { DynamicInputTheme } from '../styles'
import type {
DynamicInputActionSlotOptions,
DynamicInputDefaultSlotOptions,
DynamicInputActionSlotProps,
DynamicInputDefaultSlotProps,
OnUpdateValue
} from './interface'
import { createId } from 'seemly'
@ -21,6 +21,7 @@ import {
ref,
toRaw,
toRef,
type VNode,
watchEffect
} from 'vue'
import { NBaseIcon } from '../../_internal'
@ -33,7 +34,12 @@ import {
import { useConfig, useLocale, useTheme, useThemeClass } from '../../_mixins'
import { formItemInjectionKey } from '../../_mixins/use-form-item'
import { useRtl } from '../../_mixins/use-rtl'
import { call, resolveSlot, resolveSlotWithProps, warnOnce } from '../../_utils'
import {
call,
resolveSlot,
resolveSlotWithTypedProps,
warnOnce
} from '../../_utils'
import { NButton } from '../../button'
import { NButtonGroup } from '../../button-group'
import { dynamicInputLight } from '../styles'
@ -93,10 +99,10 @@ export const dynamicInputProps = {
export type DynamicInputProps = ExtractPublicPropTypes<typeof dynamicInputProps>
export interface DynamicInputSlots {
action?: (options: DynamicInputActionSlotOptions) => any
default?: (options: DynamicInputDefaultSlotOptions) => any
'create-button-default'?: any
'create-button-icon'?: any
action?: (props: DynamicInputActionSlotProps) => VNode[]
default?: (props: DynamicInputDefaultSlotProps) => VNode[]
'create-button-default'?: () => VNode[]
'create-button-icon'?: () => VNode[]
}
export default defineComponent({
@ -389,7 +395,7 @@ export default defineComponent({
class={[`${mergedClsPrefix}-dynamic-input-item`, itemClass]}
style={itemStyle}
>
{resolveSlotWithProps(
{resolveSlotWithTypedProps(
$slots.default,
{
value: mergedValue[index],
@ -435,7 +441,7 @@ export default defineComponent({
]
}
)}
{resolveSlotWithProps(
{resolveSlotWithTypedProps(
$slots.action,
{
value: mergedValue[index],

View File

@ -15,12 +15,12 @@ export const dynamicInputInjectionKey
export type OnUpdateValue = <T>(value: T[]) => void
export interface DynamicInputDefaultSlotOptions {
export interface DynamicInputDefaultSlotProps {
value: any
index: number
}
export interface DynamicInputActionSlotOptions {
export interface DynamicInputActionSlotProps {
value: any
index: number
create: (index: number) => void

View File

@ -1,7 +1,7 @@
export { dynamicTagsProps, default as NDynamicTags } from './src/DynamicTags'
export type { DynamicTagsProps, DynamicTagsSlots } from './src/DynamicTags'
export type {
DynamicTagsInputSlotOptions,
DynamicTagsInputSlotProps,
DynamicTagsOption,
DynamicTagsTriggerSlotOptions
DynamicTagsTriggerSlotProps
} from './src/interface'

View File

@ -3,9 +3,9 @@ import type { ExtractPublicPropTypes, MaybeArray } from '../../_utils'
import type { InputInst, InputProps } from '../../input'
import type { DynamicTagsTheme } from '../styles'
import type {
DynamicTagsInputSlotOptions,
DynamicTagsInputSlotProps,
DynamicTagsOption,
DynamicTagsTriggerSlotOptions,
DynamicTagsTriggerSlotProps,
OnCreate,
OnUpdateValue,
OnUpdateValueImpl
@ -21,6 +21,7 @@ import {
ref,
type SlotsType,
toRef,
type VNode,
type VNodeChild,
watchEffect
} from 'vue'
@ -81,9 +82,9 @@ export const dynamicTagsProps = {
export type DynamicTagsProps = ExtractPublicPropTypes<typeof dynamicTagsProps>
export interface DynamicTagsSlots {
input?: (info: DynamicTagsInputSlotOptions) => any
trigger?: (info: DynamicTagsTriggerSlotOptions) => any
default?: any
input?: (props: DynamicTagsInputSlotProps) => VNode[]
trigger?: (props: DynamicTagsTriggerSlotProps) => VNode[]
default?: () => VNode[]
}
export default defineComponent({

View File

@ -18,12 +18,12 @@ export interface DynamicTagsOption {
value: string
}
export interface DynamicTagsInputSlotOptions {
export interface DynamicTagsInputSlotProps {
submit: (value: any) => void
deactivate: () => void
}
export interface DynamicTagsTriggerSlotOptions {
export interface DynamicTagsTriggerSlotProps {
activate: () => void
disabled: boolean
}

View File

@ -11,7 +11,8 @@ import {
onDeactivated,
type PropType,
ref,
type SlotsType
type SlotsType,
type VNode
} from 'vue'
import { useTheme } from '../../_mixins'
import { useMergedClsPrefix } from '../../_mixins/use-config'
@ -40,8 +41,8 @@ export const ellipsisProps = {
export type EllipsisProps = ExtractPublicPropTypes<typeof ellipsisProps>
export interface EllipsisSlots {
default?: any
tooltip?: any
default?: () => VNode[]
tooltip?: () => VNode[]
}
export default defineComponent({

View File

@ -7,6 +7,7 @@ import {
h,
type PropType,
type SlotsType,
type VNode,
type VNodeChild
} from 'vue'
import { NBaseIcon } from '../../_internal/icon'
@ -37,9 +38,9 @@ export const emptyProps = {
export type EmptyProps = ExtractPublicPropTypes<typeof emptyProps>
export interface EmptySlots {
default?: any
extra?: any
icon?: any
default?: () => VNode[]
extra?: () => VNode[]
icon?: () => VNode[]
}
export default defineComponent({

View File

@ -11,7 +11,8 @@ import {
type PropType,
ref,
type SlotsType,
toRef
toRef,
type VNode
} from 'vue'
import { NBaseIcon } from '../../_internal'
import { CloseIcon } from '../../_internal/icons'
@ -67,9 +68,9 @@ export const floatButtonProps = {
export type FloatButtonProps = ExtractPublicPropTypes<typeof floatButtonProps>
export interface FloatButtonSlots {
default?: any
description?: any
menu?: any
default?: () => VNode[]
description?: () => VNode[]
menu?: () => VNode[]
}
export default defineComponent({

View File

@ -12,6 +12,7 @@ import {
ref,
type SlotsType,
toRef,
type VNode,
watchEffect
} from 'vue'
import { useConfig } from '../../_mixins'
@ -53,9 +54,8 @@ export const imageProps = {
export type ImageProps = ExtractPublicPropTypes<typeof imageProps>
export interface ImageSlots {
placeholder?: any
error?: any
[key: string]: any
placeholder?: () => VNode[]
error?: () => VNode[]
}
export default defineComponent({
@ -225,8 +225,7 @@ export default defineComponent({
renderToolbar={this.renderToolbar}
>
{{
default: () => imgNode,
toolbar: () => this.$slots.toolbar?.()
default: () => imgNode
}}
</NImagePreview>
)}

View File

@ -112,10 +112,10 @@ export const inputNumberProps = {
export type InputNumberProps = ExtractPublicPropTypes<typeof inputNumberProps>
export interface InputNumberSlots {
'add-icon'?: any
'minus-icon'?: any
prefix?: any
suffix?: any
'add-icon'?: () => VNode[]
'minus-icon'?: () => VNode[]
prefix?: () => VNode[]
suffix?: () => VNode[]
}
export default defineComponent({

View File

@ -172,13 +172,13 @@ export const inputProps = {
export type InputProps = ExtractPublicPropTypes<typeof inputProps>
export interface InputSlots {
'clear-icon'?: any
count?: (props: { value: string }) => any
'password-invisible-icon'?: any
'password-visible-icon'?: any
prefix?: any
separator?: any
suffix?: any
'clear-icon'?: () => VNode[]
count?: (props: { value: string }) => VNode[]
'password-invisible-icon'?: () => VNode[]
'password-visible-icon'?: () => VNode[]
prefix?: () => VNode[]
separator?: () => VNode[]
suffix?: () => VNode[]
}
export default defineComponent({
@ -1352,7 +1352,13 @@ export default defineComponent({
this.showCount && this.type !== 'textarea' ? (
<WordCount>
{{
default: (props: unknown) => $slots.count?.(props)
default: (props: unknown) => {
const { renderCount } = this
if (renderCount) {
return renderCount(props as { value: string })
}
return $slots.count?.(props)
}
}}
</WordCount>
) : null,

View File

@ -1,4 +1,4 @@
import type { CSSProperties, PropType, Ref, SlotsType } from 'vue'
import type { CSSProperties, PropType, Ref, SlotsType, VNode } from 'vue'
import type { ThemeProps } from '../../_mixins'
import type { ListTheme } from '../styles'
import { computed, defineComponent, h, provide, toRef } from 'vue'
@ -25,9 +25,9 @@ export const listProps = {
export type ListProps = ExtractPublicPropTypes<typeof listProps>
export interface ListSlots {
default?: any
footer?: any
header?: any
default?: () => VNode[]
footer?: () => VNode[]
header?: () => VNode[]
}
interface ListInjection {

View File

@ -1,12 +1,12 @@
import type { SlotsType } from 'vue'
import type { SlotsType, VNode } from 'vue'
import { defineComponent, h, inject } from 'vue'
import { throwError } from '../../_utils'
import { listInjectionKey } from './List'
export interface ListItemSlots {
default?: any
prefix?: any
suffix?: any
default?: () => VNode[]
prefix?: () => VNode[]
suffix?: () => VNode[]
}
export default defineComponent({

View File

@ -24,7 +24,8 @@ import {
ref,
type SlotsType,
toRef,
Transition
Transition,
type VNode
} from 'vue'
import {
type FollowerInst,
@ -133,8 +134,8 @@ export const mentionProps = {
export type MentionProps = ExtractPublicPropTypes<typeof mentionProps>
export interface MentionSlots {
default?: any
empty?: any
default?: () => VNode[]
empty?: () => VNode[]
}
export default defineComponent({

View File

@ -103,9 +103,7 @@ export const modalProps = {
export type ModalProps = ExtractPublicPropTypes<typeof modalProps>
export interface ModalSlots extends CardSlots, DialogSlots {
default?: any
}
export interface ModalSlots extends CardSlots, DialogSlots {}
export default defineComponent({
name: 'Modal',

View File

@ -6,7 +6,8 @@ import {
defineComponent,
h,
type PropType,
type SlotsType
type SlotsType,
type VNode
} from 'vue'
import { NBaseIcon } from '../../_internal'
import { ArrowBackIcon } from '../../_internal/icons'
@ -26,14 +27,14 @@ export const pageHeaderProps = {
export type PageHeaderProps = ExtractPublicPropTypes<typeof pageHeaderProps>
export interface PageHeaderSlots {
avatar?: any
header?: any
default?: any
extra?: any
footer?: any
subtitle?: any
title?: any
back?: any
avatar?: () => VNode[]
header?: () => VNode[]
default?: () => VNode[]
extra?: () => VNode[]
footer?: () => VNode[]
subtitle?: () => VNode[]
title?: () => VNode[]
back?: () => VNode[]
}
export default defineComponent({

View File

@ -28,6 +28,7 @@ import {
ref,
type SlotsType,
toRef,
type VNode,
type VNodeChild,
watchEffect
} from 'vue'
@ -126,13 +127,13 @@ export const paginationProps = {
export type PaginationProps = ExtractPublicPropTypes<typeof paginationProps>
export interface PaginationSlots {
default?: any
goto?: any
label?: any
next?: (info: PaginationInfo) => any
prev?: (info: PaginationInfo) => any
prefix?: (info: PaginationInfo) => any
suffix?: (info: PaginationInfo) => any
default?: () => VNode[]
goto?: () => VNode[]
label?: () => VNode[]
next?: (props: PaginationInfo) => VNode
prev?: (props: PaginationInfo) => VNode
prefix?: (props: PaginationInfo) => VNode
suffix?: (props: PaginationInfo) => VNode
}
export default defineComponent({
@ -599,8 +600,8 @@ export default defineComponent({
onRender
} = this
onRender?.()
const renderPrefix = ($slots.prefix as RenderPrefix | undefined) || prefix
const renderSuffix = ($slots.suffix as RenderSuffix | undefined) || suffix
const renderPrefix = prefix || $slots.prefix
const renderSuffix = suffix || $slots.suffix
const renderPrev = prev || $slots.prev
const renderNext = next || $slots.next
const renderLabel = label || $slots.label

View File

@ -28,7 +28,7 @@ export default defineComponent({
@positive-click="handlePositiveClick"
@negative-click="handleNegativeClick"
>
<template #activator>
<template #trigger>
<n-button>Quit Game</n-button>
</template>
I heared that players will still be abused after purchasing in some games

View File

@ -4,7 +4,7 @@
<template>
<n-popconfirm :show-icon="false">
<template #activator>
<template #trigger>
<n-button>No icon</n-button>
</template>
As is

View File

@ -12,7 +12,8 @@ import {
type PropType,
provide,
ref,
type SlotsType
type SlotsType,
type VNode
} from 'vue'
import { useConfig, useTheme } from '../../_mixins'
import { call, keep, omit } from '../../_utils'
@ -51,10 +52,10 @@ export type PopconfirmProps = ExtractPublicPropTypes<typeof popconfirmProps>
export type PopconfirmSetupProps = ExtractPropTypes<typeof popconfirmProps>
export interface PopconfirmSlots {
action?: any
default?: any
icon?: any
[key: string]: any
action?: () => VNode[]
default?: () => VNode[]
icon?: () => VNode[]
trigger?: () => VNode[]
}
export default defineComponent({
@ -131,7 +132,7 @@ export default defineComponent({
ref: 'popoverInstRef'
}),
{
trigger: slots.activator || slots.trigger,
trigger: slots.trigger,
default: () => {
const panelProps = keep(props, panelPropKeys)
return h(

View File

@ -224,11 +224,10 @@ export type PopoverProps = ExtractPublicPropTypes<typeof popoverBaseProps>
export type PopoverInternalProps = ExtractInternalPropTypes<typeof popoverProps>
export interface PopoverSlots {
trigger?: any
footer?: any
header?: any
default?: any
[key: string]: any
trigger?: () => VNode[]
footer?: () => VNode[]
header?: () => VNode[]
default?: () => VNode[]
}
export default defineComponent({
@ -495,12 +494,7 @@ export default defineComponent({
let triggerVNode: VNode | null
let popoverInside = false
if (!positionManually) {
if (slots.activator) {
triggerVNode = getFirstSlotVNode(slots, 'activator')
}
else {
triggerVNode = getFirstSlotVNode(slots, 'trigger')
}
triggerVNode = getFirstSlotVNode(slots, 'trigger')
if (triggerVNode) {
triggerVNode = cloneVNode(triggerVNode)
triggerVNode

View File

@ -10,7 +10,8 @@ import {
type PropType,
provide,
ref,
type SlotsType
type SlotsType,
type VNode
} from 'vue'
import { useConfig, useTheme } from '../../_mixins'
import { createRefSetter, keep, mergeEventHandlers, omit } from '../../_utils'
@ -38,10 +39,10 @@ export type PopselectSetupProps = ExtractPropTypes<typeof popselectProps>
export type PopselectProps = ExtractPublicPropTypes<typeof popselectProps>
export interface PopselectSlots {
default?: any
header?: any
action?: any
empty?: any
default?: () => VNode[]
header?: () => VNode[]
action?: () => VNode[]
empty?: () => VNode[]
}
export default defineComponent({

View File

@ -7,7 +7,8 @@ import {
defineComponent,
h,
type PropType,
type SlotsType
type SlotsType,
type VNode
} from 'vue'
import { NBaseIcon } from '../../_internal'
import {
@ -55,9 +56,9 @@ export const resultProps = {
export type ResultProps = ExtractPublicPropTypes<typeof resultProps>
export interface ResultSlots {
default?: any
footer?: any
icon?: any
default?: () => VNode[]
footer?: () => VNode[]
icon?: () => VNode[]
}
export default defineComponent({

View File

@ -39,6 +39,7 @@ import {
type SlotsType,
toRef,
Transition,
type VNode,
vShow,
watch,
watchEffect,
@ -219,11 +220,11 @@ export const selectProps = {
export type SelectProps = ExtractPublicPropTypes<typeof selectProps>
export interface SelectSlots {
default?: any
header?: any
action?: any
empty?: any
arrow?: any
default?: () => VNode[]
header?: () => VNode[]
action?: () => VNode[]
empty?: () => VNode[]
arrow?: () => VNode[]
}
export default defineComponent({

View File

@ -14,6 +14,7 @@ import {
type SlotsType,
toRef,
Transition,
type VNode,
type VNodeChild,
watch
} from 'vue'
@ -106,8 +107,8 @@ export const sliderProps = {
export type SliderProps = ExtractPublicPropTypes<typeof sliderProps>
export interface SliderSlots {
thumb?: any
default?: any
thumb?: () => VNode[]
default?: () => VNode[]
}
export default defineComponent({

View File

@ -11,6 +11,7 @@ import {
ref,
type SlotsType,
Transition,
type VNode,
watchEffect
} from 'vue'
import { NBaseLoading } from '../../_internal'
@ -57,9 +58,9 @@ export const spinProps = {
export type SpinProps = ExtractPublicPropTypes<typeof spinProps>
export interface SpinSlots {
default?: any
description?: any
icon?: any
default?: () => VNode[]
description?: () => VNode[]
icon?: () => VNode[]
}
export default defineComponent({

View File

@ -11,6 +11,7 @@ import {
ref,
type SlotsType,
toRef,
type VNode,
watchEffect
} from 'vue'
import { type ThemeProps, useTheme, useThemeClass } from '../../_mixins'
@ -62,10 +63,10 @@ export const splitProps = {
export type SplitProps = ExtractPublicPropTypes<typeof splitProps>
export interface SplitSlots {
default?: any
1?: any
2?: any
'resize-trigger'?: any
default?: () => VNode[]
1?: () => VNode[]
2?: () => VNode[]
'resize-trigger'?: () => VNode[]
}
export default defineComponent({

View File

@ -1,7 +1,7 @@
import type { ThemeProps } from '../../_mixins'
import type { ExtractPublicPropTypes } from '../../_utils'
import type { StatisticTheme } from '../styles'
import { computed, defineComponent, h, type SlotsType } from 'vue'
import { computed, defineComponent, h, type SlotsType, type VNode } from 'vue'
import { useConfig, useRtl, useTheme, useThemeClass } from '../../_mixins'
import { resolveWrappedSlot } from '../../_utils'
import { statisticLight } from '../styles'
@ -17,10 +17,10 @@ export const statisticProps = {
export type StatisticProps = ExtractPublicPropTypes<typeof statisticProps>
export interface StatisticSlots {
default?: any
label?: any
prefix?: any
suffix?: any
default?: () => VNode[]
label?: () => VNode[]
prefix?: () => VNode[]
suffix?: () => VNode[]
}
export default defineComponent({

View File

@ -6,7 +6,8 @@ import {
h,
inject,
type PropType,
type SlotsType
type SlotsType,
type VNode
} from 'vue'
import { NBaseIcon, NIconSwitchTransition } from '../../_internal'
import {
@ -38,9 +39,9 @@ export const stepProps = {
export type StepProps = ExtractPublicPropTypes<typeof stepProps>
export interface StepSlots {
default?: any
icon?: any
title?: any
default?: () => VNode[]
icon?: () => VNode[]
title?: () => VNode[]
}
export default defineComponent({

View File

@ -8,7 +8,6 @@ import {
type PropType,
provide,
type Ref,
type Slots,
type SlotsType,
type VNode,
type VNodeChild
@ -56,15 +55,15 @@ export interface StepsInjection {
props: ExtractPropTypes<typeof stepsProps>
mergedClsPrefixRef: Ref<string>
mergedThemeRef: Ref<MergedTheme<StepsTheme>>
stepsSlots: Slots
stepsSlots: StepsSlots
}
export type StepsProps = ExtractPublicPropTypes<typeof stepsProps>
export interface StepsSlots {
default?: any
'finish-icon'?: any
'error-icon'?: any
default?: () => VNode[]
'finish-icon'?: () => VNode[]
'error-icon'?: () => VNode[]
}
export const stepsInjectionKey = createInjectionKey<StepsInjection>('n-steps')

View File

@ -13,6 +13,7 @@ import {
ref,
type SlotsType,
toRef,
type VNode,
watchEffect
} from 'vue'
import { NBaseLoading, NIconSwitchTransition } from '../../_internal'
@ -76,12 +77,12 @@ export const switchProps = {
export type SwitchProps = ExtractPublicPropTypes<typeof switchProps>
export interface SwitchSlots {
default?: any
checked?: any
'checked-icon'?: any
icon?: any
unchecked?: any
'unchecked-icon'?: any
default?: () => VNode[]
checked?: () => VNode[]
'checked-icon'?: () => VNode[]
icon?: () => VNode[]
unchecked?: () => VNode[]
'unchecked-icon'?: () => VNode[]
}
let supportCssMax: boolean | undefined

View File

@ -40,9 +40,9 @@ export const tabPaneProps = {
export type TabPaneProps = ExtractPublicPropTypes<typeof tabPaneProps>
export interface TabPaneSlots {
default?: any
prefix?: any
suffix?: any
default?: () => VNode[]
prefix?: () => VNode[]
suffix?: () => VNode[]
}
export default defineComponent({

View File

@ -116,9 +116,9 @@ export const tabsProps = {
export type TabsProps = ExtractPublicPropTypes<typeof tabsProps>
export interface TabsSlots {
default?: any
prefix?: any
suffix?: any
default?: () => VNode[]
prefix?: () => VNode[]
suffix?: () => VNode[]
}
export default defineComponent({

View File

@ -13,6 +13,7 @@ import {
ref,
type SlotsType,
toRef,
type VNode,
watchEffect
} from 'vue'
import { NBaseClose } from '../../_internal/close'
@ -75,9 +76,9 @@ export const tagInjectionKey = createInjectionKey<TagInjection>('n-tag')
export type TagProps = ExtractPublicPropTypes<typeof tagProps>
export interface TagSlots {
default?: any
avatar?: any
icon?: any
default?: () => VNode[]
avatar?: () => VNode[]
icon?: () => VNode[]
}
export default defineComponent({

View File

@ -8,7 +8,8 @@ import {
Fragment,
h,
type PropType,
type SlotsType
type SlotsType,
type VNode
} from 'vue'
import { useConfig, useRtl, useTheme, useThemeClass } from '../../_mixins'
import { thingLight } from '../styles'
@ -30,13 +31,13 @@ export const thingProps = {
export type ThingProps = ExtractPublicPropTypes<typeof thingProps>
export interface ThingSlots {
action?: any
avatar?: any
default?: any
description?: any
footer?: any
'header-extra'?: any
header?: any
action?: () => VNode[]
avatar?: () => VNode[]
default?: () => VNode[]
description?: () => VNode[]
footer?: () => VNode[]
'header-extra'?: () => VNode[]
header?: () => VNode[]
}
export default defineComponent({

View File

@ -47,6 +47,7 @@ import {
ref,
toRef,
Transition,
type VNode,
watch,
watchEffect,
withDirectives
@ -179,8 +180,8 @@ export const timePickerProps = {
export type TimePickerProps = ExtractPublicPropTypes<typeof timePickerProps>
export interface TimePickerSlots {
default?: any
icon?: any
default?: () => VNode[]
icon?: () => VNode[]
}
export default defineComponent({

View File

@ -6,7 +6,8 @@ import {
h,
inject,
type PropType,
type SlotsType
type SlotsType,
type VNode
} from 'vue'
import { useConfig, useThemeClass } from '../../_mixins'
import {
@ -39,10 +40,10 @@ export const timelineItemProps = {
export type TimelineItemProps = ExtractPublicPropTypes<typeof timelineItemProps>
export interface TimelineItemSlots {
default?: any
icon?: any
footer?: any
header?: any
default?: () => VNode[]
icon?: () => VNode[]
footer?: () => VNode[]
header?: () => VNode[]
}
export default defineComponent({

View File

@ -39,6 +39,7 @@ import {
type SlotsType,
toRef,
Transition,
type VNode,
type VNodeChild,
watchEffect,
withDirectives
@ -183,10 +184,10 @@ export const treeSelectProps = {
export type TreeSelectProps = ExtractPublicPropTypes<typeof treeSelectProps>
export interface TreeSelectSlots {
header?: any
action?: any
arrow?: any
empty?: any
header?: () => VNode[]
action?: () => VNode[]
arrow?: () => VNode[]
empty?: () => VNode[]
}
export default defineComponent({

View File

@ -350,8 +350,8 @@ export const treeProps = {
export type TreeProps = ExtractPublicPropTypes<typeof treeProps>
export interface TreeSlots {
default?: any
empty?: any
default?: () => VNode[]
empty?: () => VNode[]
}
export default defineComponent({

View File

@ -1,5 +1,12 @@
import type { UploadTriggerDefaultSlotOptions } from './interface'
import { computed, defineComponent, h, inject } from 'vue'
import {
computed,
defineComponent,
h,
inject,
type SlotsType,
type VNode
} from 'vue'
import { NBaseIcon } from '../../_internal'
import { AddIcon } from '../../_internal/icons'
import { resolveSlot, throwError } from '../../_utils'
@ -8,7 +15,7 @@ import NUploadDragger from './UploadDragger'
import { getFilesFromEntries } from './utils'
export interface UploadTriggerSlots {
default?: (options: UploadTriggerDefaultSlotOptions) => any
default?: (options: UploadTriggerDefaultSlotOptions) => VNode[]
}
export default defineComponent({
@ -16,6 +23,7 @@ export default defineComponent({
props: {
abstract: Boolean
},
slots: Object as SlotsType<UploadTriggerSlots>,
setup(props, { slots }) {
const NUpload = inject(uploadInjectionKey, null)
if (!NUpload) {
@ -24,7 +32,6 @@ export default defineComponent({
'`n-upload-trigger` must be placed inside `n-upload`.'
)
}
const {
mergedClsPrefixRef,
mergedDisabledRef,