mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-02-23 13:31:06 +08:00
feat(collapse): clsPrefix
This commit is contained in:
parent
c4487319fb
commit
18573f9157
@ -1,3 +1,4 @@
|
||||
/* istanbul ignore file */
|
||||
export { default as NCollapse } from './src/Collapse'
|
||||
export { default as NCollapseItem } from './src/CollapseItem'
|
||||
export type { CollapseProps } from './src/Collapse'
|
||||
export type { CollapseItemProps } from './src/CollapseItem'
|
||||
|
@ -3,15 +3,17 @@ import {
|
||||
h,
|
||||
defineComponent,
|
||||
PropType,
|
||||
toRef,
|
||||
reactive,
|
||||
provide,
|
||||
ref
|
||||
ref,
|
||||
InjectionKey,
|
||||
Ref,
|
||||
ExtractPropTypes,
|
||||
CSSProperties
|
||||
} from 'vue'
|
||||
import { intersection } from 'lodash-es'
|
||||
import { useTheme } from '../../_mixins'
|
||||
import { useConfig, useTheme } from '../../_mixins'
|
||||
import type { ThemeProps } from '../../_mixins'
|
||||
import { call, warn } from '../../_utils'
|
||||
import { call, ExtractPublicPropTypes, warn } from '../../_utils'
|
||||
import type { MaybeArray } from '../../_utils'
|
||||
import { collapseLight, CollapseTheme } from '../styles'
|
||||
import style from './styles/index.cssr'
|
||||
@ -24,10 +26,60 @@ import {
|
||||
OnItemHeaderClickImpl
|
||||
} from './interface'
|
||||
|
||||
const collapseProps = {
|
||||
...(useTheme.props as ThemeProps<CollapseTheme>),
|
||||
defaultExpandesNames: [Array, String] as PropType<
|
||||
string | number | Array<string | number> | null
|
||||
>,
|
||||
expandedNames: [Array, String] as PropType<
|
||||
string | number | Array<string | number> | null
|
||||
>,
|
||||
arrowPlacement: {
|
||||
type: String as PropType<'left' | 'right'>,
|
||||
default: 'left'
|
||||
},
|
||||
accordion: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
displayDirective: {
|
||||
type: String as PropType<'if' | 'show'>,
|
||||
default: 'if'
|
||||
},
|
||||
onItemHeaderClick: [Function, Array] as PropType<
|
||||
MaybeArray<OnItemHeaderClick>
|
||||
>,
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
'onUpdate:expandedNames': [Function, Array] as PropType<
|
||||
MaybeArray<OnUpdateExpandedNames>
|
||||
>,
|
||||
onUpdateExpandedNames: [Function, Array] as PropType<
|
||||
MaybeArray<OnUpdateExpandedNames>
|
||||
>,
|
||||
// deprecated
|
||||
onExpandedNamesChange: {
|
||||
type: [Function, Array] as PropType<
|
||||
MaybeArray<OnUpdateExpandedNames> | undefined
|
||||
>,
|
||||
validator: () => {
|
||||
if (__DEV__) {
|
||||
warn(
|
||||
'collapse',
|
||||
'`on-expanded-names-change` is deprecated, please use `on-update:expanded-names` instead.'
|
||||
)
|
||||
}
|
||||
return true
|
||||
},
|
||||
default: undefined
|
||||
}
|
||||
} as const
|
||||
|
||||
export type CollapseProps = ExtractPublicPropTypes<typeof collapseProps>
|
||||
|
||||
export interface NCollapseInjection {
|
||||
arrowPlacement: 'left' | 'right'
|
||||
displayDirective: 'if' | 'show'
|
||||
expandedNames: string | number | Array<string | number> | null
|
||||
props: ExtractPropTypes<typeof collapseProps>
|
||||
expandedNamesRef: Ref<string | number | Array<string | number> | null>
|
||||
clsPrefixRef: Ref<string>
|
||||
collectedItemNames: Array<string | number>
|
||||
toggleItem: (
|
||||
collapse: boolean,
|
||||
@ -36,61 +88,20 @@ export interface NCollapseInjection {
|
||||
) => void
|
||||
}
|
||||
|
||||
export const collapseInjectionKey: InjectionKey<NCollapseInjection> = Symbol(
|
||||
'collapse'
|
||||
)
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Collapse',
|
||||
props: {
|
||||
...(useTheme.props as ThemeProps<CollapseTheme>),
|
||||
defaultExpandesNames: [Array, String] as PropType<
|
||||
string | number | Array<string | number> | null
|
||||
>,
|
||||
expandedNames: [Array, String] as PropType<
|
||||
string | number | Array<string | number> | null
|
||||
>,
|
||||
arrowPlacement: {
|
||||
type: String as PropType<'left' | 'right'>,
|
||||
default: 'left'
|
||||
},
|
||||
accordion: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
displayDirective: {
|
||||
type: String as PropType<'if' | 'show'>,
|
||||
default: 'if'
|
||||
},
|
||||
onItemHeaderClick: [Function, Array] as PropType<
|
||||
MaybeArray<OnItemHeaderClick>
|
||||
>,
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
'onUpdate:expandedNames': [Function, Array] as PropType<
|
||||
MaybeArray<OnUpdateExpandedNames>
|
||||
>,
|
||||
onUpdateExpandedNames: [Function, Array] as PropType<
|
||||
MaybeArray<OnUpdateExpandedNames>
|
||||
>,
|
||||
// deprecated
|
||||
onExpandedNamesChange: {
|
||||
type: [Function, Array] as PropType<
|
||||
MaybeArray<OnUpdateExpandedNames> | undefined
|
||||
>,
|
||||
validator: () => {
|
||||
if (__DEV__) {
|
||||
warn(
|
||||
'collapse',
|
||||
'`on-expanded-names-change` is deprecated, please use `on-update:expanded-names` instead.'
|
||||
)
|
||||
}
|
||||
return true
|
||||
},
|
||||
default: undefined
|
||||
}
|
||||
},
|
||||
props: collapseProps,
|
||||
setup (props) {
|
||||
const { mergedClsPrefix } = useConfig(props)
|
||||
const uncontrolledExpandedNamesRef = ref<
|
||||
string | number | Array<string | number> | null
|
||||
>(null)
|
||||
const controlledExpandedNamesRef = computed(() => props.expandedNames)
|
||||
const mergedExpandedNames = useMergedState(
|
||||
const mergedExpandedNamesRef = useMergedState(
|
||||
controlledExpandedNamesRef,
|
||||
uncontrolledExpandedNamesRef
|
||||
)
|
||||
@ -100,7 +111,8 @@ export default defineComponent({
|
||||
'Collapse',
|
||||
style,
|
||||
collapseLight,
|
||||
props
|
||||
props,
|
||||
mergedClsPrefix
|
||||
)
|
||||
function doUpdateExpandedNames (
|
||||
names: Array<string | number> | string | number
|
||||
@ -135,7 +147,7 @@ export default defineComponent({
|
||||
event: MouseEvent
|
||||
): void {
|
||||
const { accordion } = props
|
||||
const { value: expandedNames } = mergedExpandedNames
|
||||
const { value: expandedNames } = mergedExpandedNamesRef
|
||||
if (accordion) {
|
||||
if (collapse) {
|
||||
doUpdateExpandedNames([name])
|
||||
@ -165,18 +177,16 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
}
|
||||
provide<NCollapseInjection>(
|
||||
'NCollapse',
|
||||
reactive({
|
||||
arrowPlacement: toRef(props, 'arrowPlacement'),
|
||||
displayDirective: toRef(props, 'displayDirective'),
|
||||
expandedNames: mergedExpandedNames,
|
||||
collectedItemNames,
|
||||
toggleItem
|
||||
})
|
||||
)
|
||||
provide(collapseInjectionKey, {
|
||||
props,
|
||||
clsPrefixRef: mergedClsPrefix,
|
||||
expandedNamesRef: mergedExpandedNamesRef,
|
||||
collectedItemNames,
|
||||
toggleItem
|
||||
})
|
||||
return {
|
||||
mergedTheme: themeRef,
|
||||
cPrefix: mergedClsPrefix,
|
||||
cssVars: computed(() => {
|
||||
const {
|
||||
common: { cubicBezierEaseInOut },
|
||||
@ -204,13 +214,13 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
render () {
|
||||
return h(
|
||||
'div',
|
||||
{
|
||||
class: 'n-collapse',
|
||||
style: this.cssVars
|
||||
},
|
||||
this.$slots
|
||||
return (
|
||||
<div
|
||||
class={`${this.cPrefix}-collapse`}
|
||||
style={this.cssVars as CSSProperties}
|
||||
>
|
||||
{this.$slots}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
@ -1,30 +1,45 @@
|
||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
import { h, defineComponent, PropType, inject, computed, renderSlot } from 'vue'
|
||||
import { createId } from 'seemly'
|
||||
import { ChevronRightIcon as ArrowIcon } from '../../_internal/icons'
|
||||
import { NBaseIcon } from '../../_internal'
|
||||
import { useInjectionCollection } from '../../_utils/composable'
|
||||
import NCollapseItemContent from './CollapseItemContent'
|
||||
import { NCollapseInjection } from './Collapse'
|
||||
import { useMemo } from 'vooks'
|
||||
import { ChevronRightIcon as ArrowIcon } from '../../_internal/icons'
|
||||
import { useInjectionCollection } from '../../_utils/composable'
|
||||
import { NBaseIcon } from '../../_internal'
|
||||
import { ExtractPublicPropTypes, throwError } from '../../_utils'
|
||||
import { collapseInjectionKey } from './Collapse'
|
||||
import NCollapseItemContent from './CollapseItemContent'
|
||||
|
||||
const collapseItemProps = {
|
||||
title: String,
|
||||
name: [String, Number] as PropType<string | number>,
|
||||
displayDirective: String as PropType<'if' | 'show'>
|
||||
} as const
|
||||
|
||||
export type CollapseItemProps = ExtractPublicPropTypes<typeof collapseItemProps>
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CollapseItem',
|
||||
props: {
|
||||
title: String,
|
||||
name: [String, Number],
|
||||
displayDirective: String as PropType<'if' | 'show'>
|
||||
},
|
||||
props: collapseItemProps,
|
||||
setup (props) {
|
||||
const randomName = createId()
|
||||
const mergedNameRef = useMemo(() => {
|
||||
return props.name ?? randomName
|
||||
})
|
||||
const NCollapse = inject<NCollapseInjection>(
|
||||
'NCollapse'
|
||||
) as NCollapseInjection
|
||||
useInjectionCollection('NCollapse', 'collectedItemNames', mergedNameRef)
|
||||
const NCollapse = inject(collapseInjectionKey)
|
||||
if (!NCollapse) {
|
||||
throwError(
|
||||
'collapse-item',
|
||||
'`n-collapse-item` must be placed inside `n-collapse`.'
|
||||
)
|
||||
}
|
||||
const { expandedNamesRef, props: collapseProps, clsPrefixRef } = NCollapse
|
||||
useInjectionCollection(
|
||||
collapseInjectionKey,
|
||||
'collectedItemNames',
|
||||
mergedNameRef
|
||||
)
|
||||
const collapsedRef = computed<boolean>(() => {
|
||||
const { expandedNames } = NCollapse
|
||||
const { value: expandedNames } = expandedNamesRef
|
||||
if (Array.isArray(expandedNames)) {
|
||||
const { value: name } = mergedNameRef
|
||||
return !~expandedNames.findIndex(
|
||||
@ -35,17 +50,18 @@ export default defineComponent({
|
||||
})
|
||||
return {
|
||||
randomName,
|
||||
cPrefix: clsPrefixRef,
|
||||
collapsed: collapsedRef,
|
||||
mergedDisplayDirective: computed<'if' | 'show'>(() => {
|
||||
const { displayDirective } = props
|
||||
if (displayDirective) {
|
||||
return displayDirective
|
||||
} else {
|
||||
return NCollapse.displayDirective
|
||||
return collapseProps.displayDirective
|
||||
}
|
||||
}),
|
||||
arrowPlacement: computed<'left' | 'right'>(() => {
|
||||
return NCollapse.arrowPlacement
|
||||
return collapseProps.arrowPlacement
|
||||
}),
|
||||
handleClick (e: MouseEvent) {
|
||||
if (NCollapse) {
|
||||
@ -60,33 +76,37 @@ export default defineComponent({
|
||||
arrowPlacement,
|
||||
collapsed,
|
||||
title,
|
||||
mergedDisplayDirective
|
||||
mergedDisplayDirective,
|
||||
cPrefix
|
||||
} = this
|
||||
const headerNode = renderSlot($slots, 'header', undefined, () => [title])
|
||||
return (
|
||||
<div
|
||||
class={[
|
||||
'n-collapse-item',
|
||||
`n-collapse-item--${arrowPlacement}-arrow-placement`,
|
||||
!collapsed && 'n-collapse-item--active'
|
||||
`${cPrefix}-collapse-item`,
|
||||
`${cPrefix}-collapse-item--${arrowPlacement}-arrow-placement`,
|
||||
!collapsed && `${cPrefix}-collapse-item--active`
|
||||
]}
|
||||
>
|
||||
<div
|
||||
class={[
|
||||
'n-collapse-item__header',
|
||||
!collapsed && 'n-collapse-item__header--active'
|
||||
`${cPrefix}-collapse-item__header`,
|
||||
!collapsed && `${cPrefix}-collapse-item__header--active`
|
||||
]}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
{arrowPlacement === 'right' && headerNode}
|
||||
<div class="n-collapse-item-arrow">
|
||||
<div class={`${cPrefix}-collapse-item-arrow`}>
|
||||
{renderSlot($slots, 'arrow', { collapsed: collapsed }, () => [
|
||||
<NBaseIcon>{{ default: () => <ArrowIcon /> }}</NBaseIcon>
|
||||
<NBaseIcon clsPrefix={cPrefix}>
|
||||
{{ default: () => <ArrowIcon /> }}
|
||||
</NBaseIcon>
|
||||
])}
|
||||
</div>
|
||||
{arrowPlacement === 'left' && headerNode}
|
||||
</div>
|
||||
<NCollapseItemContent
|
||||
clsPrefix={cPrefix}
|
||||
displayDirective={mergedDisplayDirective}
|
||||
show={!collapsed}
|
||||
>
|
||||
|
@ -1,10 +1,20 @@
|
||||
import { h, withDirectives, vShow, defineComponent, toRef } from 'vue'
|
||||
import { h, withDirectives, vShow, defineComponent, toRef, PropType } from 'vue'
|
||||
import { useFalseUntilTruthy } from 'vooks'
|
||||
import { NFadeInExpandTransition } from '../../_internal'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CollapseItemContent',
|
||||
props: ['displayDirective', 'show'],
|
||||
props: {
|
||||
displayDirective: {
|
||||
type: String as PropType<'if' | 'show'>,
|
||||
required: true
|
||||
},
|
||||
show: Boolean,
|
||||
clsPrefix: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
const onceTrueRef = useFalseUntilTruthy(toRef(props, 'show'))
|
||||
return {
|
||||
@ -16,11 +26,13 @@ export default defineComponent({
|
||||
<NFadeInExpandTransition>
|
||||
{{
|
||||
default: () => {
|
||||
const { show, displayDirective, onceTrue } = this
|
||||
const { show, displayDirective, onceTrue, clsPrefix } = this
|
||||
const useVShow = displayDirective === 'show' && onceTrue
|
||||
const contentNode = (
|
||||
<div class="n-collapse-item__content-wrapper">
|
||||
<div class="n-collapse-item__content-inner">{this.$slots}</div>
|
||||
<div class={`${clsPrefix}-collapse-item__content-wrapper`}>
|
||||
<div class={`${clsPrefix}-collapse-item__content-inner`}>
|
||||
{this.$slots}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
return useVShow
|
||||
|
Loading…
Reference in New Issue
Block a user