mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-01-18 12:34:25 +08:00
refactor(select): empty status & data utils
This commit is contained in:
parent
554052e1fe
commit
3b9e318887
@ -6,6 +6,7 @@
|
||||
'n-base-select-menu--multiple': multiple,
|
||||
[`n-${theme}-theme`]: theme
|
||||
}"
|
||||
|
||||
:style="{
|
||||
width: width && (width + 'px')
|
||||
}"
|
||||
@ -14,6 +15,7 @@
|
||||
@mousedown.prevent="() => {}"
|
||||
>
|
||||
<n-scrollbar
|
||||
v-show="!empty"
|
||||
ref="scrollbar"
|
||||
:theme="theme"
|
||||
:without-scrollbar="withoutScrollbar"
|
||||
@ -22,7 +24,7 @@
|
||||
@scroll="handleMenuScroll"
|
||||
>
|
||||
<div class="n-base-select-menu-option-wrapper">
|
||||
<template v-if="!loading">
|
||||
<template v-show="empty">
|
||||
<recycle-scroller
|
||||
ref="virtualScroller"
|
||||
class="n-virtual-scroller"
|
||||
@ -54,39 +56,30 @@
|
||||
</div>
|
||||
</n-scrollbar>
|
||||
<div
|
||||
v-if="loading"
|
||||
class="n-base-select-option n-base-select-option--loading"
|
||||
v-if="empty"
|
||||
style="padding: 14px 0;"
|
||||
>
|
||||
loading
|
||||
</div>
|
||||
<div
|
||||
v-else-if="noData"
|
||||
class="n-base-select-option n-base-select-option--no-data"
|
||||
>
|
||||
{{ noDataContent }}
|
||||
</div>
|
||||
<div
|
||||
v-else-if="notFound"
|
||||
class="n-base-select-option n-base-select-option--not-found"
|
||||
>
|
||||
{{ notFoundContent }}
|
||||
<slot name="empty">
|
||||
<n-empty description="No Data" />
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import NScrollbar from '../../../common/Scrollbar'
|
||||
import NSelectOption from './SelectOption.vue'
|
||||
import NSelectGroupHeader from './SelectGroupHeader.vue'
|
||||
import NBaseLightBar from '../../LightBar'
|
||||
import NEmpty from '../../../common/Empty'
|
||||
import { RecycleScroller } from 'vue-virtual-scroller'
|
||||
import debounce from 'lodash-es/debounce'
|
||||
import {
|
||||
getPrevAvailableIndex,
|
||||
getNextAvailableIndex,
|
||||
flattenOptions,
|
||||
OPTION_TYPE
|
||||
} from '../../../utils/data/flattenedOptions'
|
||||
import NSelectOption from './SelectOption.vue'
|
||||
import NSelectGroupHeader from './SelectGroupHeader.vue'
|
||||
import NBaseLightBar from '../../LightBar'
|
||||
import debounce from 'lodash-es/debounce'
|
||||
import { RecycleScroller } from 'vue-virtual-scroller'
|
||||
} from '../../../utils/component/select'
|
||||
|
||||
export default {
|
||||
name: 'NBaseSelectMenu',
|
||||
@ -99,6 +92,7 @@ export default {
|
||||
NScrollbar,
|
||||
NBaseLightBar,
|
||||
NSelectOption,
|
||||
NEmpty,
|
||||
NSelectGroupHeader,
|
||||
RecycleScroller
|
||||
},
|
||||
@ -131,10 +125,6 @@ export default {
|
||||
type: String,
|
||||
default: 'default'
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
pattern: {
|
||||
type: String,
|
||||
default: null
|
||||
@ -155,14 +145,6 @@ export default {
|
||||
emitOption: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
noDataContent: {
|
||||
type: [String, Function],
|
||||
default: 'no data'
|
||||
},
|
||||
notFoundContent: {
|
||||
type: [String, Function],
|
||||
default: 'none result matched'
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@ -182,11 +164,9 @@ export default {
|
||||
const flattenedOptions = flattenOptions(this.options)
|
||||
return flattenedOptions
|
||||
},
|
||||
notFound () {
|
||||
return this.filterable && (this.pattern.length && !this.flattenedOptions.length)
|
||||
},
|
||||
noData () {
|
||||
return this.flattenedOptions && this.flattenedOptions.length === 0
|
||||
empty () {
|
||||
const flattenedOptions = this.flattenedOptions
|
||||
return flattenedOptions && flattenedOptions.length === 0
|
||||
},
|
||||
itemSize () {
|
||||
return ({
|
||||
@ -197,17 +177,7 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
notFound (value) {
|
||||
if (value) {
|
||||
this.hideLightBar(0)
|
||||
}
|
||||
},
|
||||
noData (value) {
|
||||
if (value) {
|
||||
this.hideLightBar(0)
|
||||
}
|
||||
},
|
||||
loading (value) {
|
||||
empty (value) {
|
||||
if (value) {
|
||||
this.hideLightBar(0)
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
export const createValueAttribute = function createValueAttribute (value) {
|
||||
if (typeof value === 'string') {
|
||||
return 's-' + value
|
||||
} else if (typeof value === 'number') {
|
||||
return 'd-' + String(value)
|
||||
} else {
|
||||
console.error(['[naive-ui/select-option]: option value is neither string or number'])
|
||||
return 'invalid'
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
:style="synthesizedStyle"
|
||||
>
|
||||
<div class="n-empty__icon">
|
||||
<empty-icon />
|
||||
<ios-remove-circle-outline />
|
||||
</div>
|
||||
<div v-if="showDescription" class="n-empty__description">
|
||||
<slot>
|
||||
@ -21,14 +21,14 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EmptyIcon from './EmptyIcon'
|
||||
import withapp from '../../../mixins/withapp'
|
||||
import themeable from '../../../mixins/themeable'
|
||||
import iosRemoveCircleOutline from '../../../icons/ios-remove-circle-outline'
|
||||
|
||||
export default {
|
||||
name: 'NEmpty',
|
||||
components: {
|
||||
EmptyIcon
|
||||
iosRemoveCircleOutline
|
||||
},
|
||||
mixins: [ withapp, themeable ],
|
||||
props: {
|
||||
|
@ -1,10 +1,8 @@
|
||||
/* istanbul ignore file */
|
||||
import Select from './src/Select.vue'
|
||||
import SelectOption from './src/SelectOption.vue'
|
||||
|
||||
Select.install = function (Vue) {
|
||||
Vue.component(Select.name, Select)
|
||||
Vue.component('NSelectOption', SelectOption)
|
||||
}
|
||||
|
||||
export default Select
|
||||
|
@ -31,6 +31,7 @@
|
||||
:disabled="disabled"
|
||||
:size="size"
|
||||
:theme="synthesizedTheme"
|
||||
:loading="loading"
|
||||
@click="handleActivatorClick"
|
||||
@delete-last-option="handleDeleteLastOption"
|
||||
@delete-option="handleToggleOption"
|
||||
@ -64,16 +65,23 @@
|
||||
:options="filteredOptions"
|
||||
:multiple="multiple"
|
||||
:size="size"
|
||||
:loading="loading"
|
||||
:no-data-content="noDataContent"
|
||||
:not-found-content="notFoundContent"
|
||||
:filterable="filterable"
|
||||
:is-option-selected="isOptionSelected"
|
||||
:mirror="false"
|
||||
@menu-toggle-option="handleToggleOption"
|
||||
@menu-scroll="handleMenuScroll"
|
||||
@menu-visible="handleMenuVisible"
|
||||
/>
|
||||
>
|
||||
<template v-if="$slots.empty" v-slot:empty>
|
||||
<slot name="empty" />
|
||||
</template>
|
||||
<template v-if="$slots.unmatch" v-slot:unmatch>
|
||||
<slot name="unmatch" />
|
||||
</template>
|
||||
<template v-if="$slots.action" v-slot:action>
|
||||
<slot name="action" />
|
||||
</template>
|
||||
</n-base-select-menu>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
@ -91,7 +99,7 @@ import {
|
||||
import {
|
||||
filterOptions,
|
||||
valueToOptionMap
|
||||
} from '../../../utils/data/flattenedOptions'
|
||||
} from '../../../utils/component/select'
|
||||
import NBasePicker from '../../../base/Picker'
|
||||
import withapp from '../../../mixins/withapp'
|
||||
import themeable from '../../../mixins/themeable'
|
||||
@ -193,14 +201,6 @@ export default {
|
||||
items: {
|
||||
type: Array,
|
||||
default: undefined
|
||||
},
|
||||
noDataContent: {
|
||||
type: [String, Function],
|
||||
default: 'No Data'
|
||||
},
|
||||
notFoundContent: {
|
||||
type: [String, Function],
|
||||
default: 'No Result'
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@ -208,8 +208,7 @@ export default {
|
||||
active: false,
|
||||
scrolling: false,
|
||||
pattern: '',
|
||||
memorizedValueToOptionMap: new Map(),
|
||||
disablePlaceableTracingWhenActive: true
|
||||
memorizedValueToOptionMap: new Map()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -273,7 +272,6 @@ export default {
|
||||
methods: {
|
||||
activate () {
|
||||
this.active = true
|
||||
this.disablePlaceableTracingWhenActive = true
|
||||
},
|
||||
deactivate () {
|
||||
this.active = false
|
||||
@ -442,7 +440,6 @@ export default {
|
||||
}
|
||||
},
|
||||
handleMenuVisible () {
|
||||
this.disablePlaceableTracingWhenActive = false
|
||||
this.updatePosition()
|
||||
},
|
||||
/**
|
||||
|
@ -1,5 +0,0 @@
|
||||
<script>
|
||||
import NBaseSelectOption from '../../../base/SelectMenu/src/SelectOption.vue'
|
||||
|
||||
export default NBaseSelectOption
|
||||
</script>
|
@ -86,17 +86,6 @@
|
||||
}
|
||||
cursor: not-allowed;
|
||||
}
|
||||
@include m(no-data) {
|
||||
color: map-get($map: $--base-select-menu-option-color, $key: "disabled");
|
||||
text-align: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
@include m(not-found) {
|
||||
color: map-get($map: $--base-select-menu-option-color, $key: "disabled");
|
||||
text-align: center;
|
||||
pointer-events: none;
|
||||
|
||||
}
|
||||
@include m(loading) {
|
||||
color: map-get($map: $--base-select-menu-option-color, $key: "disabled");
|
||||
text-align: center;
|
||||
|
@ -10,20 +10,22 @@
|
||||
@include e(icon) {
|
||||
@include once {
|
||||
transition: fill .3s $--n-ease-in-out-cubic-bezier;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
fill: $--empty-icon-fill;
|
||||
}
|
||||
@include e(description) {
|
||||
@include once {
|
||||
margin-top: 8px;
|
||||
font-size: 14px;
|
||||
margin-top: 4px;
|
||||
transition: color .3s $--n-ease-in-out-cubic-bezier;
|
||||
}
|
||||
color: $--empty-text-color;
|
||||
}
|
||||
@include e(extra) {
|
||||
@include once {
|
||||
font-size: 14px;;
|
||||
text-align: center;
|
||||
transition: color .3s $--n-ease-in-out-cubic-bezier;
|
||||
margin-top: 16px;
|
||||
|
Loading…
Reference in New Issue
Block a user