mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2024-12-21 04:50:14 +08:00
feat(transfer): clsPrefix
This commit is contained in:
parent
60689e81a5
commit
a9a1a36fb6
@ -1,2 +1,2 @@
|
||||
/* istanbul ignore file */
|
||||
export { default as NTransfer } from './src/Transfer'
|
||||
export type { TransferProps } from './src/Transfer'
|
||||
|
@ -13,10 +13,10 @@ import { depx } from 'seemly'
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from '../../_internal/icons'
|
||||
import { NBaseIcon } from '../../_internal'
|
||||
import { NButton } from '../../button'
|
||||
import { useLocale, useFormItem, useTheme } from '../../_mixins'
|
||||
import { useLocale, useFormItem, useTheme, useConfig } from '../../_mixins'
|
||||
import type { ThemeProps } from '../../_mixins'
|
||||
import { createKey } from '../../_utils/cssr'
|
||||
import { warn, call } from '../../_utils'
|
||||
import { warn, call, ExtractPublicPropTypes } from '../../_utils'
|
||||
import type { MaybeArray } from '../../_utils'
|
||||
import { transferLight } from '../styles'
|
||||
import type { TransferTheme } from '../styles'
|
||||
@ -30,75 +30,81 @@ import {
|
||||
Option,
|
||||
Filter,
|
||||
OnUpdateValue,
|
||||
TransferInjection
|
||||
transferInjectionKey
|
||||
} from './interface'
|
||||
|
||||
const transferProps = {
|
||||
...(useTheme.props as ThemeProps<TransferTheme>),
|
||||
value: Array as PropType<OptionValue[] | null>,
|
||||
defaultValue: {
|
||||
type: Array as PropType<OptionValue[] | null>,
|
||||
default: null
|
||||
},
|
||||
options: {
|
||||
type: Array as PropType<Option[]>,
|
||||
default: () => []
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
virtualScroll: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
sourceTitle: String,
|
||||
targetTitle: String,
|
||||
filterable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
sourceFilterPlaceholder: String,
|
||||
targetFilterPlaceholder: String,
|
||||
filter: {
|
||||
type: Function as PropType<Filter>,
|
||||
default: (pattern: string, option: Option) => {
|
||||
if (!pattern) return true
|
||||
return ~('' + option.label)
|
||||
.toLowerCase()
|
||||
.indexOf(('' + pattern).toLowerCase())
|
||||
}
|
||||
},
|
||||
size: {
|
||||
type: String as PropType<'small' | 'medium' | 'large' | undefined>,
|
||||
default: undefined
|
||||
},
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
'onUpdate:value': [Function, Array] as PropType<MaybeArray<OnUpdateValue>>,
|
||||
onUpdateValue: [Function, Array] as PropType<MaybeArray<OnUpdateValue>>,
|
||||
onChange: {
|
||||
type: [Function, Array] as PropType<MaybeArray<OnUpdateValue>>,
|
||||
validator: () => {
|
||||
if (__DEV__) {
|
||||
warn(
|
||||
'transfer',
|
||||
'`on-change` is deprecated, please use `on-update:value` instead.'
|
||||
)
|
||||
}
|
||||
return true
|
||||
},
|
||||
default: undefined
|
||||
}
|
||||
} as const
|
||||
|
||||
export type TransferProps = ExtractPublicPropTypes<typeof transferProps>
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Transfer',
|
||||
props: {
|
||||
...(useTheme.props as ThemeProps<TransferTheme>),
|
||||
value: Array as PropType<OptionValue[] | null>,
|
||||
defaultValue: {
|
||||
type: Array as PropType<OptionValue[] | null>,
|
||||
default: null
|
||||
},
|
||||
options: {
|
||||
type: Array as PropType<Option[]>,
|
||||
default: () => []
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
virtualScroll: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
sourceTitle: String,
|
||||
targetTitle: String,
|
||||
filterable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
sourceFilterPlaceholder: String,
|
||||
targetFilterPlaceholder: String,
|
||||
filter: {
|
||||
type: Function as PropType<Filter>,
|
||||
default: (pattern: string, option: Option) => {
|
||||
if (!pattern) return true
|
||||
return ~('' + option.label)
|
||||
.toLowerCase()
|
||||
.indexOf(('' + pattern).toLowerCase())
|
||||
}
|
||||
},
|
||||
size: {
|
||||
type: String as PropType<'small' | 'medium' | 'large' | undefined>,
|
||||
default: undefined
|
||||
},
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
'onUpdate:value': [Function, Array] as PropType<MaybeArray<OnUpdateValue>>,
|
||||
onUpdateValue: [Function, Array] as PropType<MaybeArray<OnUpdateValue>>,
|
||||
onChange: {
|
||||
type: [Function, Array] as PropType<MaybeArray<OnUpdateValue>>,
|
||||
validator: () => {
|
||||
if (__DEV__) {
|
||||
warn(
|
||||
'transfer',
|
||||
'`on-change` is deprecated, please use `on-update:value` instead.'
|
||||
)
|
||||
}
|
||||
return true
|
||||
},
|
||||
default: undefined
|
||||
}
|
||||
},
|
||||
props: transferProps,
|
||||
setup (props) {
|
||||
const { mergedClsPrefix } = useConfig(props)
|
||||
const themeRef = useTheme(
|
||||
'Transfer',
|
||||
'Transfer',
|
||||
style,
|
||||
transferLight,
|
||||
props
|
||||
props,
|
||||
mergedClsPrefix
|
||||
)
|
||||
const formItem = useFormItem(props)
|
||||
const itemSizeRef = computed(() => {
|
||||
@ -210,9 +216,10 @@ export default defineComponent({
|
||||
)
|
||||
tgtCheckedValuesRef.value = []
|
||||
}
|
||||
provide<TransferInjection>(
|
||||
'NTransfer',
|
||||
provide(
|
||||
transferInjectionKey,
|
||||
reactive({
|
||||
cPrefix: mergedClsPrefix,
|
||||
mergedSize: formItem.mergedSize,
|
||||
disabled: toRef(props, 'disabled'),
|
||||
mergedTheme: themeRef,
|
||||
@ -229,6 +236,7 @@ export default defineComponent({
|
||||
return {
|
||||
...formItem,
|
||||
...useLocale('Transfer'),
|
||||
cPrefix: mergedClsPrefix,
|
||||
itemSize: itemSizeRef,
|
||||
isMounted: useIsMounted(),
|
||||
isInputing: isInputingRef,
|
||||
@ -305,24 +313,23 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const { cPrefix } = this
|
||||
return (
|
||||
<div
|
||||
class={[
|
||||
'n-transfer',
|
||||
{
|
||||
'n-transfer--disabled': this.disabled,
|
||||
'n-transfer--filterable': this.filterable
|
||||
}
|
||||
`${cPrefix}-transfer`,
|
||||
this.disabled && `${cPrefix}-transfer--disabled`,
|
||||
this.filterable && `${cPrefix}-transfer--filterable`
|
||||
]}
|
||||
style={this.cssVars as CSSProperties}
|
||||
>
|
||||
<div class="n-transfer-list">
|
||||
<div class={`${cPrefix}-transfer-list`}>
|
||||
<NTransferHeader
|
||||
source
|
||||
onChange={this.handleSrcHeaderCheck}
|
||||
title={this.sourceTitle || this.locale.sourceTitle}
|
||||
/>
|
||||
<div class="n-transfer-list-body">
|
||||
<div class={`${cPrefix}-transfer-list-body`}>
|
||||
{this.filterable ? (
|
||||
<NTransferFilter
|
||||
onUpdateValue={this.handleSrcFilterUpdateValue}
|
||||
@ -333,7 +340,7 @@ export default defineComponent({
|
||||
onBlur={this.handleInputBlur}
|
||||
/>
|
||||
) : null}
|
||||
<div class="n-transfer-list-flex-container">
|
||||
<div class={`${cPrefix}-transfer-list-flex-container`}>
|
||||
<NTransferList
|
||||
source
|
||||
options={this.filteredSrcOpts}
|
||||
@ -345,9 +352,9 @@ export default defineComponent({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="n-transfer-list__border" />
|
||||
<div class={`${cPrefix}-transfer-list__border`} />
|
||||
</div>
|
||||
<div class="n-transfer-gap">
|
||||
<div class={`${cPrefix}-transfer-gap`}>
|
||||
<NButton
|
||||
disabled={this.toButtonDisabled || this.disabled}
|
||||
theme={this.mergedTheme.peers.Button}
|
||||
@ -356,7 +363,9 @@ export default defineComponent({
|
||||
>
|
||||
{{
|
||||
icon: () => (
|
||||
<NBaseIcon>{{ default: () => <ChevronRightIcon /> }}</NBaseIcon>
|
||||
<NBaseIcon clsPrefix={cPrefix}>
|
||||
{{ default: () => <ChevronRightIcon /> }}
|
||||
</NBaseIcon>
|
||||
)
|
||||
}}
|
||||
</NButton>
|
||||
@ -368,17 +377,19 @@ export default defineComponent({
|
||||
>
|
||||
{{
|
||||
icon: () => (
|
||||
<NBaseIcon>{{ default: () => <ChevronLeftIcon /> }}</NBaseIcon>
|
||||
<NBaseIcon clsPrefix={cPrefix}>
|
||||
{{ default: () => <ChevronLeftIcon /> }}
|
||||
</NBaseIcon>
|
||||
)
|
||||
}}
|
||||
</NButton>
|
||||
</div>
|
||||
<div class="n-transfer-list">
|
||||
<div class={`${cPrefix}-transfer-list`}>
|
||||
<NTransferHeader
|
||||
onChange={this.handleTgtHeaderCheck}
|
||||
title={this.targetTitle || this.locale.targetTitle}
|
||||
/>
|
||||
<div class="n-transfer-list-body">
|
||||
<div class={`${cPrefix}-transfer-list-body`}>
|
||||
{this.filterable ? (
|
||||
<NTransferFilter
|
||||
onUpdateValue={this.handleTgtFilterUpdateValue}
|
||||
@ -389,7 +400,7 @@ export default defineComponent({
|
||||
onBlur={this.handleInputBlur}
|
||||
/>
|
||||
) : null}
|
||||
<div class="n-transfer-list-flex-container">
|
||||
<div class={`${cPrefix}-transfer-list-flex-container`}>
|
||||
<NTransferList
|
||||
options={this.filteredTgtOpts}
|
||||
disabled={this.disabled}
|
||||
@ -400,7 +411,7 @@ export default defineComponent({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="n-transfer-list__border" />
|
||||
<div class={`${cPrefix}-transfer-list__border`} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -2,7 +2,7 @@ import { h, defineComponent, inject, PropType } from 'vue'
|
||||
import { SearchIcon } from '../../_internal/icons'
|
||||
import { NBaseIcon } from '../../_internal'
|
||||
import { NInput } from '../../input'
|
||||
import { TransferInjection } from './interface'
|
||||
import { transferInjectionKey } from './interface'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TransferFilter',
|
||||
@ -24,23 +24,23 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
setup () {
|
||||
const NTransfer = inject<TransferInjection>(
|
||||
'NTransfer'
|
||||
) as TransferInjection
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const NTransfer = inject(transferInjectionKey)!
|
||||
return {
|
||||
NTransfer
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const { NTransfer } = this
|
||||
const { mergedTheme, cPrefix } = NTransfer
|
||||
return (
|
||||
<div class="n-transfer-filter">
|
||||
<div class={`${cPrefix}-transfer-filter`}>
|
||||
<NInput
|
||||
value={this.value}
|
||||
onUpdateValue={this.onUpdateValue}
|
||||
disabled={this.disabled}
|
||||
theme={NTransfer.mergedTheme.peers.Input}
|
||||
themeOverrides={NTransfer.mergedTheme.peerOverrides.Input}
|
||||
theme={mergedTheme.peers.Input}
|
||||
themeOverrides={mergedTheme.peerOverrides.Input}
|
||||
clearable
|
||||
size="small"
|
||||
placeholder={this.placeholder}
|
||||
@ -49,7 +49,7 @@ export default defineComponent({
|
||||
>
|
||||
{{
|
||||
clear: () => (
|
||||
<NBaseIcon class="n-transfer-icon">
|
||||
<NBaseIcon clsPrefix={cPrefix} class={`${cPrefix}-transfer-icon`}>
|
||||
{{ default: () => <SearchIcon /> }}
|
||||
</NBaseIcon>
|
||||
)
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { h, computed, defineComponent, inject, PropType } from 'vue'
|
||||
import { NCheckbox } from '../../checkbox'
|
||||
import { TransferInjection } from './interface'
|
||||
import { transferInjectionKey } from './interface'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TransferHeader',
|
||||
@ -16,9 +16,8 @@ export default defineComponent({
|
||||
title: String
|
||||
},
|
||||
setup (props) {
|
||||
const NTransfer = inject<TransferInjection>(
|
||||
'NTransfer'
|
||||
) as TransferInjection
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const NTransfer = inject(transferInjectionKey)!
|
||||
const checkboxPropsRef = computed(() => {
|
||||
const { source } = props
|
||||
if (source) {
|
||||
@ -30,20 +29,23 @@ export default defineComponent({
|
||||
return () => {
|
||||
const { source } = props
|
||||
const { value: checkboxProps } = checkboxPropsRef
|
||||
const { mergedTheme, cPrefix } = NTransfer
|
||||
return (
|
||||
<div class="n-transfer-list-header">
|
||||
<div class="n-transfer-list-header__checkbox">
|
||||
<div class={`${cPrefix}-transfer-list-header`}>
|
||||
<div class={`${cPrefix}-transfer-list-header__checkbox`}>
|
||||
<NCheckbox
|
||||
theme={NTransfer.mergedTheme.peers.Checkbox}
|
||||
themeOverrides={NTransfer.mergedTheme.peerOverrides.Checkbox}
|
||||
theme={mergedTheme.peers.Checkbox}
|
||||
themeOverrides={mergedTheme.peerOverrides.Checkbox}
|
||||
checked={checkboxProps.checked}
|
||||
indeterminate={checkboxProps.indeterminate}
|
||||
disabled={checkboxProps.disabled || NTransfer.disabled}
|
||||
onUpdateChecked={props.onChange}
|
||||
/>
|
||||
</div>
|
||||
<div class="n-transfer-list-header__header">{props.title}</div>
|
||||
<div class="n-transfer-list-header__extra">
|
||||
<div class={`${cPrefix}-transfer-list-header__header`}>
|
||||
{props.title}
|
||||
</div>
|
||||
<div class={`${cPrefix}-transfer-list-header__extra`}>
|
||||
{source
|
||||
? NTransfer.srcCheckedValues.length
|
||||
: NTransfer.tgtCheckedValues.length}
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
import { VirtualList, VirtualListRef } from 'vueuc'
|
||||
import { NEmpty } from '../../empty'
|
||||
import { NScrollbar, ScrollbarInst } from '../../scrollbar'
|
||||
import type { Option, TransferInjection } from './interface'
|
||||
import { Option, transferInjectionKey } from './interface'
|
||||
import NTransferListItem from './TransferListItem'
|
||||
|
||||
export default defineComponent({
|
||||
@ -46,9 +46,8 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
setup () {
|
||||
const NTransfer = inject<TransferInjection>(
|
||||
'NTransfer'
|
||||
) as TransferInjection
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const NTransfer = inject(transferInjectionKey)!
|
||||
const scrollerInstRef = ref<ScrollbarInst | null>(null)
|
||||
const vlInstRef = ref<VirtualListRef | null>(null)
|
||||
function syncVLScroller (): void {
|
||||
@ -77,12 +76,13 @@ export default defineComponent({
|
||||
},
|
||||
render () {
|
||||
const { NTransfer, syncVLScroller } = this
|
||||
const { mergedTheme, cPrefix } = NTransfer
|
||||
return this.options.length ? (
|
||||
this.virtualScroll ? (
|
||||
<NScrollbar
|
||||
ref="scrollerInstRef"
|
||||
theme={NTransfer.mergedTheme.peers.Scrollbar}
|
||||
themeOverrides={NTransfer.mergedTheme.peerOverrides.Scrollbar}
|
||||
theme={mergedTheme.peers.Scrollbar}
|
||||
themeOverrides={mergedTheme.peerOverrides.Scrollbar}
|
||||
container={this.scrollContainer}
|
||||
content={this.scrollContent}
|
||||
>
|
||||
@ -90,7 +90,8 @@ export default defineComponent({
|
||||
default: () => (
|
||||
<VirtualList
|
||||
ref="srcVlInstRef"
|
||||
class="n-virtual-scroller n-transfer-list-content"
|
||||
style={{ height: '100%' }}
|
||||
class={`${cPrefix}-transfer-list-content`}
|
||||
items={this.options}
|
||||
itemSize={this.itemSize}
|
||||
showScrollbar={false}
|
||||
@ -122,7 +123,7 @@ export default defineComponent({
|
||||
>
|
||||
{{
|
||||
default: () => (
|
||||
<div class="n-transfer-list-content">
|
||||
<div class={`${cPrefix}-transfer-list-content`}>
|
||||
<TransitionGroup
|
||||
name="item"
|
||||
appear={this.isMounted}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { h, inject, defineComponent } from 'vue'
|
||||
import { useMemo } from 'vooks'
|
||||
import { NCheckbox } from '../../checkbox'
|
||||
import type { TransferInjection } from './interface'
|
||||
import { transferInjectionKey } from './interface'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NTransferListItem',
|
||||
@ -25,9 +25,8 @@ export default defineComponent({
|
||||
},
|
||||
setup (props) {
|
||||
const { source } = props
|
||||
const NTransfer = inject<TransferInjection>(
|
||||
'NTransfer'
|
||||
) as TransferInjection
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const NTransfer = inject(transferInjectionKey)!
|
||||
const checkedRef = source
|
||||
? useMemo(() => NTransfer.srcCheckedValues.includes(props.value))
|
||||
: useMemo(() => NTransfer.tgtCheckedValues.includes(props.value))
|
||||
@ -45,34 +44,32 @@ export default defineComponent({
|
||||
return {
|
||||
NTransfer,
|
||||
checked: checkedRef,
|
||||
className: source
|
||||
? 'n-transfer-list-item--source'
|
||||
: 'n-transfer-list-item--target',
|
||||
handleClick
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const { disabled, NTransfer, label, checked, className } = this
|
||||
const { disabled, NTransfer, label, checked, source } = this
|
||||
const { mergedTheme, cPrefix } = NTransfer
|
||||
return (
|
||||
<div
|
||||
class={[
|
||||
'n-transfer-list-item',
|
||||
className,
|
||||
{
|
||||
'n-transfer-list-item--disabled': disabled
|
||||
}
|
||||
`${cPrefix}-transfer-list-item`,
|
||||
disabled && `${cPrefix}-transfer-list-item--disabled`,
|
||||
source
|
||||
? `${cPrefix}-transfer-list-item--source`
|
||||
: `${cPrefix}-transfer-list-item--target`
|
||||
]}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
<div class="n-transfer-list-item__checkbox">
|
||||
<div class={`${cPrefix}-transfer-list-item__checkbox`}>
|
||||
<NCheckbox
|
||||
theme={NTransfer.mergedTheme.peers.Checkbox}
|
||||
themeOverrides={NTransfer.mergedTheme.peerOverrides.Checkbox}
|
||||
theme={mergedTheme.peers.Checkbox}
|
||||
themeOverrides={mergedTheme.peerOverrides.Checkbox}
|
||||
disabled={disabled}
|
||||
checked={checked}
|
||||
/>
|
||||
</div>
|
||||
<div class="n-transfer-list-item__label">{label}</div>
|
||||
<div class={`${cPrefix}-transfer-list-item__label`}>{label}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { InjectionKey } from 'vue'
|
||||
import type { MergedTheme } from '../../_mixins'
|
||||
import type { TransferTheme } from '../styles'
|
||||
|
||||
@ -21,6 +22,7 @@ export type Filter = (
|
||||
) => boolean
|
||||
|
||||
export interface TransferInjection {
|
||||
cPrefix: string
|
||||
mergedSize: 'small' | 'medium' | 'large'
|
||||
disabled: boolean
|
||||
mergedTheme: MergedTheme<TransferTheme>
|
||||
@ -34,4 +36,8 @@ export interface TransferInjection {
|
||||
handleTgtCheckboxClick: (checked: boolean, value: OptionValue) => void
|
||||
}
|
||||
|
||||
export const transferInjectionKey: InjectionKey<TransferInjection> = Symbol(
|
||||
'transfer'
|
||||
)
|
||||
|
||||
export type OnUpdateValue = (value: OptionValue[]) => void
|
||||
|
@ -82,16 +82,6 @@ export default c([
|
||||
border-radius: var(--border-radius);
|
||||
background-color: var(--list-color);
|
||||
`, [
|
||||
cB('virtual-scroller', {
|
||||
height: '100%',
|
||||
scrollbarWidth: 'none',
|
||||
'-moz-scrollbar-width': 'none'
|
||||
}, [
|
||||
c('&::-webkit-scrollbar', {
|
||||
width: 0,
|
||||
height: 0
|
||||
})
|
||||
]),
|
||||
cE('border', `
|
||||
border: 1px solid var(--border-color);
|
||||
transition: border-color .3s var(--bezier);
|
||||
|
Loading…
Reference in New Issue
Block a user