mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-04-12 14:40:47 +08:00
feat(transfer): redesign
This commit is contained in:
parent
3b64ef8fba
commit
2cf2a28213
@ -2,6 +2,10 @@
|
||||
|
||||
## NEXT_VERSION
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- `n-transfer`'s UI is totally refactored. The original transfer component is renamed as `n-legacy-transfer` and will be removed in next major version.
|
||||
|
||||
### Fixes
|
||||
|
||||
- `n-notification` add `keepAliveOnHover` props to control whether the notification will be closed when mouse hover, closes [#3249](https://github.com/TuSimple/naive-ui/issues/3249).
|
||||
@ -20,7 +24,8 @@
|
||||
- `n-checkbox-group`'s `on-update:value` prop adds trigger checkbox's value to params, closes [#3277](https://github.com/TuSimple/naive-ui/issues/3277).
|
||||
- `n-tree` supports RTL.
|
||||
- `n-input` adds `scrollTo` method, closes [#3280](https://github.com/TuSimple/naive-ui/issues/3280).
|
||||
- `n-transfer` add `render-label` prop.
|
||||
- `n-transfer` add `render-source-label` prop.
|
||||
- `n-transfer` add `render-target-label` prop.
|
||||
- `n-transfer` add `render-source-list` prop.
|
||||
|
||||
## 2.31.0
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- `n-transfer` 的样式及代码被重构
|
||||
- `n-transfer` 的 UI 完全重构,原本的 transfer 组件被重命名为 `n-legacy-transfer`,并将在下个主版本被移除。
|
||||
|
||||
### Fixes
|
||||
|
||||
@ -24,7 +24,8 @@
|
||||
- `n-checkbox-group` 的 `on-update:value` 属性增加触发变更的 checkbox 的值到参数中,关闭 [#3277](https://github.com/TuSimple/naive-ui/issues/3277)
|
||||
- `n-tree` 支持 RTL
|
||||
- `n-input` 新增 `scrollTo` 方法,关闭 [#3280](https://github.com/TuSimple/naive-ui/issues/3280)
|
||||
- `n-transfer` 新增 `render-label` 属性
|
||||
- `n-transfer` 新增 `render-source-label` 属性
|
||||
- `n-transfer` 新增 `render-target-label` 属性
|
||||
- `n-transfer` 新增 `render-source-list` 属性
|
||||
|
||||
## 2.31.0
|
||||
|
@ -44,6 +44,7 @@ export * from './input'
|
||||
export * from './input-number'
|
||||
export * from './layout'
|
||||
export * from './legacy-grid'
|
||||
export * from './legacy-transfer'
|
||||
export * from './list'
|
||||
export * from './loading-bar'
|
||||
export * from './log'
|
||||
|
@ -37,6 +37,7 @@ import type { ImageTheme } from '../../image/styles'
|
||||
import type { InputTheme } from '../../input/styles'
|
||||
import type { InputNumberTheme } from '../../input-number/styles'
|
||||
import type { LayoutTheme } from '../../layout/styles'
|
||||
import type { LegacyTransferTheme } from '../../legacy-transfer/styles'
|
||||
import type { ListTheme } from '../../list/styles'
|
||||
import type { LoadingBarTheme } from '../../loading-bar/styles'
|
||||
import type { LogTheme } from '../../log/styles'
|
||||
@ -134,6 +135,7 @@ export interface GlobalThemeWithoutCommon {
|
||||
Input?: InputTheme
|
||||
InputNumber?: InputNumberTheme
|
||||
Layout?: LayoutTheme
|
||||
LegacyTransfer?: LegacyTransferTheme
|
||||
List?: ListTheme
|
||||
LoadingBar?: LoadingBarTheme
|
||||
Log?: LogTheme
|
||||
|
@ -1,11 +1,11 @@
|
||||
<markdown>
|
||||
# Basic
|
||||
|
||||
Basic example of the Transfer component. If you have tons of data, see below for virtualised lists.
|
||||
Basic example of the Transfer component. If you have tons of data, see below for virtualized list.
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-transfer ref="transfer" v-model:value="value" :options="options" />
|
||||
<n-legacy-transfer ref="transfer" v-model:value="value" :options="options" />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
@ -3,7 +3,7 @@
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-transfer
|
||||
<n-legacy-transfer
|
||||
ref="transfer"
|
||||
v-model:value="value"
|
||||
virtual-scroll
|
||||
|
@ -2,8 +2,10 @@
|
||||
|
||||
<!--single-column-->
|
||||
|
||||
<n-alert title="Warning">
|
||||
The transfer component is deprecated and will be removed in the next major version.
|
||||
<n-alert title="Warning" type="warning">
|
||||
The transfer component is deprecated. It won't have any new feature and will be removed in the next major version. It's recommended to use new <router-link to="transfer" custom v-slot="{ href, navigate }">
|
||||
<n-a :href="href" @click="navigate">Transfer</n-a>
|
||||
</router-link>.
|
||||
</n-alert>
|
||||
|
||||
Left, right, right, left... I'm a simple man, and I can play this all day.
|
||||
@ -27,7 +29,7 @@ filterable.vue
|
||||
| disabled | `boolean` | `true` | Disabled state. |
|
||||
| filterable | `boolean` | `false` | Filterable state. |
|
||||
| filter | `function` | `(pattern: string, option: TransferOption, from: 'source' \| 'target') => boolean` | A basic label string match function. |
|
||||
| options | `Array<TransferOption>` | `[]` | For configuration options, see the TransferOption Type below. |
|
||||
| options | `TransferOption[]` | `[]` | For configuration options, see the TransferOption Type below. |
|
||||
| size | `'small' \| 'medium' \| 'large'` | `'medium'` | Size. |
|
||||
| source-filter-placeholder | `string` | `undefined` | Placeholder for the source items search box. |
|
||||
| source-title | `string` | `'Source'` | Source items title. |
|
||||
|
@ -5,7 +5,7 @@ If you have tons of data, you may need to speed the transfer up! Set `virtual-sc
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-transfer
|
||||
<n-legacy-transfer
|
||||
ref="transfer"
|
||||
v-model:value="value"
|
||||
:options="options"
|
||||
|
@ -6,13 +6,13 @@ Mixing sizes does not look harmonious.
|
||||
|
||||
<template>
|
||||
<n-space vertical>
|
||||
<n-transfer
|
||||
<n-legacy-transfer
|
||||
ref="transfer"
|
||||
v-model:value="value"
|
||||
:options="options"
|
||||
size="small"
|
||||
/>
|
||||
<n-transfer
|
||||
<n-legacy-transfer
|
||||
ref="transfer"
|
||||
v-model:value="value"
|
||||
:options="options"
|
||||
|
@ -5,7 +5,7 @@
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-transfer ref="transfer" v-model:value="value" :options="options" />
|
||||
<n-legacy-transfer ref="transfer" v-model:value="value" :options="options" />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
@ -3,7 +3,7 @@
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-transfer
|
||||
<n-legacy-transfer
|
||||
ref="transfer"
|
||||
v-model:value="value"
|
||||
virtual-scroll
|
||||
|
@ -2,8 +2,10 @@
|
||||
|
||||
<!--single-column-->
|
||||
|
||||
<n-alert title="警告">
|
||||
这个穿梭框组件已经被废弃,并将在下一个大版本中彻底移除。
|
||||
<n-alert title="警告" type="warning">
|
||||
这个穿梭框组件已经被废弃,不会迭代任何新的功能,并将在下一个大版本中彻底移除。推荐使用新的 <router-link to="transfer" custom v-slot="{ href, navigate }">
|
||||
<n-a :href="href" @click="navigate">穿梭框</n-a>
|
||||
</router-link>。
|
||||
</n-alert>
|
||||
|
||||
左、右、左、右...像我这么无聊的人能玩一整天。
|
||||
@ -27,7 +29,7 @@ filterable.vue
|
||||
| disabled | `boolean` | `true` | 是否禁用 |
|
||||
| filterable | `boolean` | `false` | 是否可过滤 |
|
||||
| filter | `(pattern: string, option: TransferOption, from: 'source' \| 'target') => boolean` | 一个简单的标签字符串匹配函数 | 搜索时使用的过滤函数 |
|
||||
| options | `Array<TransferOption>` | `[]` | 配置选项内容,详情见 TransferOption Type |
|
||||
| options | `TransferOption[]` | `[]` | 配置选项内容,详情见 TransferOption Type |
|
||||
| size | `'small' \| 'medium' \| 'large'` | `'medium'` | 尺寸 |
|
||||
| source-filter-placeholder | `string` | `undefined` | 源项搜索框中的占位符 |
|
||||
| source-title | `string` | `'源项'` | 源项标题 |
|
||||
|
@ -5,7 +5,7 @@
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-transfer
|
||||
<n-legacy-transfer
|
||||
ref="transfer"
|
||||
v-model:value="value"
|
||||
:options="options"
|
||||
|
@ -6,13 +6,13 @@
|
||||
|
||||
<template>
|
||||
<n-space vertical>
|
||||
<n-transfer
|
||||
<n-legacy-transfer
|
||||
ref="transfer"
|
||||
v-model:value="value"
|
||||
:options="options"
|
||||
size="small"
|
||||
/>
|
||||
<n-transfer
|
||||
<n-legacy-transfer
|
||||
ref="transfer"
|
||||
v-model:value="value"
|
||||
:options="options"
|
||||
|
@ -4,7 +4,8 @@ import {
|
||||
h,
|
||||
provide,
|
||||
PropType,
|
||||
CSSProperties
|
||||
CSSProperties,
|
||||
watchEffect
|
||||
} from 'vue'
|
||||
import { useIsMounted } from 'vooks'
|
||||
import { depx } from 'seemly'
|
||||
@ -14,10 +15,10 @@ import { NButton } from '../../button'
|
||||
import { useLocale, useFormItem, useTheme, useConfig } from '../../_mixins'
|
||||
import type { ThemeProps } from '../../_mixins'
|
||||
import { createKey } from '../../_utils/cssr'
|
||||
import { warn, call, ExtractPublicPropTypes } from '../../_utils'
|
||||
import { call, ExtractPublicPropTypes, warnOnce } from '../../_utils'
|
||||
import type { MaybeArray } from '../../_utils'
|
||||
import { transferLight } from '../styles'
|
||||
import type { TransferTheme } from '../styles'
|
||||
import { legacyTransferLight } from '../styles'
|
||||
import type { LegacyTransferTheme } from '../styles'
|
||||
import NTransferHeader from './TransferHeader'
|
||||
import NTransferList from './TransferList'
|
||||
import NTransferFilter from './TransferFilter'
|
||||
@ -32,7 +33,7 @@ import {
|
||||
} from './interface'
|
||||
|
||||
export const transferProps = {
|
||||
...(useTheme.props as ThemeProps<TransferTheme>),
|
||||
...(useTheme.props as ThemeProps<LegacyTransferTheme>),
|
||||
value: Array as PropType<OptionValue[] | null>,
|
||||
defaultValue: {
|
||||
type: Array as PropType<OptionValue[] | null>,
|
||||
@ -64,33 +65,31 @@ export const transferProps = {
|
||||
size: String as PropType<'small' | 'medium' | 'large'>,
|
||||
'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
|
||||
}
|
||||
onChange: [Function, Array] as PropType<MaybeArray<OnUpdateValue>>
|
||||
} as const
|
||||
|
||||
export type TransferProps = ExtractPublicPropTypes<typeof transferProps>
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Transfer',
|
||||
name: 'LegacyTransfer',
|
||||
props: transferProps,
|
||||
setup (props) {
|
||||
if (__DEV__) {
|
||||
watchEffect(() => {
|
||||
if (props.onChange !== undefined) {
|
||||
warnOnce(
|
||||
'legacy-transfer',
|
||||
'`on-change` is deprecated, please use `on-update:value` instead.'
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
const { mergedClsPrefixRef } = useConfig(props)
|
||||
const themeRef = useTheme(
|
||||
'Transfer',
|
||||
'-transfer',
|
||||
'LegacyTransfer',
|
||||
'-legacy-transfer',
|
||||
style,
|
||||
transferLight,
|
||||
legacyTransferLight,
|
||||
props,
|
||||
mergedClsPrefixRef
|
||||
)
|
||||
@ -217,7 +216,7 @@ export default defineComponent({
|
||||
handleSrcCheckboxClick,
|
||||
handleTgtCheckboxClick
|
||||
})
|
||||
const { localeRef } = useLocale('Transfer')
|
||||
const { localeRef } = useLocale('LegacyTransfer')
|
||||
return {
|
||||
locale: localeRef,
|
||||
mergedClsPrefix: mergedClsPrefixRef,
|
||||
@ -300,19 +299,19 @@ export default defineComponent({
|
||||
return (
|
||||
<div
|
||||
class={[
|
||||
`${mergedClsPrefix}-transfer`,
|
||||
this.mergedDisabled && `${mergedClsPrefix}-transfer--disabled`,
|
||||
this.filterable && `${mergedClsPrefix}-transfer--filterable`
|
||||
`${mergedClsPrefix}-legacy-transfer`,
|
||||
this.mergedDisabled && `${mergedClsPrefix}-legacy-transfer--disabled`,
|
||||
this.filterable && `${mergedClsPrefix}-legacy-transfer--filterable`
|
||||
]}
|
||||
style={this.cssVars as CSSProperties}
|
||||
>
|
||||
<div class={`${mergedClsPrefix}-transfer-list`}>
|
||||
<div class={`${mergedClsPrefix}-legacy-transfer-list`}>
|
||||
<NTransferHeader
|
||||
source
|
||||
onChange={this.handleSrcHeaderCheck}
|
||||
title={this.sourceTitle || this.locale.sourceTitle}
|
||||
/>
|
||||
<div class={`${mergedClsPrefix}-transfer-list-body`}>
|
||||
<div class={`${mergedClsPrefix}-legacy-transfer-list-body`}>
|
||||
{this.filterable ? (
|
||||
<NTransferFilter
|
||||
onUpdateValue={this.handleSrcFilterUpdateValue}
|
||||
@ -323,7 +322,9 @@ export default defineComponent({
|
||||
onBlur={this.handleInputBlur}
|
||||
/>
|
||||
) : null}
|
||||
<div class={`${mergedClsPrefix}-transfer-list-flex-container`}>
|
||||
<div
|
||||
class={`${mergedClsPrefix}-legacy-transfer-list-flex-container`}
|
||||
>
|
||||
<NTransferList
|
||||
source
|
||||
options={this.filteredSrcOpts}
|
||||
@ -335,9 +336,9 @@ export default defineComponent({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class={`${mergedClsPrefix}-transfer-list__border`} />
|
||||
<div class={`${mergedClsPrefix}-legacy-transfer-list__border`} />
|
||||
</div>
|
||||
<div class={`${mergedClsPrefix}-transfer-gap`}>
|
||||
<div class={`${mergedClsPrefix}-legacy-transfer-gap`}>
|
||||
<NButton
|
||||
disabled={this.toButtonDisabled || this.mergedDisabled}
|
||||
theme={this.mergedTheme.peers.Button}
|
||||
@ -367,12 +368,12 @@ export default defineComponent({
|
||||
}}
|
||||
</NButton>
|
||||
</div>
|
||||
<div class={`${mergedClsPrefix}-transfer-list`}>
|
||||
<div class={`${mergedClsPrefix}-legacy-transfer-list`}>
|
||||
<NTransferHeader
|
||||
onChange={this.handleTgtHeaderCheck}
|
||||
title={this.targetTitle || this.locale.targetTitle}
|
||||
/>
|
||||
<div class={`${mergedClsPrefix}-transfer-list-body`}>
|
||||
<div class={`${mergedClsPrefix}-legacy-transfer-list-body`}>
|
||||
{this.filterable ? (
|
||||
<NTransferFilter
|
||||
onUpdateValue={this.handleTgtFilterUpdateValue}
|
||||
@ -383,7 +384,9 @@ export default defineComponent({
|
||||
onBlur={this.handleInputBlur}
|
||||
/>
|
||||
) : null}
|
||||
<div class={`${mergedClsPrefix}-transfer-list-flex-container`}>
|
||||
<div
|
||||
class={`${mergedClsPrefix}-legacy-transfer-list-flex-container`}
|
||||
>
|
||||
<NTransferList
|
||||
options={this.filteredTgtOpts}
|
||||
disabled={this.mergedDisabled}
|
||||
@ -394,7 +397,7 @@ export default defineComponent({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class={`${mergedClsPrefix}-transfer-list__border`} />
|
||||
<div class={`${mergedClsPrefix}-legacy-transfer-list__border`} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -34,7 +34,7 @@ export default defineComponent({
|
||||
render () {
|
||||
const { mergedTheme, mergedClsPrefix } = this
|
||||
return (
|
||||
<div class={`${mergedClsPrefix}-transfer-filter`}>
|
||||
<div class={`${mergedClsPrefix}-legacy-transfer-filter`}>
|
||||
<NInput
|
||||
value={this.value}
|
||||
onUpdateValue={this.onUpdateValue}
|
||||
@ -51,7 +51,7 @@ export default defineComponent({
|
||||
'clear-icon-placeholder': () => (
|
||||
<NBaseIcon
|
||||
clsPrefix={mergedClsPrefix}
|
||||
class={`${mergedClsPrefix}-transfer-icon`}
|
||||
class={`${mergedClsPrefix}-legacy-transfer-icon`}
|
||||
>
|
||||
{{ default: () => <SearchIcon /> }}
|
||||
</NBaseIcon>
|
||||
|
@ -42,8 +42,10 @@ export default defineComponent({
|
||||
const { value: mergedTheme } = mergedThemeRef
|
||||
const { value: mergedClsPrefix } = mergedClsPrefixRef
|
||||
return (
|
||||
<div class={`${mergedClsPrefix}-transfer-list-header`}>
|
||||
<div class={`${mergedClsPrefix}-transfer-list-header__checkbox`}>
|
||||
<div class={`${mergedClsPrefix}-legacy-transfer-list-header`}>
|
||||
<div
|
||||
class={`${mergedClsPrefix}-legacy-transfer-list-header__checkbox`}
|
||||
>
|
||||
<NCheckbox
|
||||
theme={mergedTheme.peers.Checkbox}
|
||||
themeOverrides={mergedTheme.peerOverrides.Checkbox}
|
||||
@ -53,10 +55,10 @@ export default defineComponent({
|
||||
onUpdateChecked={props.onChange}
|
||||
/>
|
||||
</div>
|
||||
<div class={`${mergedClsPrefix}-transfer-list-header__header`}>
|
||||
<div class={`${mergedClsPrefix}-legacy-transfer-list-header__header`}>
|
||||
{props.title}
|
||||
</div>
|
||||
<div class={`${mergedClsPrefix}-transfer-list-header__extra`}>
|
||||
<div class={`${mergedClsPrefix}-legacy-transfer-list-header__extra`}>
|
||||
{source
|
||||
? srcCheckedValuesRef.value.length
|
||||
: tgtCheckedValuesRef.value.length}
|
||||
|
@ -93,7 +93,7 @@ export default defineComponent({
|
||||
<VirtualList
|
||||
ref="vlInstRef"
|
||||
style={{ height: '100%' }}
|
||||
class={`${mergedClsPrefix}-transfer-list-content`}
|
||||
class={`${mergedClsPrefix}-legacy-transfer-list-content`}
|
||||
items={this.options}
|
||||
itemSize={this.itemSize}
|
||||
showScrollbar={false}
|
||||
@ -117,7 +117,7 @@ export default defineComponent({
|
||||
}}
|
||||
</VirtualList>
|
||||
) : (
|
||||
<div class={`${mergedClsPrefix}-transfer-list-content`}>
|
||||
<div class={`${mergedClsPrefix}-legacy-transfer-list-content`}>
|
||||
<TransitionGroup
|
||||
name="item"
|
||||
appear={this.isMounted}
|
||||
|
@ -62,15 +62,15 @@ export default defineComponent({
|
||||
return (
|
||||
<div
|
||||
class={[
|
||||
`${mergedClsPrefix}-transfer-list-item`,
|
||||
disabled && `${mergedClsPrefix}-transfer-list-item--disabled`,
|
||||
`${mergedClsPrefix}-legacy-transfer-list-item`,
|
||||
disabled && `${mergedClsPrefix}-legacy-transfer-list-item--disabled`,
|
||||
source
|
||||
? `${mergedClsPrefix}-transfer-list-item--source`
|
||||
: `${mergedClsPrefix}-transfer-list-item--target`
|
||||
? `${mergedClsPrefix}-legacy-transfer-list-item--source`
|
||||
: `${mergedClsPrefix}-legacy-transfer-list-item--target`
|
||||
]}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
<div class={`${mergedClsPrefix}-transfer-list-item__checkbox`}>
|
||||
<div class={`${mergedClsPrefix}-legacy-transfer-list-item__checkbox`}>
|
||||
<NCheckbox
|
||||
theme={mergedTheme.peers.Checkbox}
|
||||
themeOverrides={mergedTheme.peerOverrides.Checkbox}
|
||||
@ -79,7 +79,7 @@ export default defineComponent({
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class={`${mergedClsPrefix}-transfer-list-item__label`}
|
||||
class={`${mergedClsPrefix}-legacy-transfer-list-item__label`}
|
||||
title={getTitleAttribute(label)}
|
||||
>
|
||||
{label}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Ref } from 'vue'
|
||||
import type { MergedTheme } from '../../_mixins'
|
||||
import { createInjectionKey } from '../../_utils'
|
||||
import type { TransferTheme } from '../styles'
|
||||
import type { LegacyTransferTheme } from '../styles'
|
||||
|
||||
export type OptionValue = string | number
|
||||
export interface Option {
|
||||
@ -26,7 +26,7 @@ export interface TransferInjection {
|
||||
mergedClsPrefixRef: Ref<string>
|
||||
mergedSizeRef: Ref<'small' | 'medium' | 'large'>
|
||||
disabledRef: Ref<boolean>
|
||||
mergedThemeRef: Ref<MergedTheme<TransferTheme>>
|
||||
mergedThemeRef: Ref<MergedTheme<LegacyTransferTheme>>
|
||||
srcCheckedValuesRef: Ref<OptionValue[]>
|
||||
tgtCheckedValuesRef: Ref<OptionValue[]>
|
||||
srcOptsRef: Ref<Option[]>
|
||||
|
@ -2,7 +2,7 @@ import { c, cB, cE, cM, cNotM } from '../../../_utils/cssr'
|
||||
import { fadeInTransition } from '../../../_styles/transitions/fade-in.cssr'
|
||||
|
||||
const animation = c([
|
||||
c('@keyframes transfer-slide-in-from-left', `
|
||||
c('@keyframes legacy-transfer-slide-in-from-left', `
|
||||
0% {
|
||||
transform: translateX(-150%);
|
||||
}
|
||||
@ -10,7 +10,7 @@ const animation = c([
|
||||
transform: translateX(0);
|
||||
}
|
||||
`),
|
||||
c('@keyframes transfer-slide-out-to-right', `
|
||||
c('@keyframes legacy-transfer-slide-out-to-right', `
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
@ -18,7 +18,7 @@ const animation = c([
|
||||
transform: translateX(150%);
|
||||
}
|
||||
`),
|
||||
c('@keyframes transfer-slide-in-from-right', `
|
||||
c('@keyframes legacy-transfer-slide-in-from-right', `
|
||||
0% {
|
||||
transform: translateX(150%);
|
||||
}
|
||||
@ -26,7 +26,7 @@ const animation = c([
|
||||
transform: translateX(0);
|
||||
}
|
||||
`),
|
||||
c('@keyframes transfer-slide-out-to-left', `
|
||||
c('@keyframes legacy-transfer-slide-out-to-left', `
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
@ -34,7 +34,7 @@ const animation = c([
|
||||
transform: translateX(-150%);
|
||||
}
|
||||
`),
|
||||
c('@keyframes transfer-height-collapse', `
|
||||
c('@keyframes legacy-transfer-height-collapse', `
|
||||
0% {
|
||||
max-height: var(--n-item-height);
|
||||
}
|
||||
@ -42,7 +42,7 @@ const animation = c([
|
||||
max-height: 0;
|
||||
}
|
||||
`),
|
||||
c('@keyframes transfer-height-expand', `
|
||||
c('@keyframes legacy-transfer-height-expand', `
|
||||
0% {
|
||||
max-height: 0;
|
||||
}
|
||||
@ -53,7 +53,7 @@ const animation = c([
|
||||
])
|
||||
|
||||
export default c([
|
||||
cB('transfer', `
|
||||
cB('legacy-transfer', `
|
||||
display: flex;
|
||||
width: var(--n-width);
|
||||
font-size: var(--n-font-size);
|
||||
@ -61,16 +61,16 @@ export default c([
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
`, [
|
||||
cB('transfer-icon', `
|
||||
cB('legacy-transfer-icon', `
|
||||
color: var(--n-icon-color);
|
||||
transition: color .3s var(--n-bezier);
|
||||
`),
|
||||
cM('disabled', [
|
||||
cB('transfer-icon', {
|
||||
cB('legacy-transfer-icon', {
|
||||
color: 'var(--n-icon-color-disabled)'
|
||||
})
|
||||
]),
|
||||
cB('transfer-list', `
|
||||
cB('legacy-transfer-list', `
|
||||
height: inherit;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -92,7 +92,7 @@ export default c([
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
`),
|
||||
cB('transfer-list-header', `
|
||||
cB('legacy-transfer-list-header', `
|
||||
height: calc(var(--n-item-height) + 4px);
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
@ -132,7 +132,7 @@ export default c([
|
||||
color: var(--n-header-extra-text-color);
|
||||
`)
|
||||
]),
|
||||
cB('transfer-list-body', `
|
||||
cB('legacy-transfer-list-body', `
|
||||
flex-basis: 0;
|
||||
flex-grow: 1;
|
||||
box-sizing: border-box;
|
||||
@ -143,7 +143,7 @@ export default c([
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
`, [
|
||||
cB('transfer-filter', `
|
||||
cB('legacy-transfer-filter', `
|
||||
padding: 0 8px 8px 8px;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--n-header-color);
|
||||
@ -152,7 +152,7 @@ export default c([
|
||||
background-color .3s var(--n-bezier);
|
||||
border-bottom: 1px solid var(--n-filter-divider-color);
|
||||
`),
|
||||
cB('transfer-list-flex-container', `
|
||||
cB('legacy-transfer-list-flex-container', `
|
||||
flex: 1;
|
||||
position: relative;
|
||||
`, [
|
||||
@ -176,17 +176,17 @@ export default c([
|
||||
`, [
|
||||
fadeInTransition()
|
||||
]),
|
||||
cB('transfer-list-content', `
|
||||
cB('legacy-transfer-list-content', `
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
`, [
|
||||
cM('transition-disabled', [
|
||||
cB('transfer-list-item', {
|
||||
cB('legacy-transfer-list-item', {
|
||||
animation: 'none !important'
|
||||
})
|
||||
]),
|
||||
cB('transfer-list-item', `
|
||||
cB('legacy-transfer-list-item', `
|
||||
height: var(--n-item-height);
|
||||
max-height: var(--n-item-height);
|
||||
transition:
|
||||
@ -228,14 +228,14 @@ export default c([
|
||||
animation-duration: .25s, .25s;
|
||||
animation-timing-function: var(--n-bezier), var(--n-bezier-ease-out);
|
||||
animation-delay: 0s, .25s;
|
||||
animation-name: transfer-height-expand, transfer-slide-in-from-right;
|
||||
animation-name: legacy-transfer-height-expand, legacy-transfer-slide-in-from-right;
|
||||
`),
|
||||
c('&.item-leave-active', `
|
||||
transform: translateX(-150%);
|
||||
animation-duration: .25s, .25s;
|
||||
animation-timing-function: var(--n-bezier), var(--n-bezier-ease-in);
|
||||
animation-delay: .25s, 0s;
|
||||
animation-name: transfer-height-collapse, transfer-slide-out-to-right;
|
||||
animation-name: legacy-transfer-height-collapse, legacy-transfer-slide-out-to-right;
|
||||
`)
|
||||
]),
|
||||
cM('target', {
|
||||
@ -246,14 +246,14 @@ export default c([
|
||||
animation-duration: .25s, .25s;
|
||||
animation-timing-function: var(--n-bezier), var(--n-bezier-ease-out);
|
||||
animation-delay: 0s, .25s;
|
||||
animation-name: transfer-height-expand, transfer-slide-in-from-left;
|
||||
animation-name: legacy-transfer-height-expand, legacy-transfer-slide-in-from-left;
|
||||
`),
|
||||
c('&.item-leave-active', `
|
||||
transform: translateX(150%);
|
||||
animation-duration: .25s, .25s;
|
||||
animation-timing-function: var(--n-bezier), var(--n-bezier-ease-in);
|
||||
animation-delay: .25s, 0s;
|
||||
animation-name: transfer-height-collapse, transfer-slide-out-to-left;
|
||||
animation-name: legacy-transfer-height-collapse, legacy-transfer-slide-out-to-left;
|
||||
`)
|
||||
])
|
||||
])
|
||||
@ -261,7 +261,7 @@ export default c([
|
||||
])
|
||||
])
|
||||
]),
|
||||
cB('transfer-gap', {
|
||||
cB('legacy-transfer-gap', {
|
||||
width: '72px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
|
@ -1,3 +1,6 @@
|
||||
export { default as transferDark } from './dark'
|
||||
export { default as transferLight } from './light'
|
||||
export type { TransferTheme, TransferThemeVars } from './light'
|
||||
export { default as legacyTransferDark } from './dark'
|
||||
export { default as legacyTransferLight } from './light'
|
||||
export type {
|
||||
TransferTheme as LegacyTransferTheme,
|
||||
TransferThemeVars as LegacyTransferThemeVars
|
||||
} from './light'
|
||||
|
@ -1,23 +1,23 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { sleep } from 'seemly'
|
||||
import { NTransfer } from '../index'
|
||||
import { NLegacyTransfer } from '../index'
|
||||
|
||||
describe('n-transfer', () => {
|
||||
describe('n-legacy-transfer', () => {
|
||||
it('should work with import on demand', () => {
|
||||
mount(NTransfer)
|
||||
mount(NLegacyTransfer)
|
||||
})
|
||||
|
||||
it('should work with `disabled` prop', () => {
|
||||
const wrapper = mount(NTransfer, { props: { disabled: true } })
|
||||
expect(wrapper.find('.n-transfer').attributes('class')).toContain(
|
||||
'n-transfer--disabled'
|
||||
const wrapper = mount(NLegacyTransfer, { props: { disabled: true } })
|
||||
expect(wrapper.find('.n-legacy-transfer').attributes('class')).toContain(
|
||||
'n-legacy-transfer--disabled'
|
||||
)
|
||||
})
|
||||
|
||||
it('should work with `filterable` prop', () => {
|
||||
const wrapper = mount(NTransfer, { props: { filterable: true } })
|
||||
expect(wrapper.find('.n-transfer').attributes('class')).toContain(
|
||||
'n-transfer--filterable'
|
||||
const wrapper = mount(NLegacyTransfer, { props: { filterable: true } })
|
||||
expect(wrapper.find('.n-legacy-transfer').attributes('class')).toContain(
|
||||
'n-legacy-transfer--filterable'
|
||||
)
|
||||
})
|
||||
|
||||
@ -29,7 +29,7 @@ describe('n-transfer', () => {
|
||||
}
|
||||
]
|
||||
const onFilter = jest.fn()
|
||||
const wrapper = mount(NTransfer, {
|
||||
const wrapper = mount(NLegacyTransfer, {
|
||||
props: { filterable: true, filter: onFilter, options: options }
|
||||
})
|
||||
await wrapper.find('input').setValue('1')
|
||||
@ -39,15 +39,17 @@ describe('n-transfer', () => {
|
||||
|
||||
it('should work with `size` prop', async () => {
|
||||
;(['small', 'medium', 'large'] as const).forEach((i) => {
|
||||
const wrapper = mount(NTransfer, {
|
||||
const wrapper = mount(NLegacyTransfer, {
|
||||
props: { size: i }
|
||||
})
|
||||
expect(wrapper.find('.n-transfer').attributes('style')).toMatchSnapshot()
|
||||
expect(
|
||||
wrapper.find('.n-legacy-transfer').attributes('style')
|
||||
).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
it('should work with `source-filter-placeholder`、`target-filter-placeholder` props', async () => {
|
||||
const wrapper = mount(NTransfer, {
|
||||
const wrapper = mount(NLegacyTransfer, {
|
||||
props: {
|
||||
filterable: true,
|
||||
'source-filter-placeholder': 'test-source',
|
||||
@ -63,17 +65,17 @@ describe('n-transfer', () => {
|
||||
})
|
||||
|
||||
it('should work with `source-title`、`target-title` props', async () => {
|
||||
const wrapper = mount(NTransfer, {
|
||||
const wrapper = mount(NLegacyTransfer, {
|
||||
props: {
|
||||
'source-title': 'test-source',
|
||||
'target-title': 'test-target'
|
||||
}
|
||||
})
|
||||
expect(wrapper.findAll('.n-transfer-list-header__header')[0].text()).toBe(
|
||||
'test-source'
|
||||
)
|
||||
expect(wrapper.findAll('.n-transfer-list-header__header')[1].text()).toBe(
|
||||
'test-target'
|
||||
)
|
||||
expect(
|
||||
wrapper.findAll('.n-legacy-transfer-list-header__header')[0].text()
|
||||
).toBe('test-source')
|
||||
expect(
|
||||
wrapper.findAll('.n-legacy-transfer-list-header__header')[1].text()
|
||||
).toBe('test-target')
|
||||
})
|
||||
})
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`n-transfer should work with \`size\` prop 1`] = `"--n-bezier: cubic-bezier(.4, 0, .2, 1); --n-bezier-ease-in: cubic-bezier(.4, 0, 1, 1); --n-bezier-ease-out: cubic-bezier(0, 0, .2, 1); --n-border-color: rgb(224, 224, 230); --n-border-radius: 3px; --n-extra-font-size: 12px; --n-filter-divider-color: rgb(224, 224, 230); --n-font-size: 14px; --n-header-color: rgba(250, 250, 252, 1); --n-header-extra-text-color: rgb(51, 54, 57); --n-header-font-weight: 400; --n-header-text-color: rgb(31, 34, 37); --n-header-text-color-disabled: rgba(194, 194, 194, 1); --n-item-color-pending: rgb(243, 243, 245); --n-item-height: 28px; --n-item-text-color: rgb(51, 54, 57); --n-item-text-color-disabled: rgba(194, 194, 194, 1); --n-list-color: #fff; --n-width: 440px; --n-icon-color: rgba(194, 194, 194, 1); --n-icon-color-disabled: rgba(209, 209, 209, 1);"`;
|
||||
exports[`n-legacy-transfer should work with \`size\` prop 1`] = `"--n-bezier: cubic-bezier(.4, 0, .2, 1); --n-bezier-ease-in: cubic-bezier(.4, 0, 1, 1); --n-bezier-ease-out: cubic-bezier(0, 0, .2, 1); --n-border-color: rgb(224, 224, 230); --n-border-radius: 3px; --n-extra-font-size: 12px; --n-filter-divider-color: rgb(224, 224, 230); --n-font-size: 14px; --n-header-color: rgba(250, 250, 252, 1); --n-header-extra-text-color: rgb(51, 54, 57); --n-header-font-weight: 400; --n-header-text-color: rgb(31, 34, 37); --n-header-text-color-disabled: rgba(194, 194, 194, 1); --n-item-color-pending: rgb(243, 243, 245); --n-item-height: 28px; --n-item-text-color: rgb(51, 54, 57); --n-item-text-color-disabled: rgba(194, 194, 194, 1); --n-list-color: #fff; --n-width: 440px; --n-icon-color: rgba(194, 194, 194, 1); --n-icon-color-disabled: rgba(209, 209, 209, 1);"`;
|
||||
|
||||
exports[`n-transfer should work with \`size\` prop 2`] = `"--n-bezier: cubic-bezier(.4, 0, .2, 1); --n-bezier-ease-in: cubic-bezier(.4, 0, 1, 1); --n-bezier-ease-out: cubic-bezier(0, 0, .2, 1); --n-border-color: rgb(224, 224, 230); --n-border-radius: 3px; --n-extra-font-size: 12px; --n-filter-divider-color: rgb(224, 224, 230); --n-font-size: 14px; --n-header-color: rgba(250, 250, 252, 1); --n-header-extra-text-color: rgb(51, 54, 57); --n-header-font-weight: 400; --n-header-text-color: rgb(31, 34, 37); --n-header-text-color-disabled: rgba(194, 194, 194, 1); --n-item-color-pending: rgb(243, 243, 245); --n-item-height: 34px; --n-item-text-color: rgb(51, 54, 57); --n-item-text-color-disabled: rgba(194, 194, 194, 1); --n-list-color: #fff; --n-width: 440px; --n-icon-color: rgba(194, 194, 194, 1); --n-icon-color-disabled: rgba(209, 209, 209, 1);"`;
|
||||
exports[`n-legacy-transfer should work with \`size\` prop 2`] = `"--n-bezier: cubic-bezier(.4, 0, .2, 1); --n-bezier-ease-in: cubic-bezier(.4, 0, 1, 1); --n-bezier-ease-out: cubic-bezier(0, 0, .2, 1); --n-border-color: rgb(224, 224, 230); --n-border-radius: 3px; --n-extra-font-size: 12px; --n-filter-divider-color: rgb(224, 224, 230); --n-font-size: 14px; --n-header-color: rgba(250, 250, 252, 1); --n-header-extra-text-color: rgb(51, 54, 57); --n-header-font-weight: 400; --n-header-text-color: rgb(31, 34, 37); --n-header-text-color-disabled: rgba(194, 194, 194, 1); --n-item-color-pending: rgb(243, 243, 245); --n-item-height: 34px; --n-item-text-color: rgb(51, 54, 57); --n-item-text-color-disabled: rgba(194, 194, 194, 1); --n-list-color: #fff; --n-width: 440px; --n-icon-color: rgba(194, 194, 194, 1); --n-icon-color-disabled: rgba(209, 209, 209, 1);"`;
|
||||
|
||||
exports[`n-transfer should work with \`size\` prop 3`] = `"--n-bezier: cubic-bezier(.4, 0, .2, 1); --n-bezier-ease-in: cubic-bezier(.4, 0, 1, 1); --n-bezier-ease-out: cubic-bezier(0, 0, .2, 1); --n-border-color: rgb(224, 224, 230); --n-border-radius: 3px; --n-extra-font-size: 12px; --n-filter-divider-color: rgb(224, 224, 230); --n-font-size: 15px; --n-header-color: rgba(250, 250, 252, 1); --n-header-extra-text-color: rgb(51, 54, 57); --n-header-font-weight: 400; --n-header-text-color: rgb(31, 34, 37); --n-header-text-color-disabled: rgba(194, 194, 194, 1); --n-item-color-pending: rgb(243, 243, 245); --n-item-height: 40px; --n-item-text-color: rgb(51, 54, 57); --n-item-text-color-disabled: rgba(194, 194, 194, 1); --n-list-color: #fff; --n-width: 440px; --n-icon-color: rgba(194, 194, 194, 1); --n-icon-color-disabled: rgba(209, 209, 209, 1);"`;
|
||||
exports[`n-legacy-transfer should work with \`size\` prop 3`] = `"--n-bezier: cubic-bezier(.4, 0, .2, 1); --n-bezier-ease-in: cubic-bezier(.4, 0, 1, 1); --n-bezier-ease-out: cubic-bezier(0, 0, .2, 1); --n-border-color: rgb(224, 224, 230); --n-border-radius: 3px; --n-extra-font-size: 12px; --n-filter-divider-color: rgb(224, 224, 230); --n-font-size: 15px; --n-header-color: rgba(250, 250, 252, 1); --n-header-extra-text-color: rgb(51, 54, 57); --n-header-font-weight: 400; --n-header-text-color: rgb(31, 34, 37); --n-header-text-color-disabled: rgba(194, 194, 194, 1); --n-item-color-pending: rgb(243, 243, 245); --n-item-height: 40px; --n-item-text-color: rgb(51, 54, 57); --n-item-text-color-disabled: rgba(194, 194, 194, 1); --n-list-color: #fff; --n-width: 440px; --n-icon-color: rgba(194, 194, 194, 1); --n-icon-color-disabled: rgba(209, 209, 209, 1);"`;
|
||||
|
@ -57,9 +57,17 @@ const deDE: NLocale = {
|
||||
confirm: 'Bestätigen',
|
||||
clear: 'Löschen'
|
||||
},
|
||||
LegacyTransfer: {
|
||||
sourceTitle: 'Quelle',
|
||||
targetTitle: 'Ziel'
|
||||
},
|
||||
// TODO: translation
|
||||
Transfer: {
|
||||
selectAll: 'Select all',
|
||||
unselectAll: 'Unselect all',
|
||||
clearAll: 'Clear',
|
||||
total: (num: number): string => `Total ${num} items`,
|
||||
selectedTotal: (num: number): string => `Selected ${num} items`
|
||||
selected: (num: number): string => `${num} items selected`
|
||||
},
|
||||
Empty: {
|
||||
description: 'Keine Daten'
|
||||
|
@ -56,9 +56,16 @@ const enGB: NLocale = {
|
||||
confirm: 'Confirm',
|
||||
clear: 'Clear'
|
||||
},
|
||||
LegacyTransfer: {
|
||||
sourceTitle: 'Source',
|
||||
targetTitle: 'Target'
|
||||
},
|
||||
Transfer: {
|
||||
selectAll: 'Select all',
|
||||
unselectAll: 'Unselect all',
|
||||
clearAll: 'Clear',
|
||||
total: (num: number): string => `Total ${num} items`,
|
||||
selectedTotal: (num: number): string => `Selected ${num} items`
|
||||
selected: (num: number): string => `${num} items selected`
|
||||
},
|
||||
Empty: {
|
||||
description: 'No Data'
|
||||
|
@ -54,9 +54,16 @@ const enUS = {
|
||||
confirm: 'Confirm',
|
||||
clear: 'Clear'
|
||||
},
|
||||
LegacyTransfer: {
|
||||
sourceTitle: 'Source',
|
||||
targetTitle: 'Target'
|
||||
},
|
||||
Transfer: {
|
||||
selectAll: 'Select all',
|
||||
unselectAll: 'Unselect all',
|
||||
clearAll: 'Clear',
|
||||
total: (num: number): string => `Total ${num} items`,
|
||||
selectedTotal: (num: number): string => `Selected ${num} items`
|
||||
selected: (num: number): string => `${num} items selected`
|
||||
},
|
||||
Empty: {
|
||||
description: 'No Data'
|
||||
|
@ -57,9 +57,17 @@ const eo: NLocale = {
|
||||
confirm: 'Konfirmi',
|
||||
clear: 'Malplenigi'
|
||||
},
|
||||
LegacyTransfer: {
|
||||
sourceTitle: 'Source',
|
||||
targetTitle: 'Target'
|
||||
},
|
||||
// TODO: translation
|
||||
Transfer: {
|
||||
selectAll: 'Select all',
|
||||
unselectAll: 'Unselect all',
|
||||
clearAll: 'Clear',
|
||||
total: (num: number): string => `Total ${num} items`,
|
||||
selectedTotal: (num: number): string => `Selected ${num} items`
|
||||
selected: (num: number): string => `${num} items selected`
|
||||
},
|
||||
Empty: {
|
||||
description: 'Neniu datumo'
|
||||
|
@ -58,9 +58,17 @@ const esAR: NLocale = {
|
||||
confirm: 'Confirmar',
|
||||
clear: 'Limpiar'
|
||||
},
|
||||
LegacyTransfer: {
|
||||
sourceTitle: 'Fuente',
|
||||
targetTitle: 'Objetivo'
|
||||
},
|
||||
// TODO: translation
|
||||
Transfer: {
|
||||
selectAll: 'Select all',
|
||||
unselectAll: 'Unselect all',
|
||||
clearAll: 'Clear',
|
||||
total: (num: number): string => `Total ${num} items`,
|
||||
selectedTotal: (num: number): string => `Selected ${num} items`
|
||||
selected: (num: number): string => `${num} items selected`
|
||||
},
|
||||
Empty: {
|
||||
description: 'Sin datos'
|
||||
|
@ -57,9 +57,17 @@ const frFR: NLocale = {
|
||||
confirm: 'Confirmer',
|
||||
clear: 'Effacer'
|
||||
},
|
||||
LegacyTransfer: {
|
||||
sourceTitle: 'Source',
|
||||
targetTitle: 'Cible'
|
||||
},
|
||||
// TODO: translation
|
||||
Transfer: {
|
||||
selectAll: 'Select all',
|
||||
unselectAll: 'Unselect all',
|
||||
clearAll: 'Clear',
|
||||
total: (num: number): string => `Total ${num} items`,
|
||||
selectedTotal: (num: number): string => `Selected ${num} items`
|
||||
selected: (num: number): string => `${num} items selected`
|
||||
},
|
||||
Empty: {
|
||||
description: 'Aucune donnée'
|
||||
|
@ -58,9 +58,17 @@ const idID: NLocale = {
|
||||
confirm: 'Setuju',
|
||||
clear: 'Bersihkan'
|
||||
},
|
||||
LegacyTransfer: {
|
||||
sourceTitle: 'Sumber',
|
||||
targetTitle: 'Tujuan'
|
||||
},
|
||||
// TODO: translation
|
||||
Transfer: {
|
||||
selectAll: 'Select all',
|
||||
unselectAll: 'Unselect all',
|
||||
clearAll: 'Clear',
|
||||
total: (num: number): string => `Total ${num} items`,
|
||||
selectedTotal: (num: number): string => `Selected ${num} items`
|
||||
selected: (num: number): string => `${num} items selected`
|
||||
},
|
||||
Empty: {
|
||||
description: 'Tidak ada data'
|
||||
|
@ -57,9 +57,17 @@ const itIT: NLocale = {
|
||||
confirm: 'Conferma',
|
||||
clear: 'Cancella'
|
||||
},
|
||||
LegacyTransfer: {
|
||||
sourceTitle: 'Fonte',
|
||||
targetTitle: 'Destinazione'
|
||||
},
|
||||
// TODO: translation
|
||||
Transfer: {
|
||||
selectAll: 'Select all',
|
||||
unselectAll: 'Unselect all',
|
||||
clearAll: 'Clear',
|
||||
total: (num: number): string => `Total ${num} items`,
|
||||
selectedTotal: (num: number): string => `Selected ${num} items`
|
||||
selected: (num: number): string => `${num} items selected`
|
||||
},
|
||||
Empty: {
|
||||
description: 'Nessun Dato'
|
||||
|
@ -57,9 +57,17 @@ const jaJP: NLocale = {
|
||||
confirm: 'OK',
|
||||
clear: 'リセット'
|
||||
},
|
||||
LegacyTransfer: {
|
||||
sourceTitle: '元',
|
||||
targetTitle: '先'
|
||||
},
|
||||
// TODO: translation
|
||||
Transfer: {
|
||||
selectAll: 'Select all',
|
||||
unselectAll: 'Unselect all',
|
||||
clearAll: 'Clear',
|
||||
total: (num: number): string => `Total ${num} items`,
|
||||
selectedTotal: (num: number): string => `Selected ${num} items`
|
||||
selected: (num: number): string => `${num} items selected`
|
||||
},
|
||||
Empty: {
|
||||
description: 'データなし'
|
||||
|
@ -57,10 +57,18 @@ const koKR: NLocale = {
|
||||
confirm: '확인',
|
||||
clear: '지우기'
|
||||
},
|
||||
Transfer: {
|
||||
LegacyTransfer: {
|
||||
sourceTitle: '원본',
|
||||
targetTitle: '타깃'
|
||||
},
|
||||
// TODO: translation
|
||||
Transfer: {
|
||||
selectAll: 'Select all',
|
||||
unselectAll: 'Unselect all',
|
||||
clearAll: 'Clear',
|
||||
total: (num: number): string => `Total ${num} items`,
|
||||
selected: (num: number): string => `${num} items selected`
|
||||
},
|
||||
Empty: {
|
||||
description: '데이터 없음'
|
||||
},
|
||||
|
@ -58,9 +58,17 @@ const nbNO: NLocale = {
|
||||
confirm: 'Bekreft',
|
||||
clear: 'Tøm'
|
||||
},
|
||||
LegacyTransfer: {
|
||||
sourceTitle: 'Kilde',
|
||||
targetTitle: 'Mål'
|
||||
},
|
||||
// TODO: translation
|
||||
Transfer: {
|
||||
selectAll: 'Select all',
|
||||
unselectAll: 'Unselect all',
|
||||
clearAll: 'Clear',
|
||||
total: (num: number): string => `Total ${num} items`,
|
||||
selectedTotal: (num: number): string => `Selected ${num} items`
|
||||
selected: (num: number): string => `${num} items selected`
|
||||
},
|
||||
Empty: {
|
||||
description: 'Ingen data'
|
||||
|
@ -56,10 +56,18 @@ const nlNL: NLocale = {
|
||||
confirm: 'Bevestig',
|
||||
clear: 'Wis'
|
||||
},
|
||||
Transfer: {
|
||||
LegacyTransfer: {
|
||||
sourceTitle: 'Bron',
|
||||
targetTitle: 'Doel'
|
||||
},
|
||||
// TODO: translation
|
||||
Transfer: {
|
||||
selectAll: 'Select all',
|
||||
unselectAll: 'Unselect all',
|
||||
clearAll: 'Clear',
|
||||
total: (num: number): string => `Total ${num} items`,
|
||||
selected: (num: number): string => `${num} items selected`
|
||||
},
|
||||
Empty: {
|
||||
description: 'Geen Data'
|
||||
},
|
||||
|
@ -57,9 +57,17 @@ const plPL: NLocale = {
|
||||
confirm: 'Potwierdź',
|
||||
clear: 'Wyczyść'
|
||||
},
|
||||
LegacyTransfer: {
|
||||
sourceTitle: 'Źródło',
|
||||
targetTitle: 'Cel'
|
||||
},
|
||||
// TODO: translation
|
||||
Transfer: {
|
||||
selectAll: 'Select all',
|
||||
unselectAll: 'Unselect all',
|
||||
clearAll: 'Clear',
|
||||
total: (num: number): string => `Total ${num} items`,
|
||||
selectedTotal: (num: number): string => `Selected ${num} items`
|
||||
selected: (num: number): string => `${num} items selected`
|
||||
},
|
||||
Empty: {
|
||||
description: 'Brak danych'
|
||||
|
@ -57,10 +57,18 @@ const ptBR: NLocale = {
|
||||
confirm: 'Confirmar',
|
||||
clear: 'Limpar'
|
||||
},
|
||||
Transfer: {
|
||||
LegacyTransfer: {
|
||||
sourceTitle: 'Fonte',
|
||||
targetTitle: 'Destino'
|
||||
},
|
||||
// TODO: translation
|
||||
Transfer: {
|
||||
selectAll: 'Select all',
|
||||
unselectAll: 'Unselect all',
|
||||
clearAll: 'Clear',
|
||||
total: (num: number): string => `Total ${num} items`,
|
||||
selected: (num: number): string => `${num} items selected`
|
||||
},
|
||||
Empty: {
|
||||
description: 'Não há dados'
|
||||
},
|
||||
|
@ -58,9 +58,17 @@ const ruRu: NLocale = {
|
||||
confirm: 'Подтвердить',
|
||||
clear: 'Очистить'
|
||||
},
|
||||
LegacyTransfer: {
|
||||
sourceTitle: 'Источник',
|
||||
targetTitle: 'Назначение'
|
||||
},
|
||||
// TODO: translation
|
||||
Transfer: {
|
||||
selectAll: 'Select all',
|
||||
unselectAll: 'Unselect all',
|
||||
clearAll: 'Clear',
|
||||
total: (num: number): string => `Total ${num} items`,
|
||||
selectedTotal: (num: number): string => `Selected ${num} items`
|
||||
selected: (num: number): string => `${num} items selected`
|
||||
},
|
||||
Empty: {
|
||||
description: 'Нет данных'
|
||||
|
@ -57,9 +57,17 @@ const skSK: NLocale = {
|
||||
confirm: 'Potvrdiť',
|
||||
clear: 'Vyčistiť'
|
||||
},
|
||||
LegacyTransfer: {
|
||||
sourceTitle: 'Zdroj',
|
||||
targetTitle: 'Cieľ'
|
||||
},
|
||||
// TODO: translation
|
||||
Transfer: {
|
||||
selectAll: 'Select all',
|
||||
unselectAll: 'Unselect all',
|
||||
clearAll: 'Clear',
|
||||
total: (num: number): string => `Total ${num} items`,
|
||||
selectedTotal: (num: number): string => `Selected ${num} items`
|
||||
selected: (num: number): string => `${num} items selected`
|
||||
},
|
||||
Empty: {
|
||||
description: 'Žiadne dáta'
|
||||
|
@ -57,10 +57,18 @@ const thTH: NLocale = {
|
||||
confirm: 'ยืนยัน',
|
||||
clear: 'ล้างข้อมูล'
|
||||
},
|
||||
Transfer: {
|
||||
LegacyTransfer: {
|
||||
sourceTitle: 'Source',
|
||||
targetTitle: 'Target'
|
||||
},
|
||||
// TODO: translation
|
||||
Transfer: {
|
||||
selectAll: 'Select all',
|
||||
unselectAll: 'Unselect all',
|
||||
clearAll: 'Clear',
|
||||
total: (num: number): string => `Total ${num} items`,
|
||||
selected: (num: number): string => `${num} items selected`
|
||||
},
|
||||
Empty: {
|
||||
description: 'ไม่มีข้อมูล'
|
||||
},
|
||||
|
@ -56,9 +56,17 @@ const ukUA: NLocale = {
|
||||
confirm: 'Підтвердити',
|
||||
clear: 'Стерти'
|
||||
},
|
||||
LegacyTransfer: {
|
||||
sourceTitle: 'Джерело',
|
||||
targetTitle: 'Ціль'
|
||||
},
|
||||
// TODO: translation
|
||||
Transfer: {
|
||||
selectAll: 'Select all',
|
||||
unselectAll: 'Unselect all',
|
||||
clearAll: 'Clear',
|
||||
total: (num: number): string => `Total ${num} items`,
|
||||
selectedTotal: (num: number): string => `Selected ${num} items`
|
||||
selected: (num: number): string => `${num} items selected`
|
||||
},
|
||||
Empty: {
|
||||
description: 'Немає даних'
|
||||
|
@ -56,10 +56,18 @@ const viVN: NLocale = {
|
||||
confirm: 'Xác nhận',
|
||||
clear: 'Xóa'
|
||||
},
|
||||
Transfer: {
|
||||
LegacyTransfer: {
|
||||
sourceTitle: 'Nguồn',
|
||||
targetTitle: 'Đích'
|
||||
},
|
||||
// TODO: translation
|
||||
Transfer: {
|
||||
selectAll: 'Select all',
|
||||
unselectAll: 'Unselect all',
|
||||
clearAll: 'Clear',
|
||||
total: (num: number): string => `Total ${num} items`,
|
||||
selected: (num: number): string => `${num} items selected`
|
||||
},
|
||||
Empty: {
|
||||
description: 'Không có dữ liệu'
|
||||
},
|
||||
|
@ -56,9 +56,16 @@ const zhCN: NLocale = {
|
||||
confirm: '确认',
|
||||
clear: '重置'
|
||||
},
|
||||
LegacyTransfer: {
|
||||
sourceTitle: '源项',
|
||||
targetTitle: '目标项'
|
||||
},
|
||||
Transfer: {
|
||||
selectAll: '全选',
|
||||
clearAll: '清除',
|
||||
unselectAll: '取消全选',
|
||||
total: (num: number): string => `共 ${num} 项`,
|
||||
selectedTotal: (num: number): string => `已选 ${num} 项`
|
||||
selected: (num: number): string => `已选 ${num} 项`
|
||||
},
|
||||
Empty: {
|
||||
description: '无数据'
|
||||
|
@ -56,9 +56,17 @@ const zhTW: NLocale = {
|
||||
confirm: '確認',
|
||||
clear: '重置'
|
||||
},
|
||||
LegacyTransfer: {
|
||||
sourceTitle: '源項',
|
||||
targetTitle: '目標項'
|
||||
},
|
||||
Transfer: {
|
||||
// TODO: translation
|
||||
selectAll: '全选',
|
||||
unselectAll: '取消全选',
|
||||
clearAll: '清除',
|
||||
total: (num: number): string => `共 ${num} 項`,
|
||||
selectedTotal: (num: number): string => `已選 ${num} 項`
|
||||
selected: (num: number): string => `已選 ${num} 項`
|
||||
},
|
||||
Empty: {
|
||||
description: '無數據'
|
||||
|
@ -38,6 +38,7 @@ import { imageDark } from '../image/styles'
|
||||
import { inputDark } from '../input/styles'
|
||||
import { inputNumberDark } from '../input-number/styles'
|
||||
import { layoutDark } from '../layout/styles'
|
||||
import { legacyTransferDark } from '../legacy-transfer/styles'
|
||||
import { listDark } from '../list/styles'
|
||||
import { loadingBarDark } from '../loading-bar/styles'
|
||||
import { logDark } from '../log/styles'
|
||||
@ -120,6 +121,7 @@ export const darkTheme: BuiltInGlobalTheme = {
|
||||
Image: imageDark,
|
||||
Input: inputDark,
|
||||
InputNumber: inputNumberDark,
|
||||
LegacyTransfer: legacyTransferDark,
|
||||
Layout: layoutDark,
|
||||
List: listDark,
|
||||
LoadingBar: loadingBarDark,
|
||||
|
@ -40,6 +40,7 @@ import { imageLight } from '../image/styles'
|
||||
import { inputLight } from '../input/styles'
|
||||
import { inputNumberLight } from '../input-number/styles'
|
||||
import { layoutLight } from '../layout/styles'
|
||||
import { legacyTransferLight } from '../legacy-transfer/styles'
|
||||
import { listLight } from '../list/styles'
|
||||
import { loadingBarLight } from '../loading-bar/styles'
|
||||
import { logLight } from '../log/styles'
|
||||
@ -123,6 +124,7 @@ export const lightTheme: BuiltInGlobalTheme = {
|
||||
Input: inputLight,
|
||||
InputNumber: inputNumberLight,
|
||||
Layout: layoutLight,
|
||||
LegacyTransfer: legacyTransferLight,
|
||||
List: listLight,
|
||||
LoadingBar: loadingBarLight,
|
||||
Log: logLight,
|
||||
|
@ -1,7 +1,7 @@
|
||||
<markdown>
|
||||
# Basic
|
||||
|
||||
Basic example of the Transfer component. If you have tons of data, see below for virtualised lists.
|
||||
Basic example of the Transfer component. If you have tons of data, see below for virtualized list.
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
@ -19,15 +19,11 @@ function createOptions () {
|
||||
}))
|
||||
}
|
||||
|
||||
function createValues () {
|
||||
return Array.from({ length: 50 }).map((v, i) => i)
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
options: createOptions(),
|
||||
value: ref(createValues())
|
||||
value: ref([])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -1,43 +1,41 @@
|
||||
# Transfer
|
||||
|
||||
<!--single-column-->
|
||||
A more efficient transfer.
|
||||
|
||||
~~Left, right, right, left... I'm a simple man, and I can play this all day.~~
|
||||
|
||||
Now, the transfer's style is simple and efficient. I can't continue to play.
|
||||
If you want to use original transfer, please refer to [Legacy Transfer](legacy-transfer). Please note that the legacy transfer will be removed in the next major version. It's not recommended to to use it.
|
||||
|
||||
## Demos
|
||||
|
||||
```demo
|
||||
basic.vue
|
||||
large-data.vue
|
||||
size.vue
|
||||
filterable.vue
|
||||
render-label
|
||||
render-source-list
|
||||
render-label.vue
|
||||
render-source-list.vue
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Transfer Props
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| default-value | `Array<string \| number> \| null` | `null` | Default value. |
|
||||
| disabled | `boolean` | `true` | Disabled state. |
|
||||
| filterable | `boolean` | `false` | Filterable state. |
|
||||
| filter | `function` | `(pattern: string, option: TransferOption, from: 'source' \| 'target') => boolean` | A basic label string match function. |
|
||||
| options | `Array<TransferOption>` | `[]` | For configuration options, see the TransferOption Type below. |
|
||||
| render-label | `({ from, option }: { from: 'source' \| 'target', option: TransferOption }) => VNodeChild` | `undefined` | Customize label rendering. |
|
||||
| render-source-list | `({ onCheck, checkedOptions, pattern }: { onCheck: (checkedValueList: Array<OptionValue>) => void, checkedOptions: Array<Option>, pattern: string }) => VNodeChild` | `undefined` | Customize source list rendering. |
|
||||
| size | `'small' \| 'medium' \| 'large'` | `'medium'` | Size. |
|
||||
| source-filter-placeholder | `string` | `undefined` | Placeholder for the source items search box. |
|
||||
| source-title | `string` | `'Source'` | Source items title. |
|
||||
| target-filter-placeholder | `string` | `undefined` | Placeholder for the target items search box. |
|
||||
| target-title | `string` | `'Target'` | Target items title. |
|
||||
| value | `Array<string \| number> \| null` | `undefined` | Value when being set manually. |
|
||||
| on-update:value | `(value: Array<string \| number>) => void` | `undefined` | Callback when the value changes. |
|
||||
| virtual-scroll | `boolean` | `false` | Enable virtual scrolling. |
|
||||
| Name | Type | Default | Description | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| default-value | `Array<string \| number> \| null` | `null` | Default value. | |
|
||||
| disabled | `boolean` | `true` | Disabled state. | |
|
||||
| filterable | `boolean` | `false` | Filterable state. | |
|
||||
| filter | `(pattern: string, option: TransferOption) => boolean` | A basic label string match function. | |
|
||||
| options | `TransferOption[]` | `[]` | For configuration options, see the TransferOption Type below. | |
|
||||
| render-source-label | `(props: { option: TransferOption }) => VNodeChild` | `undefined` | Customize source label rendering. | NEXT_VERSION |
|
||||
| render-target-label | `(props: { option: TransferOption }) => VNodeChild` | `undefined` | Customize target label rendering. | NEXT_VERSION |
|
||||
| render-source-list | `(props: { onCheck: (checkedValueList: Array<string \| number>) => void, checkedOptions: TransferOption[], pattern: string }) => VNodeChild` | `undefined` | Customize source list rendering. | NEXT_VERSION |
|
||||
| size | `'small' \| 'medium' \| 'large'` | `'medium'` | Size. | |
|
||||
| source-filter-placeholder | `string` | `undefined` | Placeholder for the source items search box. | |
|
||||
| source-title | `string` | `'Source'` | Source items title. | |
|
||||
| target-filter-placeholder | `string` | `undefined` | Placeholder for the target items search box. | |
|
||||
| target-title | `string` | `'Target'` | Target items title. | |
|
||||
| value | `Array<string \| number> \| null` | `undefined` | Value when being set manually. | |
|
||||
| on-update:value | `(value: Array<string \| number>) => void` | `undefined` | Callback when the value changes. | |
|
||||
| virtual-scroll | `boolean` | `false` | Enable virtual scrolling. | |
|
||||
|
||||
#### TransferOption Type
|
||||
|
||||
|
@ -1,9 +1,5 @@
|
||||
<markdown>
|
||||
# Large Data
|
||||
|
||||
~~If you have tons of data, you may need to speed the transfer up! Set virtual-scroll on transfer to use a blazing fast transfer (which turns the ridiculous animation off).~~
|
||||
|
||||
Now we don't have to worry about the grinding animation.
|
||||
# Large data
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
|
@ -1,84 +0,0 @@
|
||||
# Customize label rendering
|
||||
|
||||
It can be changed into address book, menu, etc. there are many application scenarios.
|
||||
|
||||
```html
|
||||
<n-transfer
|
||||
ref="transfer"
|
||||
v-model:value="value"
|
||||
:options="options"
|
||||
:renderLabel="renderLabel"
|
||||
/>
|
||||
```
|
||||
|
||||
```js
|
||||
import { defineComponent, ref, h } from 'vue'
|
||||
import { NAvatar } from 'naive-ui'
|
||||
|
||||
const options = [
|
||||
{
|
||||
label: '07akioni',
|
||||
value: 'https://avatars.githubusercontent.com/u/18677354?s=60&v=4'
|
||||
},
|
||||
{
|
||||
label: 'amadeus711',
|
||||
value: 'https://avatars.githubusercontent.com/u/46394163?s=60&v=4'
|
||||
},
|
||||
{
|
||||
label: 'Talljack',
|
||||
value: 'https://avatars.githubusercontent.com/u/34439652?s=60&v=4'
|
||||
},
|
||||
{
|
||||
label: 'JiwenBai',
|
||||
value: 'https://avatars.githubusercontent.com/u/43430022?s=60&v=4'
|
||||
},
|
||||
{
|
||||
label: 'songjianet',
|
||||
value: 'https://avatars.githubusercontent.com/u/19239641?s=60&v=4'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
options,
|
||||
value: ref([options[0].value]),
|
||||
renderLabel: function ({ from, option }) {
|
||||
return h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
display: 'flex',
|
||||
margin: from === 'source' ? undefined : '5px 0'
|
||||
}
|
||||
},
|
||||
{
|
||||
default: () => [
|
||||
from === 'source'
|
||||
? undefined
|
||||
: h(NAvatar, {
|
||||
round: true,
|
||||
src: option.value,
|
||||
size: 'small',
|
||||
fallbackSrc:
|
||||
'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg'
|
||||
}),
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
display: 'flex',
|
||||
marginLeft: from === 'source' ? undefined : '5px',
|
||||
alignSelf: 'center'
|
||||
}
|
||||
},
|
||||
{ default: () => option.label }
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
85
src/transfer/demos/enUS/render-label.demo.vue
Normal file
85
src/transfer/demos/enUS/render-label.demo.vue
Normal file
@ -0,0 +1,85 @@
|
||||
<markdown>
|
||||
# Custom label
|
||||
|
||||
Transfer can be applied for many scenarios.
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-transfer
|
||||
ref="transfer"
|
||||
v-model:value="value"
|
||||
:options="options"
|
||||
:render-target-label="renderLabel"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, h } from 'vue'
|
||||
import { NAvatar, TransferRenderTargetLabel } from 'naive-ui'
|
||||
|
||||
const options = [
|
||||
{
|
||||
label: '07akioni',
|
||||
value: 'https://avatars.githubusercontent.com/u/18677354?s=60&v=4'
|
||||
},
|
||||
{
|
||||
label: 'amadeus711',
|
||||
value: 'https://avatars.githubusercontent.com/u/46394163?s=60&v=4'
|
||||
},
|
||||
{
|
||||
label: 'Talljack',
|
||||
value: 'https://avatars.githubusercontent.com/u/34439652?s=60&v=4'
|
||||
},
|
||||
{
|
||||
label: 'JiwenBai',
|
||||
value: 'https://avatars.githubusercontent.com/u/43430022?s=60&v=4'
|
||||
},
|
||||
{
|
||||
label: 'songjianet',
|
||||
value: 'https://avatars.githubusercontent.com/u/19239641?s=60&v=4'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
const renderLabel: TransferRenderTargetLabel = function ({ option }) {
|
||||
return h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
display: 'flex',
|
||||
margin: '6px 0'
|
||||
}
|
||||
},
|
||||
{
|
||||
default: () => [
|
||||
h(NAvatar, {
|
||||
round: true,
|
||||
src: option.value as string,
|
||||
size: 'small',
|
||||
fallbackSrc:
|
||||
'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg'
|
||||
}),
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
display: 'flex',
|
||||
marginLeft: '6px',
|
||||
alignSelf: 'center'
|
||||
}
|
||||
},
|
||||
{ default: () => option.label }
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
return {
|
||||
options,
|
||||
value: ref([options[0].value]),
|
||||
renderLabel
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
@ -1,70 +0,0 @@
|
||||
# Customize source list rendering
|
||||
|
||||
```html
|
||||
<n-transfer
|
||||
ref="transfer"
|
||||
v-model:value="value"
|
||||
:options="options"
|
||||
:renderSourceList="renderSourceList"
|
||||
filterable
|
||||
/>
|
||||
```
|
||||
|
||||
```js
|
||||
import { defineComponent, ref, h } from 'vue'
|
||||
import { repeat } from 'seemly'
|
||||
import { NTree } from 'naive-ui'
|
||||
|
||||
function createLabel (level) {
|
||||
if (level === 4) return 'Out of Tao, One is born'
|
||||
if (level === 3) return 'Out of One, Two'
|
||||
if (level === 2) return 'Out of Two, Three'
|
||||
if (level === 1) return 'Out of Three, the created universe'
|
||||
return ''
|
||||
}
|
||||
|
||||
function createData (level = 4, baseKey = '') {
|
||||
if (!level) return undefined
|
||||
return repeat(6 - level, undefined).map((_, index) => {
|
||||
const value = '' + baseKey + level + index
|
||||
return {
|
||||
label: createLabel(level),
|
||||
value,
|
||||
children: createData(level - 1, value)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function flattenTree (list) {
|
||||
const result = []
|
||||
function flatten (_list = []) {
|
||||
_list.forEach((item) => {
|
||||
result.push(item)
|
||||
flatten(item.children)
|
||||
})
|
||||
}
|
||||
flatten(list)
|
||||
return result
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
options: flattenTree(createData()),
|
||||
value: ref([]),
|
||||
renderSourceList: function ({ onCheck, checkedOptions, pattern }) {
|
||||
return h(NTree, {
|
||||
keyField: 'value',
|
||||
checkable: true,
|
||||
data: createData(),
|
||||
pattern,
|
||||
checkedKeys: checkedOptions.map((i) => i.value),
|
||||
onUpdateCheckedKeys: function (_, option) {
|
||||
onCheck(option.map((i) => i.value))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
84
src/transfer/demos/enUS/render-source-list.demo.vue
Normal file
84
src/transfer/demos/enUS/render-source-list.demo.vue
Normal file
@ -0,0 +1,84 @@
|
||||
<markdown>
|
||||
# Custom source list
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-transfer
|
||||
ref="transfer"
|
||||
v-model:value="value"
|
||||
:options="options"
|
||||
:render-source-list="renderSourceList"
|
||||
filterable
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, h } from 'vue'
|
||||
import { repeat } from 'seemly'
|
||||
import { NTree, TransferRenderSourceList } from 'naive-ui'
|
||||
|
||||
function createLabel (level: number): string {
|
||||
if (level === 4) return 'Foo'
|
||||
if (level === 3) return 'Bar'
|
||||
if (level === 2) return 'Baz'
|
||||
if (level === 1) return '???'
|
||||
return ''
|
||||
}
|
||||
|
||||
type Option = {
|
||||
label: string
|
||||
value: string
|
||||
children?: Option[]
|
||||
}
|
||||
|
||||
function createData (level = 4, baseKey = ''): Option[] | undefined {
|
||||
if (!level) return undefined
|
||||
return repeat(6 - level, undefined).map((_, index) => {
|
||||
const value = '' + baseKey + level + index
|
||||
return {
|
||||
label: createLabel(level),
|
||||
value,
|
||||
children: createData(level - 1, value)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function flattenTree (list: undefined | Option[]): Option[] {
|
||||
const result: Option[] = []
|
||||
function flatten (_list: Option[] = []) {
|
||||
_list.forEach((item) => {
|
||||
result.push(item)
|
||||
flatten(item.children)
|
||||
})
|
||||
}
|
||||
flatten(list)
|
||||
return result
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
const treeData = createData()
|
||||
const valueRef = ref<Array<string | number>>([])
|
||||
const renderSourceList: TransferRenderSourceList = function ({
|
||||
onCheck,
|
||||
pattern
|
||||
}) {
|
||||
return h(NTree, {
|
||||
keyField: 'value',
|
||||
checkable: true,
|
||||
data: treeData,
|
||||
pattern,
|
||||
checkedKeys: valueRef.value,
|
||||
onUpdateCheckedKeys: (checkedKeys: Array<string | number>) => {
|
||||
onCheck(checkedKeys)
|
||||
}
|
||||
})
|
||||
}
|
||||
return {
|
||||
options: flattenTree(createData()),
|
||||
value: valueRef,
|
||||
renderSourceList
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
@ -1,43 +1,41 @@
|
||||
# 穿梭框 Transfer
|
||||
|
||||
<!--single-column-->
|
||||
一个更高效穿梭框。
|
||||
|
||||
~~左、右、左、右...像我这么无聊的人能玩一整天。~~
|
||||
|
||||
现在的样式简洁高效,没得玩了。
|
||||
如果你需要使用原有的穿梭框,请参考 [旧版穿梭框](legacy-transfer),需要注意旧版的穿梭框会在下一个主版本被移除,不建议使用。
|
||||
|
||||
## 演示
|
||||
|
||||
```demo
|
||||
basic.vue
|
||||
large-data.vue
|
||||
size.vue
|
||||
filterable.vue
|
||||
render-label
|
||||
render-source-list
|
||||
render-label.vue
|
||||
render-source-list.vue
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Transfer Props
|
||||
|
||||
| 名称 | 类型 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| default-value | `Array<string \| number> \| null` | `null` | 非受控模式下的默认值 |
|
||||
| disabled | `boolean` | `true` | 是否禁用 |
|
||||
| filterable | `boolean` | `false` | 是否可过滤 |
|
||||
| filter | `(pattern: string, option: TransferOption, from: 'source' \| 'target') => boolean` | 一个简单的标签字符串匹配函数 | 搜索时使用的过滤函数 |
|
||||
| options | `Array<TransferOption>` | `[]` | 配置选项内容,详情见 TransferOption Type |
|
||||
| render-label | `({ from, option }: { from: 'source' \| 'target', option: TransferOption }) => VNodeChild` | `undefined` | 自定义标签 |
|
||||
| render-source-list | `({ onCheck, checkedOptions, pattern }: { onCheck: (checkedValueList: Array<OptionValue>) => void, checkedOptions: Array<Option>, pattern: string }) => VNodeChild` | `undefined` | 自定义源列表 |
|
||||
| size | `'small' \| 'medium' \| 'large'` | `'medium'` | 尺寸 |
|
||||
| source-filter-placeholder | `string` | `undefined` | 源项搜索框中的占位符 |
|
||||
| source-title | `string` | `'源项'` | 源项标题 |
|
||||
| target-filter-placeholder | `string` | `undefined` | 目标项搜索框中的占位符 |
|
||||
| target-title | `string` | `'目标项'` | 目标项标题 |
|
||||
| value | `Array<string \| number> \| null` | `undefined` | 受控模式下的值 |
|
||||
| on-update:value | `(value: Array<string \| number>) => void` | `undefined` | 值发生改变时的回调 |
|
||||
| virtual-scroll | `boolean` | `false` | 是否启用虚拟滚动 |
|
||||
| 名称 | 类型 | 默认值 | 说明 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| default-value | `Array<string \| number> \| null` | `null` | 非受控模式下的默认值 | |
|
||||
| disabled | `boolean` | `true` | 是否禁用 | |
|
||||
| filterable | `boolean` | `false` | 是否可过滤 | |
|
||||
| filter | `(pattern: string, option: TransferOption) => boolean` | 一个简单的标签字符串匹配函数 | 搜索时使用的过滤函数 | |
|
||||
| options | `TransferOption[]` | `[]` | 配置选项内容,详情见 TransferOption Type | |
|
||||
| render-source-label | `(props: { from: 'source' \| 'target', option: TransferOption }) => VNodeChild` | `undefined` | 自定义源标签 | NEXT_VERSION |
|
||||
| render-target-label | `(props: { from: 'source' \| 'target', option: TransferOption }) => VNodeChild` | `undefined` | 自定义目标标签 | NEXT_VERSION |
|
||||
| render-source-list | `(props: { onCheck: (checkedValueList: Array<string \| number>) => void, checkedOptions: TransferOption[], pattern: string }) => VNodeChild` | `undefined` | 自定义源列表 | NEXT_VERSION |
|
||||
| size | `'small' \| 'medium' \| 'large'` | `'medium'` | 尺寸 | |
|
||||
| source-filter-placeholder | `string` | `undefined` | 源项搜索框中的占位符 | |
|
||||
| source-title | `string` | `'源项'` | 源项标题 | |
|
||||
| target-filter-placeholder | `string` | `undefined` | 目标项搜索框中的占位符 | |
|
||||
| target-title | `string` | `'目标项'` | 目标项标题 | |
|
||||
| value | `Array<string \| number> \| null` | `undefined` | 受控模式下的值 | |
|
||||
| on-update:value | `(value: Array<string \| number>) => void` | `undefined` | 值发生改变时的回调 | |
|
||||
| virtual-scroll | `boolean` | `false` | 是否启用虚拟滚动 | |
|
||||
|
||||
#### TransferOption Type
|
||||
|
||||
|
@ -1,9 +1,5 @@
|
||||
<markdown>
|
||||
# 一大堆数据
|
||||
|
||||
~~如果你有一大堆数据,你可能想让它快一点。设定 virtual-scroll 来使用一个飞快的穿梭框(会关掉那个傻乎乎的动画)。~~
|
||||
|
||||
现在不用操心那磨人的动画了。
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
|
@ -1,84 +0,0 @@
|
||||
# 自定义标签
|
||||
|
||||
可以变成通讯录、菜单等,应用场景挺多
|
||||
|
||||
```html
|
||||
<n-transfer
|
||||
ref="transfer"
|
||||
v-model:value="value"
|
||||
:options="options"
|
||||
:renderLabel="renderLabel"
|
||||
/>
|
||||
```
|
||||
|
||||
```js
|
||||
import { defineComponent, ref, h } from 'vue'
|
||||
import { NAvatar } from 'naive-ui'
|
||||
|
||||
const options = [
|
||||
{
|
||||
label: '07akioni',
|
||||
value: 'https://avatars.githubusercontent.com/u/18677354?s=60&v=4'
|
||||
},
|
||||
{
|
||||
label: 'amadeus711',
|
||||
value: 'https://avatars.githubusercontent.com/u/46394163?s=60&v=4'
|
||||
},
|
||||
{
|
||||
label: 'Talljack',
|
||||
value: 'https://avatars.githubusercontent.com/u/34439652?s=60&v=4'
|
||||
},
|
||||
{
|
||||
label: 'JiwenBai',
|
||||
value: 'https://avatars.githubusercontent.com/u/43430022?s=60&v=4'
|
||||
},
|
||||
{
|
||||
label: 'songjianet',
|
||||
value: 'https://avatars.githubusercontent.com/u/19239641?s=60&v=4'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
options,
|
||||
value: ref([options[0].value]),
|
||||
renderLabel: function ({ from, option }) {
|
||||
return h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
display: 'flex',
|
||||
margin: from === 'source' ? undefined : '5px 0'
|
||||
}
|
||||
},
|
||||
{
|
||||
default: () => [
|
||||
from === 'source'
|
||||
? undefined
|
||||
: h(NAvatar, {
|
||||
round: true,
|
||||
src: option.value,
|
||||
size: 'small',
|
||||
fallbackSrc:
|
||||
'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg'
|
||||
}),
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
display: 'flex',
|
||||
marginLeft: from === 'source' ? undefined : '5px',
|
||||
alignSelf: 'center'
|
||||
}
|
||||
},
|
||||
{ default: () => option.label }
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
85
src/transfer/demos/zhCN/render-label.demo.vue
Normal file
85
src/transfer/demos/zhCN/render-label.demo.vue
Normal file
@ -0,0 +1,85 @@
|
||||
<markdown>
|
||||
# 自定义标签
|
||||
|
||||
可以变成通讯录、菜单等,应用场景挺多。
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-transfer
|
||||
ref="transfer"
|
||||
v-model:value="value"
|
||||
:options="options"
|
||||
:render-target-label="renderLabel"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, h } from 'vue'
|
||||
import { NAvatar, TransferRenderTargetLabel } from 'naive-ui'
|
||||
|
||||
const options = [
|
||||
{
|
||||
label: '07akioni',
|
||||
value: 'https://avatars.githubusercontent.com/u/18677354?s=60&v=4'
|
||||
},
|
||||
{
|
||||
label: 'amadeus711',
|
||||
value: 'https://avatars.githubusercontent.com/u/46394163?s=60&v=4'
|
||||
},
|
||||
{
|
||||
label: 'Talljack',
|
||||
value: 'https://avatars.githubusercontent.com/u/34439652?s=60&v=4'
|
||||
},
|
||||
{
|
||||
label: 'JiwenBai',
|
||||
value: 'https://avatars.githubusercontent.com/u/43430022?s=60&v=4'
|
||||
},
|
||||
{
|
||||
label: 'songjianet',
|
||||
value: 'https://avatars.githubusercontent.com/u/19239641?s=60&v=4'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
const renderLabel: TransferRenderTargetLabel = function ({ option }) {
|
||||
return h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
display: 'flex',
|
||||
margin: '6px 0'
|
||||
}
|
||||
},
|
||||
{
|
||||
default: () => [
|
||||
h(NAvatar, {
|
||||
round: true,
|
||||
src: option.value as string,
|
||||
size: 'small',
|
||||
fallbackSrc:
|
||||
'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg'
|
||||
}),
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
display: 'flex',
|
||||
marginLeft: '6px',
|
||||
alignSelf: 'center'
|
||||
}
|
||||
},
|
||||
{ default: () => option.label }
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
return {
|
||||
options,
|
||||
value: ref([options[0].value]),
|
||||
renderLabel
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
@ -1,70 +0,0 @@
|
||||
# 自定义列表
|
||||
|
||||
```html
|
||||
<n-transfer
|
||||
ref="transfer"
|
||||
v-model:value="value"
|
||||
:options="options"
|
||||
:renderSourceList="renderSourceList"
|
||||
filterable
|
||||
/>
|
||||
```
|
||||
|
||||
```js
|
||||
import { defineComponent, ref, h } from 'vue'
|
||||
import { repeat } from 'seemly'
|
||||
import { NTree } from 'naive-ui'
|
||||
|
||||
function createLabel (level) {
|
||||
if (level === 4) return '道生一'
|
||||
if (level === 3) return '一生二'
|
||||
if (level === 2) return '二生三'
|
||||
if (level === 1) return '三生万物'
|
||||
return ''
|
||||
}
|
||||
|
||||
function createData (level = 4, baseKey = '') {
|
||||
if (!level) return undefined
|
||||
return repeat(6 - level, undefined).map((_, index) => {
|
||||
const value = '' + baseKey + level + index
|
||||
return {
|
||||
label: createLabel(level),
|
||||
value,
|
||||
children: createData(level - 1, value)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function flattenTree (list) {
|
||||
const result = []
|
||||
function flatten (_list = []) {
|
||||
_list.forEach((item) => {
|
||||
result.push(item)
|
||||
flatten(item.children)
|
||||
})
|
||||
}
|
||||
flatten(list)
|
||||
return result
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
options: flattenTree(createData()),
|
||||
value: ref([]),
|
||||
renderSourceList: function ({ onCheck, checkedOptions, pattern }) {
|
||||
return h(NTree, {
|
||||
keyField: 'value',
|
||||
checkable: true,
|
||||
data: createData(),
|
||||
pattern,
|
||||
checkedKeys: checkedOptions.map((i) => i.value),
|
||||
onUpdateCheckedKeys: function (_, option) {
|
||||
onCheck(option.map((i) => i.value))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
84
src/transfer/demos/zhCN/render-source-list.demo.vue
Normal file
84
src/transfer/demos/zhCN/render-source-list.demo.vue
Normal file
@ -0,0 +1,84 @@
|
||||
<markdown>
|
||||
# 自定义列表
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-transfer
|
||||
ref="transfer"
|
||||
v-model:value="value"
|
||||
:options="options"
|
||||
:render-source-list="renderSourceList"
|
||||
filterable
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, h } from 'vue'
|
||||
import { repeat } from 'seemly'
|
||||
import { NTree, TransferRenderSourceList } from 'naive-ui'
|
||||
|
||||
function createLabel (level: number): string {
|
||||
if (level === 4) return '道生一'
|
||||
if (level === 3) return '一生二'
|
||||
if (level === 2) return '二生三'
|
||||
if (level === 1) return '三生万物'
|
||||
return ''
|
||||
}
|
||||
|
||||
type Option = {
|
||||
label: string
|
||||
value: string
|
||||
children?: Option[]
|
||||
}
|
||||
|
||||
function createData (level = 4, baseKey = ''): Option[] | undefined {
|
||||
if (!level) return undefined
|
||||
return repeat(6 - level, undefined).map((_, index) => {
|
||||
const value = '' + baseKey + level + index
|
||||
return {
|
||||
label: createLabel(level),
|
||||
value,
|
||||
children: createData(level - 1, value)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function flattenTree (list: undefined | Option[]): Option[] {
|
||||
const result: Option[] = []
|
||||
function flatten (_list: Option[] = []) {
|
||||
_list.forEach((item) => {
|
||||
result.push(item)
|
||||
flatten(item.children)
|
||||
})
|
||||
}
|
||||
flatten(list)
|
||||
return result
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
const treeData = createData()
|
||||
const valueRef = ref<Array<string | number>>([])
|
||||
const renderSourceList: TransferRenderSourceList = function ({
|
||||
onCheck,
|
||||
pattern
|
||||
}) {
|
||||
return h(NTree, {
|
||||
keyField: 'value',
|
||||
checkable: true,
|
||||
data: treeData,
|
||||
pattern,
|
||||
checkedKeys: valueRef.value,
|
||||
onUpdateCheckedKeys: (checkedKeys: Array<string | number>) => {
|
||||
onCheck(checkedKeys)
|
||||
}
|
||||
})
|
||||
}
|
||||
return {
|
||||
options: flattenTree(createData()),
|
||||
value: valueRef,
|
||||
renderSourceList
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
@ -1,3 +1,8 @@
|
||||
export { default as NTransfer, transferProps } from './src/Transfer'
|
||||
export type { TransferProps } from './src/Transfer'
|
||||
export type { Option as TransferOption } from './src/interface'
|
||||
export type {
|
||||
Option as TransferOption,
|
||||
TransferRenderSourceLabel,
|
||||
TransferRenderTargetLabel,
|
||||
RenderSourceListType as TransferRenderSourceList
|
||||
} from './src/interface'
|
||||
|
@ -4,14 +4,17 @@ import {
|
||||
h,
|
||||
provide,
|
||||
PropType,
|
||||
CSSProperties
|
||||
CSSProperties,
|
||||
watchEffect,
|
||||
toRef
|
||||
} from 'vue'
|
||||
import { useIsMounted } from 'vooks'
|
||||
import { depx } from 'seemly'
|
||||
import { NScrollbar } from '../../_internal'
|
||||
import { useFormItem, useTheme, useConfig } from '../../_mixins'
|
||||
import type { ThemeProps } from '../../_mixins'
|
||||
import { createKey } from '../../_utils/cssr'
|
||||
import { warn, call, ExtractPublicPropTypes } from '../../_utils'
|
||||
import { call, ExtractPublicPropTypes, warnOnce } from '../../_utils'
|
||||
import type { MaybeArray } from '../../_utils'
|
||||
import { transferLight } from '../styles'
|
||||
import type { TransferTheme } from '../styles'
|
||||
@ -19,17 +22,17 @@ import NTransferHeader from './TransferHeader'
|
||||
import NTransferList from './TransferList'
|
||||
import NTransferFilter from './TransferFilter'
|
||||
import { useTransferData } from './use-transfer-data'
|
||||
import style from './styles/index.cssr'
|
||||
import {
|
||||
OptionValue,
|
||||
Option,
|
||||
Filter,
|
||||
OnUpdateValue,
|
||||
transferInjectionKey,
|
||||
RenderLabelType,
|
||||
RenderSourceListType
|
||||
TransferRenderTargetLabel,
|
||||
RenderSourceListType,
|
||||
TransferRenderSourceLabel
|
||||
} from './interface'
|
||||
import { NScrollbar } from '../../_internal'
|
||||
import style from './styles/index.cssr'
|
||||
|
||||
export const transferProps = {
|
||||
...(useTheme.props as ThemeProps<TransferTheme>),
|
||||
@ -62,23 +65,12 @@ export const transferProps = {
|
||||
}
|
||||
},
|
||||
size: String as PropType<'small' | 'medium' | 'large'>,
|
||||
renderLabel: Function as PropType<RenderLabelType>,
|
||||
renderSourceLabel: Function as PropType<TransferRenderSourceLabel>,
|
||||
renderTargetLabel: Function as PropType<TransferRenderTargetLabel>,
|
||||
renderSourceList: Function as PropType<RenderSourceListType>,
|
||||
'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
|
||||
}
|
||||
onChange: [Function, Array] as PropType<MaybeArray<OnUpdateValue>>
|
||||
} as const
|
||||
|
||||
export type TransferProps = ExtractPublicPropTypes<typeof transferProps>
|
||||
@ -87,6 +79,16 @@ export default defineComponent({
|
||||
name: 'Transfer',
|
||||
props: transferProps,
|
||||
setup (props) {
|
||||
if (__DEV__) {
|
||||
watchEffect(() => {
|
||||
if (props.onChange !== undefined) {
|
||||
warnOnce(
|
||||
'transfer',
|
||||
'`on-change` is deprecated, please use `on-update:value` instead.'
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
const { mergedClsPrefixRef } = useConfig(props)
|
||||
const themeRef = useTheme(
|
||||
'Transfer',
|
||||
@ -106,18 +108,17 @@ export default defineComponent({
|
||||
return depx(itemSize)
|
||||
})
|
||||
const {
|
||||
uncontrolledValue: uncontrolledValueRef,
|
||||
mergedValue: mergedValueRef,
|
||||
tgtValueSet: tgtValueSetRef,
|
||||
avlSrcValueSet: avlSrcValueSetRef,
|
||||
tgtOpts: tgtOptsRef,
|
||||
srcOpts: srcOptsRef,
|
||||
filteredSrcOpts: filteredSrcOptsRef,
|
||||
headerBtnStatus: headerBtnStatusRef,
|
||||
srcPattern: srcPatternRef,
|
||||
isInputing: isInputingRef,
|
||||
handleInputFocus,
|
||||
handleInputBlur,
|
||||
uncontrolledValueRef,
|
||||
mergedValueRef,
|
||||
targetValueSetRef,
|
||||
valueSetForSelectAllRef,
|
||||
valueSetForUnselectAllRef,
|
||||
targetOptionsRef,
|
||||
filteredSrcOptionsRef,
|
||||
canNotSelectAnythingRef,
|
||||
canBeClearedRef,
|
||||
allCheckedRef,
|
||||
srcPatternRef,
|
||||
handleSrcFilterUpdateValue
|
||||
} = useTransferData(props)
|
||||
function doUpdateValue (value: OptionValue[]): void {
|
||||
@ -136,11 +137,11 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
function handleClearAll (): void {
|
||||
doUpdateValue([])
|
||||
doUpdateValue([...valueSetForUnselectAllRef.value])
|
||||
}
|
||||
|
||||
function handleCheckedAll (): void {
|
||||
doUpdateValue([...avlSrcValueSetRef.value])
|
||||
doUpdateValue([...valueSetForSelectAllRef.value])
|
||||
}
|
||||
|
||||
function handleItemCheck (checked: boolean, optionValue: OptionValue): void {
|
||||
@ -161,28 +162,29 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
provide(transferInjectionKey, {
|
||||
tgtValueSetRef,
|
||||
targetValueSetRef,
|
||||
mergedClsPrefixRef,
|
||||
disabledRef: mergedDisabledRef,
|
||||
mergedThemeRef: themeRef,
|
||||
srcOptsRef,
|
||||
tgtOptsRef,
|
||||
headerBtnStatusRef,
|
||||
targetOptionsRef,
|
||||
canNotSelectAnythingRef,
|
||||
canBeClearedRef,
|
||||
allCheckedRef,
|
||||
srcOptionsLengthRef: computed(() => props.options.length),
|
||||
handleItemCheck,
|
||||
renderLabel: props.renderLabel
|
||||
renderSourceLabelRef: toRef(props, 'renderSourceLabel'),
|
||||
renderTargetLabelRef: toRef(props, 'renderTargetLabel')
|
||||
})
|
||||
return {
|
||||
mergedClsPrefix: mergedClsPrefixRef,
|
||||
mergedDisabled: mergedDisabledRef,
|
||||
itemSize: itemSizeRef,
|
||||
isMounted: useIsMounted(),
|
||||
isInputing: isInputingRef,
|
||||
mergedTheme: themeRef,
|
||||
filteredSrcOpts: filteredSrcOptsRef,
|
||||
tgtOpts: tgtOptsRef,
|
||||
filteredSrcOpts: filteredSrcOptionsRef,
|
||||
tgtOpts: targetOptionsRef,
|
||||
srcPattern: srcPatternRef,
|
||||
handleInputFocus,
|
||||
handleInputBlur,
|
||||
mergedSize: mergedSizeRef,
|
||||
handleSrcFilterUpdateValue,
|
||||
handleCheckedAll,
|
||||
handleClearAll,
|
||||
@ -193,7 +195,6 @@ export default defineComponent({
|
||||
const {
|
||||
common: { cubicBezierEaseInOut },
|
||||
self: {
|
||||
width,
|
||||
borderRadius,
|
||||
borderColor,
|
||||
listColor,
|
||||
@ -203,12 +204,21 @@ export default defineComponent({
|
||||
itemTextColor,
|
||||
itemColorPending,
|
||||
itemTextColorDisabled,
|
||||
extraFontSize,
|
||||
titleFontWeight,
|
||||
iconColor,
|
||||
iconColorDisabled,
|
||||
closeColorHover,
|
||||
closeColorPressed,
|
||||
closeIconColor,
|
||||
closeIconColorHover,
|
||||
closeIconColorPressed,
|
||||
closeIconSize,
|
||||
closeSize,
|
||||
dividerColor,
|
||||
extraTextColorDisabled,
|
||||
[createKey('extraFontSize', size)]: extraFontSize,
|
||||
[createKey('fontSize', size)]: fontSize,
|
||||
[createKey('itemHeight', size)]: itemHeight
|
||||
[createKey('titleFontSize', size)]: titleFontSize,
|
||||
[createKey('itemHeight', size)]: itemHeight,
|
||||
[createKey('headerHeight', size)]: headerHeight
|
||||
}
|
||||
} = themeRef.value
|
||||
return {
|
||||
@ -217,7 +227,9 @@ export default defineComponent({
|
||||
'--n-border-radius': borderRadius,
|
||||
'--n-extra-font-size': extraFontSize,
|
||||
'--n-font-size': fontSize,
|
||||
'--n-header-font-size': titleFontSize,
|
||||
'--n-header-extra-text-color': extraTextColor,
|
||||
'--n-header-extra-text-color-disabled': extraTextColorDisabled,
|
||||
'--n-header-font-weight': titleFontWeight,
|
||||
'--n-header-text-color': titleTextColor,
|
||||
'--n-header-text-color-disabled': titleTextColorDisabled,
|
||||
@ -226,9 +238,15 @@ export default defineComponent({
|
||||
'--n-item-text-color': itemTextColor,
|
||||
'--n-item-text-color-disabled': itemTextColorDisabled,
|
||||
'--n-list-color': listColor,
|
||||
'--n-width': width,
|
||||
'--n-icon-color': iconColor,
|
||||
'--n-icon-color-disabled': iconColorDisabled
|
||||
'--n-header-height': headerHeight,
|
||||
'--n-close-size': closeSize,
|
||||
'--n-close-icon-size': closeIconSize,
|
||||
'--n-close-color-hover': closeColorHover,
|
||||
'--n-close-color-pressed': closeColorPressed,
|
||||
'--n-close-icon-color': closeIconColor,
|
||||
'--n-close-icon-color-hover': closeIconColorHover,
|
||||
'--n-close-icon-color-pressed': closeIconColorPressed,
|
||||
'--n-divider-color': dividerColor
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -244,12 +262,15 @@ export default defineComponent({
|
||||
]}
|
||||
style={this.cssVars as CSSProperties}
|
||||
>
|
||||
<div class={`${mergedClsPrefix}-transfer-list`}>
|
||||
<div
|
||||
class={`${mergedClsPrefix}-transfer-list ${mergedClsPrefix}-transfer-list--source`}
|
||||
>
|
||||
<NTransferHeader
|
||||
source
|
||||
title={this.sourceTitle}
|
||||
onCheckedAll={this.handleCheckedAll}
|
||||
onClearAll={this.handleClearAll}
|
||||
title={this.sourceTitle}
|
||||
size={this.mergedSize}
|
||||
/>
|
||||
<div class={`${mergedClsPrefix}-transfer-list-body`}>
|
||||
{this.filterable ? (
|
||||
@ -258,8 +279,6 @@ export default defineComponent({
|
||||
value={this.srcPattern}
|
||||
disabled={this.mergedDisabled}
|
||||
placeholder={this.sourceFilterPlaceholder}
|
||||
onFocus={this.handleInputFocus}
|
||||
onBlur={this.handleInputBlur}
|
||||
/>
|
||||
) : null}
|
||||
<div class={`${mergedClsPrefix}-transfer-list-flex-container`}>
|
||||
@ -283,8 +302,6 @@ export default defineComponent({
|
||||
options={this.filteredSrcOpts}
|
||||
disabled={this.mergedDisabled}
|
||||
virtualScroll={this.virtualScroll}
|
||||
isMounted={this.isMounted}
|
||||
isInputing={this.isInputing}
|
||||
itemSize={this.itemSize}
|
||||
/>
|
||||
)}
|
||||
@ -292,10 +309,13 @@ export default defineComponent({
|
||||
</div>
|
||||
<div class={`${mergedClsPrefix}-transfer-list__border`} />
|
||||
</div>
|
||||
<div class={`${mergedClsPrefix}-transfer-list`}>
|
||||
<div
|
||||
class={`${mergedClsPrefix}-transfer-list ${mergedClsPrefix}-transfer-list--target`}
|
||||
>
|
||||
<NTransferHeader
|
||||
title={this.targetTitle}
|
||||
onClearAll={this.handleClearAll}
|
||||
size={this.mergedSize}
|
||||
title={this.targetTitle}
|
||||
/>
|
||||
<div class={`${mergedClsPrefix}-transfer-list-body`}>
|
||||
<div class={`${mergedClsPrefix}-transfer-list-flex-container`}>
|
||||
@ -303,8 +323,6 @@ export default defineComponent({
|
||||
options={this.tgtOpts}
|
||||
disabled={this.mergedDisabled}
|
||||
virtualScroll={this.virtualScroll}
|
||||
isMounted={this.isMounted}
|
||||
isInputing={this.isInputing}
|
||||
itemSize={this.itemSize}
|
||||
/>
|
||||
</div>
|
||||
|
@ -10,14 +10,6 @@ export default defineComponent({
|
||||
value: String,
|
||||
placeholder: String,
|
||||
disabled: Boolean,
|
||||
onFocus: {
|
||||
type: Function as PropType<() => void>,
|
||||
required: true
|
||||
},
|
||||
onBlur: {
|
||||
type: Function as PropType<() => void>,
|
||||
required: true
|
||||
},
|
||||
onUpdateValue: {
|
||||
type: Function as PropType<(value: string | null) => void>,
|
||||
required: true
|
||||
@ -39,20 +31,15 @@ export default defineComponent({
|
||||
value={this.value}
|
||||
onUpdateValue={this.onUpdateValue}
|
||||
disabled={this.disabled}
|
||||
placeholder={this.placeholder}
|
||||
theme={mergedTheme.peers.Input}
|
||||
themeOverrides={mergedTheme.peerOverrides.Input}
|
||||
clearable
|
||||
size="small"
|
||||
placeholder={this.placeholder}
|
||||
onFocus={this.onFocus}
|
||||
onBlur={this.onBlur}
|
||||
>
|
||||
{{
|
||||
'clear-icon-placeholder': () => (
|
||||
<NBaseIcon
|
||||
clsPrefix={mergedClsPrefix}
|
||||
class={`${mergedClsPrefix}-transfer-icon`}
|
||||
>
|
||||
<NBaseIcon clsPrefix={mergedClsPrefix}>
|
||||
{{ default: () => <SearchIcon /> }}
|
||||
</NBaseIcon>
|
||||
)
|
||||
|
@ -6,77 +6,77 @@ import { transferInjectionKey } from './interface'
|
||||
export default defineComponent({
|
||||
name: 'TransferHeader',
|
||||
props: {
|
||||
source: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
onCheckedAll: {
|
||||
type: Function as PropType<() => void>
|
||||
},
|
||||
onClearAll: {
|
||||
type: Function as PropType<() => void>
|
||||
size: {
|
||||
type: String as PropType<'small' | 'medium' | 'large'>,
|
||||
required: true
|
||||
},
|
||||
source: Boolean,
|
||||
onCheckedAll: Function as PropType<() => void>,
|
||||
onClearAll: Function as PropType<() => void>,
|
||||
title: String
|
||||
},
|
||||
setup (props) {
|
||||
const {
|
||||
srcOptsRef,
|
||||
tgtOptsRef,
|
||||
headerBtnStatusRef,
|
||||
targetOptionsRef,
|
||||
canNotSelectAnythingRef,
|
||||
canBeClearedRef,
|
||||
allCheckedRef,
|
||||
mergedThemeRef,
|
||||
disabledRef,
|
||||
mergedClsPrefixRef
|
||||
mergedClsPrefixRef,
|
||||
srcOptionsLengthRef
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
} = inject(transferInjectionKey)!
|
||||
const { localeRef } = useLocale('Transfer')
|
||||
return () => {
|
||||
const { source, onClearAll, onCheckedAll } = props
|
||||
const { value: headerBtnStatus } = headerBtnStatusRef
|
||||
const { value: mergedTheme } = mergedThemeRef
|
||||
const { value: mergedClsPrefix } = mergedClsPrefixRef
|
||||
const { value: locale } = localeRef
|
||||
const buttonSize = props.size === 'large' ? 'small' : 'tiny'
|
||||
const { title } = props
|
||||
return (
|
||||
<div class={`${mergedClsPrefix}-transfer-list-header`}>
|
||||
{title && (
|
||||
<div class={`${mergedClsPrefix}-transfer-list-header__title`}>
|
||||
{title}
|
||||
</div>
|
||||
)}
|
||||
{source && (
|
||||
<div class={`${mergedClsPrefix}-transfer-list-header__button`}>
|
||||
<NButton
|
||||
theme={mergedTheme.peers.Button}
|
||||
themeOverrides={mergedTheme.peerOverrides.Button}
|
||||
size="tiny"
|
||||
tertiary
|
||||
onClick={headerBtnStatus.allChecked ? onClearAll : onCheckedAll}
|
||||
disabled={headerBtnStatus.disabled || disabledRef.value}
|
||||
>
|
||||
{{
|
||||
default: () =>
|
||||
headerBtnStatus.allChecked ? '取消全选' : '全选'
|
||||
}}
|
||||
</NButton>
|
||||
</div>
|
||||
<NButton
|
||||
class={`${mergedClsPrefix}-transfer-list-header__button`}
|
||||
theme={mergedTheme.peers.Button}
|
||||
themeOverrides={mergedTheme.peerOverrides.Button}
|
||||
size={buttonSize}
|
||||
tertiary
|
||||
onClick={allCheckedRef.value ? onClearAll : onCheckedAll}
|
||||
disabled={canNotSelectAnythingRef.value || disabledRef.value}
|
||||
>
|
||||
{{
|
||||
default: () =>
|
||||
allCheckedRef.value ? locale.unselectAll : locale.selectAll
|
||||
}}
|
||||
</NButton>
|
||||
)}
|
||||
{!source && headerBtnStatus.checked && (
|
||||
<div class={`${mergedClsPrefix}-transfer-list-header__button`}>
|
||||
<NButton
|
||||
theme={mergedTheme.peers.Button}
|
||||
themeOverrides={mergedTheme.peerOverrides.Button}
|
||||
size="tiny"
|
||||
tertiary
|
||||
onClick={onClearAll}
|
||||
disabled={headerBtnStatus.disabled || disabledRef.value}
|
||||
>
|
||||
{{
|
||||
default: () => '清空'
|
||||
}}
|
||||
</NButton>
|
||||
</div>
|
||||
{!source && canBeClearedRef.value && (
|
||||
<NButton
|
||||
class={`${mergedClsPrefix}-transfer-list-header__button`}
|
||||
theme={mergedTheme.peers.Button}
|
||||
themeOverrides={mergedTheme.peerOverrides.Button}
|
||||
size={buttonSize}
|
||||
tertiary
|
||||
onClick={onClearAll}
|
||||
disabled={disabledRef.value}
|
||||
>
|
||||
{{
|
||||
default: () => locale.clearAll
|
||||
}}
|
||||
</NButton>
|
||||
)}
|
||||
{/* <div class={`${mergedClsPrefix}-transfer-list-header__header`}>
|
||||
{props.title}
|
||||
</div> */}
|
||||
<div class={`${mergedClsPrefix}-transfer-list-header__extra`}>
|
||||
{source
|
||||
? locale.total(srcOptsRef.value.length)
|
||||
: locale.selectedTotal(tgtOptsRef.value.length)}
|
||||
? locale.total(srcOptionsLengthRef.value)
|
||||
: locale.selected(targetOptionsRef.value.length)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -1,13 +1,4 @@
|
||||
import {
|
||||
h,
|
||||
defineComponent,
|
||||
ref,
|
||||
inject,
|
||||
PropType,
|
||||
TransitionGroup,
|
||||
Transition,
|
||||
Fragment
|
||||
} from 'vue'
|
||||
import { h, defineComponent, ref, inject, PropType } from 'vue'
|
||||
import { VirtualList, VirtualListInst } from 'vueuc'
|
||||
import { NEmpty } from '../../empty'
|
||||
import { NScrollbar, ScrollbarInst } from '../../_internal'
|
||||
@ -33,18 +24,7 @@ export default defineComponent({
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
isMounted: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
isInputing: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
source: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
source: Boolean
|
||||
},
|
||||
setup () {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
@ -77,89 +57,71 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const { mergedTheme, mergedClsPrefix, virtualScroll, syncVLScroller } = this
|
||||
const { mergedTheme, options } = this
|
||||
if (options.length === 0) {
|
||||
return (
|
||||
<NEmpty
|
||||
theme={mergedTheme.peers.Empty}
|
||||
themeOverrides={mergedTheme.peerOverrides.Empty}
|
||||
/>
|
||||
)
|
||||
}
|
||||
const { mergedClsPrefix, virtualScroll, source, disabled, syncVLScroller } =
|
||||
this
|
||||
return (
|
||||
<>
|
||||
<NScrollbar
|
||||
ref="scrollerInstRef"
|
||||
theme={mergedTheme.peers.Scrollbar}
|
||||
themeOverrides={mergedTheme.peerOverrides.Scrollbar}
|
||||
container={virtualScroll ? this.scrollContainer : undefined}
|
||||
content={virtualScroll ? this.scrollContent : undefined}
|
||||
>
|
||||
{{
|
||||
default: () =>
|
||||
virtualScroll ? (
|
||||
<VirtualList
|
||||
ref="vlInstRef"
|
||||
style={{ height: '100%' }}
|
||||
class={`${mergedClsPrefix}-transfer-list-content`}
|
||||
items={this.options}
|
||||
itemSize={this.itemSize}
|
||||
showScrollbar={false}
|
||||
onResize={syncVLScroller}
|
||||
onScroll={syncVLScroller}
|
||||
keyField="value"
|
||||
>
|
||||
{{
|
||||
default: ({ item }: { item: Option }) => {
|
||||
const { source, disabled } = this
|
||||
return (
|
||||
<NTransferListItem
|
||||
source={source}
|
||||
key={item.value}
|
||||
value={item.value}
|
||||
disabled={item.disabled || disabled}
|
||||
label={item.label}
|
||||
option={item}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}}
|
||||
</VirtualList>
|
||||
) : (
|
||||
<div class={`${mergedClsPrefix}-transfer-list-content`}>
|
||||
<TransitionGroup
|
||||
name="item"
|
||||
appear={this.isMounted}
|
||||
css={!this.isInputing}
|
||||
>
|
||||
{{
|
||||
default: () => {
|
||||
const { source, disabled } = this
|
||||
return this.options.map((option) => (
|
||||
<NTransferListItem
|
||||
source={source}
|
||||
key={option.value}
|
||||
value={option.value}
|
||||
disabled={option.disabled || disabled}
|
||||
label={option.label}
|
||||
option={option}
|
||||
/>
|
||||
))
|
||||
}
|
||||
}}
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</NScrollbar>
|
||||
<Transition
|
||||
name="fade-in-transition"
|
||||
appear={this.isMounted}
|
||||
css={!this.isInputing}
|
||||
>
|
||||
{{
|
||||
default: () =>
|
||||
this.options.length ? null : (
|
||||
<NEmpty
|
||||
theme={mergedTheme.peers.Empty}
|
||||
themeOverrides={mergedTheme.peerOverrides.Empty}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
</Transition>
|
||||
</>
|
||||
<NScrollbar
|
||||
ref="scrollerInstRef"
|
||||
theme={mergedTheme.peers.Scrollbar}
|
||||
themeOverrides={mergedTheme.peerOverrides.Scrollbar}
|
||||
container={virtualScroll ? this.scrollContainer : undefined}
|
||||
content={virtualScroll ? this.scrollContent : undefined}
|
||||
>
|
||||
{{
|
||||
default: () =>
|
||||
virtualScroll ? (
|
||||
<VirtualList
|
||||
ref="vlInstRef"
|
||||
style={{ height: '100%' }}
|
||||
class={`${mergedClsPrefix}-transfer-list-content`}
|
||||
items={this.options}
|
||||
itemSize={this.itemSize}
|
||||
showScrollbar={false}
|
||||
onResize={syncVLScroller}
|
||||
onScroll={syncVLScroller}
|
||||
keyField="value"
|
||||
>
|
||||
{{
|
||||
default: ({ item }: { item: Option }) => {
|
||||
const { source, disabled } = this
|
||||
return (
|
||||
<NTransferListItem
|
||||
source={source}
|
||||
key={item.value}
|
||||
value={item.value}
|
||||
disabled={item.disabled || disabled}
|
||||
label={item.label}
|
||||
option={item}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}}
|
||||
</VirtualList>
|
||||
) : (
|
||||
<div class={`${mergedClsPrefix}-transfer-list-content`}>
|
||||
{this.options.map((option) => (
|
||||
<NTransferListItem
|
||||
source={source}
|
||||
key={option.value}
|
||||
value={option.value}
|
||||
disabled={option.disabled || disabled}
|
||||
label={option.label}
|
||||
option={option}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</NScrollbar>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
@ -1,17 +1,14 @@
|
||||
import { h, inject, defineComponent, ref, PropType } from 'vue'
|
||||
import { h, inject, defineComponent, PropType } from 'vue'
|
||||
import { useMemo } from 'vooks'
|
||||
import { NCheckbox } from '../../checkbox'
|
||||
import { transferInjectionKey, Option } from './interface'
|
||||
import { getTitleAttribute } from '../../_utils'
|
||||
import { NBaseClose } from '../../_internal'
|
||||
import { transferInjectionKey, Option } from './interface'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NTransferListItem',
|
||||
props: {
|
||||
source: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
source: Boolean,
|
||||
label: {
|
||||
type: String,
|
||||
required: true
|
||||
@ -20,10 +17,7 @@ export default defineComponent({
|
||||
type: [String, Number],
|
||||
required: true
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disabled: Boolean,
|
||||
option: {
|
||||
type: Object as PropType<Option>,
|
||||
required: true
|
||||
@ -31,35 +25,27 @@ export default defineComponent({
|
||||
},
|
||||
setup (props) {
|
||||
const {
|
||||
tgtValueSetRef,
|
||||
targetValueSetRef,
|
||||
mergedClsPrefixRef,
|
||||
mergedThemeRef,
|
||||
handleItemCheck,
|
||||
renderLabel
|
||||
renderSourceLabelRef,
|
||||
renderTargetLabelRef
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
} = inject(transferInjectionKey)!
|
||||
const checkedRef = useMemo(() => tgtValueSetRef.value.has(props.value))
|
||||
const hasItemHoverRef = ref(false)
|
||||
const checkedRef = useMemo(() => targetValueSetRef.value.has(props.value))
|
||||
function handleClick (): void {
|
||||
if (!props.disabled) {
|
||||
handleItemCheck(!checkedRef.value, props.value)
|
||||
}
|
||||
}
|
||||
function handleMouseEnter (): void {
|
||||
hasItemHoverRef.value = true
|
||||
}
|
||||
function handleMouseLeave (): void {
|
||||
hasItemHoverRef.value = false
|
||||
}
|
||||
return {
|
||||
mergedClsPrefix: mergedClsPrefixRef,
|
||||
mergedTheme: mergedThemeRef,
|
||||
checked: checkedRef,
|
||||
hasItemHover: hasItemHoverRef,
|
||||
handleClick,
|
||||
handleMouseEnter,
|
||||
handleMouseLeave,
|
||||
renderLabel
|
||||
renderSourceLabel: renderSourceLabelRef,
|
||||
renderTargetLabel: renderTargetLabelRef
|
||||
}
|
||||
},
|
||||
render () {
|
||||
@ -70,7 +56,8 @@ export default defineComponent({
|
||||
label,
|
||||
checked,
|
||||
source,
|
||||
renderLabel
|
||||
renderSourceLabel,
|
||||
renderTargetLabel
|
||||
} = this
|
||||
return (
|
||||
<div
|
||||
@ -81,10 +68,9 @@ export default defineComponent({
|
||||
? `${mergedClsPrefix}-transfer-list-item--source`
|
||||
: `${mergedClsPrefix}-transfer-list-item--target`
|
||||
]}
|
||||
onClick={() => (source ? this.handleClick() : null)}
|
||||
onMouseenter={this.handleMouseEnter}
|
||||
onMouseleave={this.handleMouseLeave}
|
||||
onClick={source ? this.handleClick : undefined}
|
||||
>
|
||||
<div class={`${mergedClsPrefix}-transfer-list-item__background`} />
|
||||
{source && (
|
||||
<div class={`${mergedClsPrefix}-transfer-list-item__checkbox`}>
|
||||
<NCheckbox
|
||||
@ -99,20 +85,25 @@ export default defineComponent({
|
||||
class={`${mergedClsPrefix}-transfer-list-item__label`}
|
||||
title={getTitleAttribute(label)}
|
||||
>
|
||||
{renderLabel
|
||||
? renderLabel({
|
||||
from: source ? 'source' : 'target',
|
||||
option: this.option
|
||||
})
|
||||
: label}
|
||||
{source
|
||||
? renderSourceLabel
|
||||
? renderSourceLabel({
|
||||
option: this.option
|
||||
})
|
||||
: label
|
||||
: renderTargetLabel
|
||||
? renderTargetLabel({
|
||||
option: this.option
|
||||
})
|
||||
: label}
|
||||
</div>
|
||||
{!source && this.hasItemHover && !disabled && (
|
||||
<div class={`${mergedClsPrefix}-transfer-list-item__close`}>
|
||||
<NBaseClose
|
||||
clsPrefix={mergedClsPrefix}
|
||||
onClick={this.handleClick}
|
||||
/>
|
||||
</div>
|
||||
{!source && !disabled && (
|
||||
<NBaseClose
|
||||
focusable={false}
|
||||
class={`${mergedClsPrefix}-transfer-list-item__close`}
|
||||
clsPrefix={mergedClsPrefix}
|
||||
onClick={this.handleClick}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
|
@ -10,24 +10,14 @@ export interface Option {
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
export interface CheckedStatus {
|
||||
checked: boolean
|
||||
allChecked: boolean
|
||||
disabled: boolean
|
||||
}
|
||||
|
||||
export type Filter = (
|
||||
pattern: string,
|
||||
option: Option,
|
||||
from: 'source' | 'target'
|
||||
) => boolean
|
||||
export type Filter = (pattern: string, option: Option) => boolean
|
||||
|
||||
export interface RenderLabelProps {
|
||||
from: 'source' | 'target'
|
||||
option: Option
|
||||
}
|
||||
|
||||
export type RenderLabelType = (props: RenderLabelProps) => VNodeChild
|
||||
export type TransferRenderTargetLabel = (props: RenderLabelProps) => VNodeChild
|
||||
export type TransferRenderSourceLabel = (props: RenderLabelProps) => VNodeChild
|
||||
|
||||
export interface RenderListProps {
|
||||
onCheck: (checkedValueList: OptionValue[]) => void
|
||||
@ -38,15 +28,18 @@ export interface RenderListProps {
|
||||
export type RenderSourceListType = (props: RenderListProps) => VNodeChild
|
||||
|
||||
export interface TransferInjection {
|
||||
tgtValueSetRef: Ref<Set<OptionValue>>
|
||||
targetValueSetRef: Ref<Set<OptionValue>>
|
||||
mergedClsPrefixRef: Ref<string>
|
||||
disabledRef: Ref<boolean>
|
||||
mergedThemeRef: Ref<MergedTheme<TransferTheme>>
|
||||
srcOptsRef: Ref<Option[]>
|
||||
tgtOptsRef: Ref<Option[]>
|
||||
headerBtnStatusRef: Ref<CheckedStatus>
|
||||
targetOptionsRef: Ref<Option[]>
|
||||
canNotSelectAnythingRef: Ref<boolean>
|
||||
canBeClearedRef: Ref<boolean>
|
||||
allCheckedRef: Ref<boolean>
|
||||
srcOptionsLengthRef: Ref<number>
|
||||
handleItemCheck: (checked: boolean, value: OptionValue) => void
|
||||
renderLabel: RenderLabelType | undefined
|
||||
renderSourceLabelRef: Ref<TransferRenderSourceLabel | undefined>
|
||||
renderTargetLabelRef: Ref<TransferRenderTargetLabel | undefined>
|
||||
}
|
||||
|
||||
export const transferInjectionKey =
|
||||
|
@ -1,241 +1,199 @@
|
||||
import { c, cB, cE, cM, cNotM } from '../../../_utils/cssr'
|
||||
|
||||
const animation = c([
|
||||
c('@keyframes transfer-slide-in-from-left', `
|
||||
0% {
|
||||
transform: translateX(-150%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
`),
|
||||
c('@keyframes transfer-slide-out-to-right', `
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(150%);
|
||||
}
|
||||
`),
|
||||
c('@keyframes transfer-slide-in-from-right', `
|
||||
0% {
|
||||
transform: translateX(150%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
`),
|
||||
c('@keyframes transfer-slide-out-to-left', `
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(-150%);
|
||||
}
|
||||
`),
|
||||
c('@keyframes transfer-height-collapse', `
|
||||
0% {
|
||||
max-height: var(--n-item-height);
|
||||
}
|
||||
100% {
|
||||
max-height: 0;
|
||||
}
|
||||
`),
|
||||
c('@keyframes transfer-height-expand', `
|
||||
0% {
|
||||
max-height: 0;
|
||||
}
|
||||
100% {
|
||||
max-height: var(--n-item-height);
|
||||
}
|
||||
`)
|
||||
])
|
||||
|
||||
export default c([
|
||||
cB('transfer', `
|
||||
// --n-close-size
|
||||
// --n-close-icon-size
|
||||
// --n-close-color-hover
|
||||
// --n-close-color-pressed
|
||||
// --n-close-icon-color
|
||||
// --n-close-icon-color-hover
|
||||
// --n-close-icon-color-pressed
|
||||
export default cB('transfer', `
|
||||
width: 100%;
|
||||
font-size: var(--n-font-size);
|
||||
height: 300px;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
word-break: break-word;
|
||||
`, [
|
||||
cM('disabled', [
|
||||
cB('transfer-list', [
|
||||
cB('transfer-list-header', [
|
||||
cE('title', `
|
||||
color: var(--n-header-text-color-disabled);
|
||||
`),
|
||||
cE('extra', `
|
||||
color: var(--n-header-extra-text-color-disabled);
|
||||
`)
|
||||
])
|
||||
])
|
||||
]),
|
||||
cB('transfer-list', `
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
height: inherit;
|
||||
display: flex;
|
||||
width: var(--n-width);
|
||||
font-size: var(--n-font-size);
|
||||
height: 240px;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
flex-direction: column;
|
||||
background-clip: padding-box;
|
||||
position: relative;
|
||||
transition: background-color .3s var(--n-bezier);
|
||||
background-color: var(--n-list-color);
|
||||
`, [
|
||||
cB('transfer-icon', `
|
||||
color: var(--n-icon-color);
|
||||
transition: color .3s var(--n-bezier);
|
||||
`),
|
||||
cM('disabled', [
|
||||
cB('transfer-icon', {
|
||||
color: 'var(--n-icon-color-disabled)'
|
||||
})
|
||||
cM('source', `
|
||||
border-top-left-radius: var(--n-border-radius);
|
||||
border-bottom-left-radius: var(--n-border-radius);
|
||||
`, [
|
||||
cE('border', 'border-right: 1px solid var(--n-divider-color);')
|
||||
]),
|
||||
cB('transfer-list', `
|
||||
height: inherit;
|
||||
cM('target', `
|
||||
border-top-right-radius: var(--n-border-radius);
|
||||
border-bottom-right-radius: var(--n-border-radius);
|
||||
`, [
|
||||
cE('border', 'border-left: none;')
|
||||
]),
|
||||
cE('border', `
|
||||
padding: 0 12px;
|
||||
border: 1px solid var(--n-border-color);
|
||||
transition: border-color .3s var(--n-bezier);
|
||||
pointer-events: none;
|
||||
border-radius: inherit;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
`),
|
||||
cB('transfer-list-header', `
|
||||
min-height: var(--n-header-height);
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
padding: 12px 12px 10px 12px;
|
||||
align-items: center;
|
||||
background-clip: padding-box;
|
||||
border-radius: inherit;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
line-height: 1.5;
|
||||
transition:
|
||||
border-color .3s var(--n-bezier),
|
||||
background-color .3s var(--n-bezier);
|
||||
`, [
|
||||
c('> *:not(:first-child)', `
|
||||
margin-left: 8px;
|
||||
`),
|
||||
cE('title', `
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
line-height: 1.5;
|
||||
font-size: var(--n-header-font-size);
|
||||
font-weight: var(--n-header-font-weight);
|
||||
transition: color .3s var(--n-bezier);
|
||||
color: var(--n-header-text-color);
|
||||
`),
|
||||
cE('button', `
|
||||
position: relative;
|
||||
`),
|
||||
cE('extra', `
|
||||
transition: color .3s var(--n-bezier);
|
||||
font-size: var(--n-extra-font-size);
|
||||
margin-right: 0;
|
||||
white-space: nowrap;
|
||||
color: var(--n-header-extra-text-color);
|
||||
`)
|
||||
]),
|
||||
cB('transfer-list-body', `
|
||||
flex-basis: 0;
|
||||
flex-grow: 1;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-clip: padding-box;
|
||||
width: calc(50% - 36px);
|
||||
position: relative;
|
||||
transition: background-color .3s var(--n-bezier);
|
||||
border-radius: var(--n-border-radius);
|
||||
background-color: var(--n-list-color);
|
||||
border-radius: inherit;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
`, [
|
||||
c('&:first-child', `
|
||||
border-top-right-radius: 0!important;
|
||||
border-bottom-right-radius: 0!important;
|
||||
`),
|
||||
c('&:last-child', `
|
||||
margin-left: -1px!important;
|
||||
border-top-left-radius: 0!important;
|
||||
border-bottom-left-radius: 0!important;
|
||||
`, [
|
||||
cB('transfer-list-header', null, [
|
||||
cE('header', `
|
||||
flex: 1;
|
||||
line-height: 1;
|
||||
font-weight: var(--n-header-font-weight);
|
||||
transition: color .3s var(--n-bezier);
|
||||
color: var(--n-header-text-color);
|
||||
padding-left: 14px;
|
||||
`, [
|
||||
cM('disabled', {
|
||||
color: 'var(--n-header-text-color-disabled)'
|
||||
})
|
||||
])
|
||||
]),
|
||||
cB('transfer-list-item', null, [
|
||||
cE('label', `
|
||||
padding-left: 14px;
|
||||
`)
|
||||
])
|
||||
]),
|
||||
cE('border', `
|
||||
border: 1px solid var(--n-border-color);
|
||||
transition: border-color .3s var(--n-bezier);
|
||||
pointer-events: none;
|
||||
border-radius: inherit;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
`),
|
||||
cB('transfer-list-header', `
|
||||
height: calc(var(--n-item-height) + 4px);
|
||||
cB('transfer-filter', `
|
||||
padding: 4px 12px 8px 12px;
|
||||
box-sizing: border-box;
|
||||
display: grid;
|
||||
grid-template-areas: "button . extra";
|
||||
grid-template-columns: auto 1fr auto;
|
||||
align-items: center;
|
||||
background-clip: padding-box;
|
||||
border-radius: inherit;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
transition:
|
||||
border-color .3s var(--n-bezier),
|
||||
background-color .3s var(--n-bezier);
|
||||
`, [
|
||||
cE('button', `
|
||||
grid-area: button;
|
||||
position: relative;
|
||||
padding: 0 9px 0 14px;
|
||||
`),
|
||||
cE('extra', `
|
||||
grid-area: extra;
|
||||
transition: color .3s var(--n-bezier);
|
||||
font-size: var(--n-extra-font-size);
|
||||
margin-right: 14px;
|
||||
white-space: nowrap;
|
||||
color: var(--n-header-extra-text-color);
|
||||
`)
|
||||
]),
|
||||
cB('transfer-list-body', `
|
||||
flex-basis: 0;
|
||||
flex-grow: 1;
|
||||
box-sizing: border-box;
|
||||
`),
|
||||
cB('transfer-list-flex-container', `
|
||||
flex: 1;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: inherit;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
`, [
|
||||
cB('transfer-filter', `
|
||||
padding: 2px 8px 8px 8px;
|
||||
box-sizing: border-box;
|
||||
transition:
|
||||
border-color .3s var(--n-bezier),
|
||||
background-color .3s var(--n-bezier);
|
||||
cB('scrollbar', `
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
height: unset;
|
||||
`),
|
||||
cB('transfer-list-flex-container', `
|
||||
flex: 1;
|
||||
cB('empty', `
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translateY(-50%) translateX(-50%);
|
||||
`),
|
||||
cB('transfer-list-content', `
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
`, [
|
||||
cB('scrollbar', `
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
height: unset;
|
||||
`, [
|
||||
cB('scrollbar-content', {
|
||||
width: '100%'
|
||||
})
|
||||
]),
|
||||
cB('empty', `
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translateY(-50%) translateX(-50%);
|
||||
`),
|
||||
cB('transfer-list-content', `
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
cB('transfer-list-item', `
|
||||
padding: 0 12px;
|
||||
min-height: var(--n-item-height);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--n-item-text-color);
|
||||
position: relative;
|
||||
transition: color .3s var(--n-bezier);
|
||||
`, [
|
||||
cM('transition-disabled', [
|
||||
cB('transfer-list-item', {
|
||||
animation: 'none !important'
|
||||
})
|
||||
]),
|
||||
cB('transfer-list-item', `
|
||||
min-height: var(--n-item-height);
|
||||
display: grid;
|
||||
grid-template-areas: "checkbox label suffix";
|
||||
grid-template-columns: auto 1fr auto;
|
||||
align-items: center;
|
||||
color: var(--n-item-text-color);
|
||||
`, [
|
||||
cNotM('disabled', [
|
||||
c('&:hover', {
|
||||
backgroundColor: 'var(--n-item-color-pending)'
|
||||
})
|
||||
]),
|
||||
cE('checkbox', `
|
||||
grid-area: checkbox;
|
||||
padding: 0 9px 0 14px;
|
||||
`),
|
||||
cE('close', `
|
||||
grid-area: suffix;
|
||||
padding: 4px 14px 0 9px;
|
||||
`),
|
||||
cM('disabled', `
|
||||
cursor: not-allowed
|
||||
background-color: #0000;
|
||||
color: var(--n-item-text-color-disabled);
|
||||
`),
|
||||
cM('source', `
|
||||
cursor: pointer;
|
||||
`),
|
||||
cM('target', `
|
||||
cursor: default;
|
||||
`)
|
||||
cE('background', `
|
||||
position: absolute;
|
||||
left: 4px;
|
||||
right: 4px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
border-radius: var(--n-border-radius);
|
||||
transition: background-color .3s var(--n-bezier);
|
||||
`),
|
||||
cE('checkbox', `
|
||||
position: relative;
|
||||
margin-right: 8px;
|
||||
`),
|
||||
cE('close', `
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
position: relative;
|
||||
transition:
|
||||
opacity .3s var(--n-bezier),
|
||||
background-color .3s var(--n-bezier),
|
||||
color .3s var(--n-bezier);
|
||||
`),
|
||||
cE('label', `
|
||||
position: relative;
|
||||
min-width: 0;
|
||||
flex-grow: 1;
|
||||
`),
|
||||
cM('source', 'cursor: pointer;'),
|
||||
cM('disabled', `
|
||||
cursor: not-allowed;
|
||||
color: var(--n-item-text-color-disabled);
|
||||
`),
|
||||
cNotM('disabled', [
|
||||
c('&:hover', [
|
||||
cE('background', 'background-color: var(--n-item-color-pending);'),
|
||||
cE('close', `
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
`)
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
]),
|
||||
animation
|
||||
])
|
||||
])
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ref, computed, toRef } from 'vue'
|
||||
import { useMergedState } from 'vooks'
|
||||
import type { Option, OptionValue, Filter, CheckedStatus } from './interface'
|
||||
import type { Option, OptionValue, Filter } from './interface'
|
||||
|
||||
interface UseTransferDataProps {
|
||||
defaultValue: OptionValue[] | null
|
||||
@ -13,87 +13,91 @@ interface UseTransferDataProps {
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
export function useTransferData (props: UseTransferDataProps) {
|
||||
const uncontrolledValueRef = ref(props.defaultValue)
|
||||
const controlledValueRef = toRef(props, 'value')
|
||||
|
||||
const mergedValueRef = useMergedState(
|
||||
controlledValueRef,
|
||||
toRef(props, 'value'),
|
||||
uncontrolledValueRef
|
||||
)
|
||||
|
||||
// map 化的 options
|
||||
const optMapRef = computed(() => {
|
||||
const optionsMapRef = computed(() => {
|
||||
const map = new Map()
|
||||
;(props.options || []).forEach((opt) => map.set(opt.value, opt))
|
||||
return map as Map<OptionValue, Option>
|
||||
})
|
||||
|
||||
// set 化的 value
|
||||
const tgtValueSetRef = computed(() => new Set(mergedValueRef.value || []))
|
||||
const targetValueSetRef = computed(() => new Set(mergedValueRef.value || []))
|
||||
|
||||
// 用于展示源项列表数目
|
||||
const srcOptsRef = computed(() => props.options)
|
||||
|
||||
// 用于展示目标项列表数目
|
||||
const tgtOptsRef = computed(() => {
|
||||
const optMap = optMapRef.value
|
||||
return (mergedValueRef.value || []).map((v) => optMap.get(v)) as Option[]
|
||||
const targetOptionsRef = computed(() => {
|
||||
const optionMap = optionsMapRef.value
|
||||
return (mergedValueRef.value || []).map((v) => optionMap.get(v)) as Option[]
|
||||
})
|
||||
|
||||
// 源项过滤输入的值
|
||||
const srcPatternRef = ref('')
|
||||
|
||||
// 被过滤后的源项列表
|
||||
const filteredSrcOptsRef = computed(() => {
|
||||
const filteredSrcOptionsRef = computed(() => {
|
||||
if (!props.filterable) return props.options
|
||||
const { filter } = props
|
||||
return props.options.filter((opt) =>
|
||||
filter(srcPatternRef.value, opt, 'source')
|
||||
return props.options.filter((opt) => filter(srcPatternRef.value, opt))
|
||||
})
|
||||
|
||||
const mergedValueSetRef = computed<Set<string | number>>(() => {
|
||||
const { value } = mergedValueRef
|
||||
if (value === null) return new Set()
|
||||
return new Set(value)
|
||||
})
|
||||
|
||||
const valueSetForSelectAllRef = computed(() => {
|
||||
const mergedValueSet = mergedValueSetRef.value
|
||||
return new Set(
|
||||
filteredSrcOptionsRef.value
|
||||
.filter(
|
||||
(option) => !option.disabled || mergedValueSet.has(option.value)
|
||||
)
|
||||
.map((option) => option.value)
|
||||
)
|
||||
})
|
||||
|
||||
// 没有被禁用的源项列表
|
||||
const avlSrcValueSetRef = computed(
|
||||
const valueSetForUnselectAllRef = computed(
|
||||
() =>
|
||||
new Set(
|
||||
filteredSrcOptsRef.value
|
||||
.filter((opt) => !opt.disabled)
|
||||
.map((opt) => opt.value)
|
||||
targetOptionsRef.value
|
||||
.filter((option) => option.disabled)
|
||||
.map((option) => option.value)
|
||||
)
|
||||
)
|
||||
|
||||
// 用于头部按钮状态
|
||||
const headerBtnStatusRef = computed<CheckedStatus>(() => {
|
||||
const checkedLength = mergedValueRef.value?.length
|
||||
const avlValueCount = avlSrcValueSetRef.value.size
|
||||
return {
|
||||
checked: !!checkedLength,
|
||||
allChecked: checkedLength === avlValueCount,
|
||||
disabled: !avlValueCount
|
||||
}
|
||||
const canNotSelectAnythingRef = computed(() => {
|
||||
return filteredSrcOptionsRef.value.every((option) => option.disabled)
|
||||
})
|
||||
const isInputingRef = ref(false)
|
||||
function handleInputFocus (): void {
|
||||
isInputingRef.value = true
|
||||
}
|
||||
function handleInputBlur (): void {
|
||||
isInputingRef.value = false
|
||||
}
|
||||
|
||||
const allCheckedRef = computed(() => {
|
||||
if (!filteredSrcOptionsRef.value.length) {
|
||||
return false
|
||||
}
|
||||
const mergedValueSet = mergedValueSetRef.value
|
||||
return filteredSrcOptionsRef.value.every(
|
||||
(option) => option.disabled || mergedValueSet.has(option.value)
|
||||
)
|
||||
})
|
||||
|
||||
const canBeClearedRef = computed(() => {
|
||||
return targetOptionsRef.value.some((option) => !option.disabled)
|
||||
})
|
||||
|
||||
function handleSrcFilterUpdateValue (value: string | null): void {
|
||||
srcPatternRef.value = value ?? ''
|
||||
}
|
||||
return {
|
||||
uncontrolledValue: uncontrolledValueRef,
|
||||
mergedValue: mergedValueRef,
|
||||
tgtValueSet: tgtValueSetRef,
|
||||
avlSrcValueSet: avlSrcValueSetRef,
|
||||
tgtOpts: tgtOptsRef,
|
||||
srcOpts: srcOptsRef,
|
||||
filteredSrcOpts: filteredSrcOptsRef,
|
||||
headerBtnStatus: headerBtnStatusRef,
|
||||
srcPattern: srcPatternRef,
|
||||
isInputing: isInputingRef,
|
||||
handleInputFocus,
|
||||
handleInputBlur,
|
||||
uncontrolledValueRef,
|
||||
mergedValueRef,
|
||||
targetValueSetRef,
|
||||
valueSetForSelectAllRef,
|
||||
valueSetForUnselectAllRef,
|
||||
targetOptionsRef,
|
||||
filteredSrcOptionsRef,
|
||||
canNotSelectAnythingRef,
|
||||
canBeClearedRef,
|
||||
allCheckedRef,
|
||||
srcPatternRef,
|
||||
handleSrcFilterUpdateValue
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,13 @@
|
||||
export default {
|
||||
extraFontSize: '12px',
|
||||
width: '440px'
|
||||
extraFontSizeSmall: '12px',
|
||||
extraFontSizeMedium: '12px',
|
||||
extraFontSizeLarge: '14px',
|
||||
titleFontSizeSmall: '14px',
|
||||
titleFontSizeMedium: '16px',
|
||||
titleFontSizeLarge: '16px',
|
||||
closeSize: '20px',
|
||||
closeIconSize: '16px',
|
||||
headerHeightSmall: '44px',
|
||||
headerHeightMedium: '44px',
|
||||
headerHeightLarge: '50px'
|
||||
}
|
||||
|
@ -19,45 +19,53 @@ const transferDark: TransferTheme = {
|
||||
},
|
||||
self (vars) {
|
||||
const {
|
||||
iconColorDisabled,
|
||||
iconColor,
|
||||
fontWeight,
|
||||
fontSizeLarge,
|
||||
fontSizeMedium,
|
||||
fontSizeSmall,
|
||||
heightLarge,
|
||||
heightMedium,
|
||||
heightSmall,
|
||||
borderRadius,
|
||||
inputColor,
|
||||
tableHeaderColor,
|
||||
textColor1,
|
||||
textColorDisabled,
|
||||
textColor2,
|
||||
hoverColor
|
||||
textColor3,
|
||||
hoverColor,
|
||||
closeColorHover,
|
||||
closeColorPressed,
|
||||
closeIconColor,
|
||||
closeIconColorHover,
|
||||
closeIconColorPressed,
|
||||
dividerColor
|
||||
} = vars
|
||||
return {
|
||||
...commonVariables,
|
||||
itemHeightSmall: heightSmall,
|
||||
itemHeightSmall: heightMedium,
|
||||
itemHeightMedium: heightMedium,
|
||||
itemHeightLarge: heightLarge,
|
||||
fontSizeSmall,
|
||||
fontSizeMedium,
|
||||
fontSizeLarge,
|
||||
borderRadius,
|
||||
dividerColor,
|
||||
borderColor: '#0000',
|
||||
listColor: inputColor,
|
||||
headerColor: tableHeaderColor,
|
||||
titleTextColor: textColor1,
|
||||
titleTextColorDisabled: textColorDisabled,
|
||||
extraTextColor: textColor2,
|
||||
filterDividerColor: '#0000',
|
||||
extraTextColor: textColor3,
|
||||
extraTextColorDisabled: textColorDisabled,
|
||||
itemTextColor: textColor2,
|
||||
itemTextColorDisabled: textColorDisabled,
|
||||
itemColorPending: hoverColor,
|
||||
titleFontWeight: fontWeight,
|
||||
iconColor,
|
||||
iconColorDisabled
|
||||
closeColorHover,
|
||||
closeColorPressed,
|
||||
closeIconColor,
|
||||
closeIconColorHover,
|
||||
closeIconColorPressed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,45 +12,52 @@ import { createTheme } from '../../_mixins'
|
||||
const self = (vars: ThemeCommonVars) => {
|
||||
const {
|
||||
fontWeight,
|
||||
iconColorDisabled,
|
||||
iconColor,
|
||||
fontSizeLarge,
|
||||
fontSizeMedium,
|
||||
fontSizeSmall,
|
||||
heightLarge,
|
||||
heightMedium,
|
||||
heightSmall,
|
||||
borderRadius,
|
||||
cardColor,
|
||||
tableHeaderColor,
|
||||
textColor1,
|
||||
textColorDisabled,
|
||||
textColor2,
|
||||
textColor3,
|
||||
borderColor,
|
||||
hoverColor
|
||||
hoverColor,
|
||||
closeColorHover,
|
||||
closeColorPressed,
|
||||
closeIconColor,
|
||||
closeIconColorHover,
|
||||
closeIconColorPressed
|
||||
} = vars
|
||||
return {
|
||||
...commonVariables,
|
||||
itemHeightSmall: heightSmall,
|
||||
itemHeightSmall: heightMedium,
|
||||
itemHeightMedium: heightMedium,
|
||||
itemHeightLarge: heightLarge,
|
||||
fontSizeSmall,
|
||||
fontSizeMedium,
|
||||
fontSizeLarge,
|
||||
borderRadius,
|
||||
dividerColor: borderColor,
|
||||
borderColor,
|
||||
listColor: cardColor,
|
||||
headerColor: composite(cardColor, tableHeaderColor),
|
||||
titleTextColor: textColor1,
|
||||
titleTextColorDisabled: textColorDisabled,
|
||||
extraTextColor: textColor2,
|
||||
filterDividerColor: borderColor,
|
||||
extraTextColor: textColor3,
|
||||
extraTextColorDisabled: textColorDisabled,
|
||||
itemTextColor: textColor2,
|
||||
itemTextColorDisabled: textColorDisabled,
|
||||
itemColorPending: hoverColor,
|
||||
titleFontWeight: fontWeight,
|
||||
iconColor,
|
||||
iconColorDisabled
|
||||
closeColorHover,
|
||||
closeColorPressed,
|
||||
closeIconColor,
|
||||
closeIconColorHover,
|
||||
closeIconColorPressed
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`n-transfer should work with \`size\` prop 1`] = `"--n-bezier: cubic-bezier(.4, 0, .2, 1); --n-border-color: rgb(224, 224, 230); --n-border-radius: 3px; --n-extra-font-size: 12px; --n-font-size: 14px; --n-header-extra-text-color: rgb(51, 54, 57); --n-header-font-weight: 400; --n-header-text-color: rgb(31, 34, 37); --n-header-text-color-disabled: rgba(194, 194, 194, 1); --n-item-color-pending: rgb(243, 243, 245); --n-item-height: 28px; --n-item-text-color: rgb(51, 54, 57); --n-item-text-color-disabled: rgba(194, 194, 194, 1); --n-list-color: #fff; --n-width: 440px; --n-icon-color: rgba(194, 194, 194, 1); --n-icon-color-disabled: rgba(209, 209, 209, 1);"`;
|
||||
exports[`n-transfer should work with \`size\` prop 1`] = `"--n-bezier: cubic-bezier(.4, 0, .2, 1); --n-border-color: rgb(224, 224, 230); --n-border-radius: 3px; --n-extra-font-size: 12px; --n-font-size: 14px; --n-header-font-size: 14px; --n-header-extra-text-color: rgb(118, 124, 130); --n-header-extra-text-color-disabled: rgba(194, 194, 194, 1); --n-header-font-weight: 400; --n-header-text-color: rgb(31, 34, 37); --n-header-text-color-disabled: rgba(194, 194, 194, 1); --n-item-color-pending: rgb(243, 243, 245); --n-item-height: 34px; --n-item-text-color: rgb(51, 54, 57); --n-item-text-color-disabled: rgba(194, 194, 194, 1); --n-list-color: #fff; --n-header-height: 44px; --n-close-size: 20px; --n-close-icon-size: 16px; --n-close-color-hover: rgba(0, 0, 0, .09); --n-close-color-pressed: rgba(0, 0, 0, .13); --n-close-icon-color: rgba(102, 102, 102, 1); --n-close-icon-color-hover: rgba(102, 102, 102, 1); --n-close-icon-color-pressed: rgba(102, 102, 102, 1); --n-divider-color: rgb(224, 224, 230);"`;
|
||||
|
||||
exports[`n-transfer should work with \`size\` prop 2`] = `"--n-bezier: cubic-bezier(.4, 0, .2, 1); --n-border-color: rgb(224, 224, 230); --n-border-radius: 3px; --n-extra-font-size: 12px; --n-font-size: 14px; --n-header-extra-text-color: rgb(51, 54, 57); --n-header-font-weight: 400; --n-header-text-color: rgb(31, 34, 37); --n-header-text-color-disabled: rgba(194, 194, 194, 1); --n-item-color-pending: rgb(243, 243, 245); --n-item-height: 34px; --n-item-text-color: rgb(51, 54, 57); --n-item-text-color-disabled: rgba(194, 194, 194, 1); --n-list-color: #fff; --n-width: 440px; --n-icon-color: rgba(194, 194, 194, 1); --n-icon-color-disabled: rgba(209, 209, 209, 1);"`;
|
||||
exports[`n-transfer should work with \`size\` prop 2`] = `"--n-bezier: cubic-bezier(.4, 0, .2, 1); --n-border-color: rgb(224, 224, 230); --n-border-radius: 3px; --n-extra-font-size: 12px; --n-font-size: 14px; --n-header-font-size: 16px; --n-header-extra-text-color: rgb(118, 124, 130); --n-header-extra-text-color-disabled: rgba(194, 194, 194, 1); --n-header-font-weight: 400; --n-header-text-color: rgb(31, 34, 37); --n-header-text-color-disabled: rgba(194, 194, 194, 1); --n-item-color-pending: rgb(243, 243, 245); --n-item-height: 34px; --n-item-text-color: rgb(51, 54, 57); --n-item-text-color-disabled: rgba(194, 194, 194, 1); --n-list-color: #fff; --n-header-height: 44px; --n-close-size: 20px; --n-close-icon-size: 16px; --n-close-color-hover: rgba(0, 0, 0, .09); --n-close-color-pressed: rgba(0, 0, 0, .13); --n-close-icon-color: rgba(102, 102, 102, 1); --n-close-icon-color-hover: rgba(102, 102, 102, 1); --n-close-icon-color-pressed: rgba(102, 102, 102, 1); --n-divider-color: rgb(224, 224, 230);"`;
|
||||
|
||||
exports[`n-transfer should work with \`size\` prop 3`] = `"--n-bezier: cubic-bezier(.4, 0, .2, 1); --n-border-color: rgb(224, 224, 230); --n-border-radius: 3px; --n-extra-font-size: 12px; --n-font-size: 15px; --n-header-extra-text-color: rgb(51, 54, 57); --n-header-font-weight: 400; --n-header-text-color: rgb(31, 34, 37); --n-header-text-color-disabled: rgba(194, 194, 194, 1); --n-item-color-pending: rgb(243, 243, 245); --n-item-height: 40px; --n-item-text-color: rgb(51, 54, 57); --n-item-text-color-disabled: rgba(194, 194, 194, 1); --n-list-color: #fff; --n-width: 440px; --n-icon-color: rgba(194, 194, 194, 1); --n-icon-color-disabled: rgba(209, 209, 209, 1);"`;
|
||||
exports[`n-transfer should work with \`size\` prop 3`] = `"--n-bezier: cubic-bezier(.4, 0, .2, 1); --n-border-color: rgb(224, 224, 230); --n-border-radius: 3px; --n-extra-font-size: 14px; --n-font-size: 15px; --n-header-font-size: 16px; --n-header-extra-text-color: rgb(118, 124, 130); --n-header-extra-text-color-disabled: rgba(194, 194, 194, 1); --n-header-font-weight: 400; --n-header-text-color: rgb(31, 34, 37); --n-header-text-color-disabled: rgba(194, 194, 194, 1); --n-item-color-pending: rgb(243, 243, 245); --n-item-height: 40px; --n-item-text-color: rgb(51, 54, 57); --n-item-text-color-disabled: rgba(194, 194, 194, 1); --n-list-color: #fff; --n-header-height: 50px; --n-close-size: 20px; --n-close-icon-size: 16px; --n-close-color-hover: rgba(0, 0, 0, .09); --n-close-color-pressed: rgba(0, 0, 0, .13); --n-close-icon-color: rgba(102, 102, 102, 1); --n-close-icon-color-hover: rgba(102, 102, 102, 1); --n-close-icon-color-pressed: rgba(102, 102, 102, 1); --n-divider-color: rgb(224, 224, 230);"`;
|
||||
|
1
volar.d.ts
vendored
1
volar.d.ts
vendored
@ -139,6 +139,7 @@ declare module 'vue' {
|
||||
NUploadFileList: typeof import('naive-ui')['NUploadFileList']
|
||||
NUploadTrigger: typeof import('naive-ui')['NUploadTrigger']
|
||||
NWatermark: typeof import('naive-ui')['NWatermark']
|
||||
NLegacyTransfer: typeof import('naive-ui')['NLegacyTransfer']
|
||||
}
|
||||
}
|
||||
export {}
|
||||
|
Loading…
x
Reference in New Issue
Block a user