refactor(base-select-menu): ts

This commit is contained in:
07akioni 2021-01-19 18:38:05 +08:00
parent 9e095c1a6a
commit 5faf1a8870
16 changed files with 514 additions and 419 deletions

View File

@ -1,2 +0,0 @@
/* istanbul ignore file */
export { default } from './src/SelectMenu.vue'

View File

@ -0,0 +1,2 @@
/* istanbul ignore file */
export { default } from './src/SelectMenu'

View File

@ -1,10 +1,11 @@
import { h, defineComponent } from 'vue'
import { h, defineComponent, PropType } from 'vue'
import { TreeNode } from 'treemate'
export default defineComponent({
name: 'NBaseSelectGroupHeader',
props: {
tmNode: {
type: Object,
type: Object as PropType<TreeNode>,
required: true
}
},

View File

@ -0,0 +1,387 @@
import {
h,
ref,
onMounted,
computed,
defineComponent,
PropType,
watch,
toRef,
renderSlot,
VNode,
provide,
reactive
} from 'vue'
import { RawNode, TreeMate, TreeNode } from 'treemate'
import { VirtualList, VirtualListRef } from 'vueuc'
import { depx, getPadding } from 'seemly'
import { NEmpty } from '../../../empty'
import { NScrollbar } from '../../../scrollbar'
import type { ScrollbarRef } from '../../../scrollbar'
import { formatLength } from '../../../_utils'
import { createKey } from '../../../_utils/cssr'
import { useTheme } from '../../../_mixins'
import type { ThemeProps } from '../../../_mixins'
import NSelectOption from './SelectOption'
import NSelectGroupHeader from './SelectGroupHeader'
import style from './styles/index.cssr'
import { baseSelectMenuLight, BaseSelectMenuTheme } from '../styles'
export interface BaseSelectMenuInjection {
handleOptionMouseEnter: (e: MouseEvent, tmNode: TreeNode) => void
handleOptionClick: (e: MouseEvent, tmNode: TreeNode) => void
valueSet: Set<number | string>
pendingTmNode: TreeNode | null
multiple: boolean
value: string | number | Array<string | number> | null
}
export interface BaseSelectMenuRef {
getPendingOption: () => TreeNode | null
}
export default defineComponent({
name: 'BaseSelectMenu',
props: {
...(useTheme.props as ThemeProps<BaseSelectMenuTheme>),
scrollable: {
type: Boolean,
default: true
},
treeMate: {
type: Object as PropType<TreeMate>,
required: true
},
multiple: {
type: Boolean,
default: false
},
size: {
type: String as PropType<'small' | 'medium' | 'large'>,
default: 'medium'
},
pattern: {
type: String,
default: undefined
},
value: {
type: [String, Number, Array] as PropType<
string | number | null | Array<string | number>
>,
default: null
},
width: {
type: [Number, String],
default: undefined
},
autoPending: {
type: Boolean,
default: false
},
virtualScroll: {
type: Boolean,
default: true
},
onScroll: {
type: Function as PropType<((e: Event) => void) | undefined>,
default: undefined
},
// deprecated
onMenuToggleOption: {
type: Function,
default: undefined
}
},
setup (props) {
const themeRef = useTheme(
'BaseSelectMenu',
'BaseSelectMenu',
style,
baseSelectMenuLight,
props
)
const virtualListRef = ref<VirtualListRef | null>(null)
const scrollbarRef = ref<ScrollbarRef | null>(null)
const { treeMate } = props
const pendingNodeRef = ref(
props.autoPending
? props.value === null
? treeMate.getFirstAvailableNode()
: props.multiple
? treeMate.getNode(
((props.value as Array<string | number> | null) || [])[
((props.value as Array<string | number> | null) || []).length -
1
]
) || treeMate.getFirstAvailableNode()
: treeMate.getNode(props.value as string | number) ||
treeMate.getFirstAvailableNode()
: null
)
const itemSizeRef = computed(() => {
return depx(themeRef.value.self[createKey('optionHeight', props.size)])
})
const paddingRef = computed(() => {
return getPadding(themeRef.value.self[createKey('padding', props.size)])
})
const valueSetRef = computed(() => {
if (props.multiple && Array.isArray(props.value)) {
return new Set(props.value)
}
return new Set<string | number>()
})
const emptyRef = computed(() => {
const tmNodes = props.treeMate.flattenedNodes
return tmNodes && tmNodes.length === 0
})
const styleRef = computed(() => {
return [{ width: formatLength(props.width) }, cssVarsRef.value]
})
const tmNodesRef = computed(() => {
return props.treeMate.treeNodes
})
watch(toRef(props, 'treeMate'), () => {
if (props.autoPending) {
const tmNode = props.treeMate.getFirstAvailableNode()
setPendingTmNode(tmNode)
} else {
setPendingTmNode(null)
}
})
function doToggleOption (option: RawNode): void {
const { onMenuToggleOption } = props
if (onMenuToggleOption) onMenuToggleOption(option)
}
function doScroll (e: Event): void {
const { onScroll } = props
if (onScroll) onScroll(e)
}
// required, scroller sync need to be triggered manually
function handleVirtualListScroll (e: Event): void {
scrollbarRef.value?.sync()
doScroll(e)
}
function handleVirtualListResize (): void {
scrollbarRef.value?.sync()
}
function getPendingOption (): RawNode | null {
const { value: pendingTmNode } = pendingNodeRef
if (pendingTmNode) return pendingTmNode.rawNode
return null
}
function handleOptionMouseEnter (e: MouseEvent, tmNode: TreeNode): void {
if (tmNode.disabled) return
setPendingTmNode(tmNode, false)
}
function handleOptionClick (e: MouseEvent, tmNode: TreeNode): void {
if (tmNode.disabled) return
doToggleOption(tmNode.rawNode)
}
// keyboard related methods
function handleKeyUp (e: KeyboardEvent): void {
switch (e.code) {
case 'ArrowUp':
prev()
break
case 'ArrowDown':
next()
break
}
}
function handleMouseDown (e: MouseEvent): void {
e.preventDefault()
}
function next (): void {
const { value: pendingTmNode } = pendingNodeRef
if (pendingTmNode) {
setPendingTmNode(pendingTmNode.getNext({ loop: true }), true)
}
}
function prev (): void {
const { value: pendingTmNode } = pendingNodeRef
if (pendingTmNode) {
setPendingTmNode(pendingTmNode.getPrev({ loop: true }), true)
}
}
function setPendingTmNode (tmNode: TreeNode | null, doScroll = false): void {
pendingNodeRef.value = tmNode
if (doScroll && tmNode) {
if (props.virtualScroll) {
virtualListRef.value?.scrollTo({ index: tmNode.fIndex })
} else {
scrollbarRef.value?.scrollTo({
index: tmNode.fIndex,
elSize: itemSizeRef.value
})
}
}
}
provide<BaseSelectMenuInjection>(
'NBaseSelectMenu',
reactive({
handleOptionMouseEnter,
handleOptionClick,
valueSet: valueSetRef,
multiple: toRef(props, 'multiple'),
value: toRef(props, 'value'),
pendingTmNode: pendingNodeRef
})
)
onMounted(() => {
const { value } = scrollbarRef
if (value) value.sync()
})
const cssVarsRef = computed(() => {
const { size } = props
const {
common: { cubicBezierEaseInOut },
self: {
borderRadius,
color,
boxShadow,
groupHeaderTextColor,
actionDividerColor,
optionTextColorPressed,
optionTextColor,
optionTextColorDisabled,
optionTextColorActive,
optionOpacityDisabled,
optionCheckColor,
actionTextColor,
optionColorPending,
[createKey('optionFontSize', size)]: fontSize,
[createKey('optionHeight', size)]: optionHeight
}
} = themeRef.value
return {
'--action-divider-color': actionDividerColor,
'--action-text-color': actionTextColor,
'--bezier': cubicBezierEaseInOut,
'--border-radius': borderRadius,
'--box-shadow': boxShadow,
'--color': color,
'--option-font-size': fontSize,
'--group-header-text-color': groupHeaderTextColor,
'--option-check-color': optionCheckColor,
'--option-color-pending': optionColorPending,
'--option-height': optionHeight,
'--option-opacity-disabled': optionOpacityDisabled,
'--option-text-color': optionTextColor,
'--option-text-color-active': optionTextColorActive,
'--option-text-color-disabled': optionTextColorDisabled,
'--option-text-color-pressed': optionTextColorPressed
}
})
return {
virtualListRef,
scrollbarRef,
style: styleRef,
defaultScrollIndex: pendingNodeRef.value?.fIndex,
itemSize: itemSizeRef,
padding: paddingRef,
tmNodes: tmNodesRef,
empty: emptyRef,
next,
prev,
virtualListContainer () {
const { value } = virtualListRef
return value?.listRef as HTMLElement
},
virtualListContent () {
const { value } = virtualListRef
return value?.itemsRef as HTMLElement
},
doScroll,
handleKeyUp,
handleMouseDown,
handleVirtualListResize,
handleVirtualListScroll,
getPendingOption
}
},
render () {
const { $slots, virtualScroll } = this
return (
<div
class={[
'n-base-select-menu',
{
'n-base-select-menu--multiple': this.multiple
}
]}
style={this.style as any}
onKeyup={this.handleKeyUp}
onMousedown={this.handleMouseDown}
>
{!this.empty ? (
<NScrollbar
ref="scrollbarRef"
scrollable={this.scrollable}
container={virtualScroll ? this.virtualListContainer : undefined}
content={virtualScroll ? this.virtualListContent : undefined}
onScroll={this.doScroll}
>
{{
default: () => {
return virtualScroll ? (
<VirtualList
ref="virtualListRef"
class="n-virtual-list"
items={this.tmNodes}
itemSize={this.itemSize}
showScrollbar={false}
defaultScrollIndex={this.defaultScrollIndex}
paddingTop={this.padding.top}
paddingBottom={this.padding.bottom}
onResize={this.handleVirtualListResize}
onScroll={this.handleVirtualListScroll}
>
{{
default: ({ item: tmNode }: { item: TreeNode }) => {
return tmNode.rawNode.type === 'group' ? (
<NSelectGroupHeader
key={tmNode.key}
tmNode={tmNode}
/>
) : (
<NSelectOption key={tmNode.key} tmNode={tmNode} />
)
}
}}
</VirtualList>
) : (
<div
class="n-base-select-menu-option-wrapper"
style={{
paddingTop: this.padding.top,
paddingBottom: this.padding.bottom
}}
>
{this.tmNodes.map((tmNode) =>
tmNode.rawNode.type === 'group' ? (
<NSelectGroupHeader key={tmNode.key} tmNode={tmNode} />
) : (
<NSelectOption key={tmNode.key} tmNode={tmNode} />
)
)}
</div>
)
}
}}
</NScrollbar>
) : (
<div style="padding: 14px 0; width: 100%">
{renderSlot($slots, 'empty', undefined, () => [
(<NEmpty />) as VNode
])}
</div>
)}
{$slots.action && (
<div class="n-base-select-menu__action">
{renderSlot($slots, 'action')}
</div>
)}
</div>
)
}
})

View File

@ -1,327 +0,0 @@
<template>
<div
class="n-base-select-menu"
:class="{
'n-base-select-menu--multiple': multiple
}"
:style="style"
@keyup.up.stop="handleKeyUpUp"
@keyup.down.stop="handleKeyUpDown"
@mousedown.prevent
>
<n-scrollbar
v-if="!empty"
ref="scrollbarRef"
:scrollable="scrollable"
:container="virtualScroll ? virtualListContainer : undefined"
:content="virtualScroll ? virtualListContent : undefined"
@scroll="doScroll"
>
<virtual-list
v-if="virtualScroll"
ref="virtualListRef"
class="n-virtual-list"
:items="tmNodes"
:item-size="itemSize"
:show-scrollbar="false"
:default-scroll-index="defaultScrollIndex"
:padding-top="padding.top"
:padding-bottom="padding.bottom"
@resize="handleVirtualListResize"
@scroll="handleVirtualListScroll"
>
<template #default="{ item: tmNode }">
<n-select-group-header
v-if="tmNode.rawNode.type === 'group'"
:key="tmNode.key"
:tm-node="tmNode"
/>
<n-select-option v-else :key="tmNode.key" :tm-node="tmNode" />
</template>
</virtual-list>
<div
v-else
class="n-base-select-menu-option-wrapper"
:style="{
paddingTop: padding.top,
paddingBottom: padding.bottom
}"
>
<template v-for="tmNode in tmNodes">
<n-select-group-header
v-if="tmNode.rawNode.type === 'group'"
:key="tmNode.key"
:tm-node="tmNode"
/>
<n-select-option v-else :key="tmNode.key" :tm-node="tmNode" />
</template>
</div>
</n-scrollbar>
<div v-else style="padding: 14px 0; width: 100%">
<slot name="empty">
<n-empty />
</slot>
</div>
<div v-if="$slots.action" class="n-base-select-menu__action">
<slot name="action" />
</div>
</div>
</template>
<script>
import { ref, onMounted, computed, defineComponent } from 'vue'
import { VirtualList } from 'vueuc'
import { depx, getPadding } from 'seemly'
import { NEmpty } from '../../../empty'
import { NScrollbar } from '../../../scrollbar'
import { formatLength } from '../../../_utils'
import { createKey } from '../../../_utils/cssr'
import { useTheme } from '../../../_mixins'
import NSelectOption from './SelectOption.js'
import NSelectGroupHeader from './SelectGroupHeader.js'
import style from './styles/index.cssr.js'
import { baseSelectMenuLight } from '../styles'
export default defineComponent({
name: 'BaseSelectMenu',
components: {
VirtualList,
NScrollbar,
NSelectOption,
NEmpty,
NSelectGroupHeader
},
provide () {
return {
NBaseSelectMenu: this
}
},
props: {
...useTheme.props,
scrollable: {
type: Boolean,
default: true
},
treeMate: {
type: Object,
required: true
},
multiple: {
type: Boolean,
default: false
},
size: {
type: String,
default: 'medium'
},
pattern: {
type: String,
default: undefined
},
value: {
type: [String, Number, Array],
default: null
},
width: {
type: [Number, String],
default: undefined
},
autoPending: {
type: Boolean,
default: false
},
virtualScroll: {
type: Boolean,
default: true
},
onScroll: {
type: Function,
default: undefined
},
// deprecated
onMenuToggleOption: {
type: Function,
default: undefined
}
},
setup (props) {
const themeRef = useTheme(
'BaseSelectMenu',
'BaseSelectMenu',
style,
baseSelectMenuLight,
props
)
const virtualListRef = ref(null)
const scrollbarRef = ref(null)
const { treeMate } = props
const pendingNodeRef = ref(
props.autoPending
? props.value === null
? treeMate.getFirstAvailableNode()
: props.multiple
? treeMate.getNode(
(props.value || [])[(props.value || []).length - 1]
) || treeMate.getFirstAvailableNode()
: treeMate.getNode(props.value) || treeMate.getFirstAvailableNode()
: null
)
const itemSizeRef = computed(() => {
return depx(themeRef.value.self[createKey('optionHeight', props.size)])
})
const paddingRef = computed(() => {
return getPadding(themeRef.value.self[createKey('padding', props.size)])
})
onMounted(() => {
const { value } = scrollbarRef
if (value) value.sync()
})
return {
tmNodes: computed(() => props.treeMate.flattenedNodes),
virtualListRef,
scrollbarRef,
virtualListContainer () {
const { value } = virtualListRef
return value && value.listRef
},
virtualListContent () {
const { value } = virtualListRef
return value && value.itemsRef
},
pendingTmNode: pendingNodeRef,
defaultScrollIndex: pendingNodeRef.value?.fIndex,
itemSize: itemSizeRef,
padding: paddingRef,
cssVars: computed(() => {
const { size } = props
const {
common: { cubicBezierEaseInOut },
self: {
borderRadius,
color,
boxShadow,
groupHeaderTextColor,
actionDividerColor,
optionTextColorPressed,
optionTextColor,
optionTextColorDisabled,
optionTextColorActive,
optionOpacityDisabled,
optionCheckColor,
actionTextColor,
optionColorPending,
[createKey('optionFontSize', size)]: fontSize,
[createKey('optionHeight', size)]: optionHeight
}
} = themeRef.value
return {
'--action-divider-color': actionDividerColor,
'--action-text-color': actionTextColor,
'--bezier': cubicBezierEaseInOut,
'--border-radius': borderRadius,
'--box-shadow': boxShadow,
'--color': color,
'--option-font-size': fontSize,
'--group-header-text-color': groupHeaderTextColor,
'--option-check-color': optionCheckColor,
'--option-color-pending': optionColorPending,
'--option-height': optionHeight,
'--option-opacity-disabled': optionOpacityDisabled,
'--option-text-color': optionTextColor,
'--option-text-color-active': optionTextColorActive,
'--option-text-color-disabled': optionTextColorDisabled,
'--option-text-color-pressed': optionTextColorPressed
}
})
}
},
computed: {
valueSet () {
if (this.multiple && Array.isArray(this.value)) return new Set(this.value)
return null
},
empty () {
const { tmNodes } = this
return tmNodes && tmNodes.length === 0
},
style () {
return {
width: formatLength(this.width),
...this.cssVars
}
}
},
watch: {
treeMate (value) {
if (this.autoPending) {
const tmNode = this.treeMate.getFirstAvailableNode()
this.setPendingTmNode(tmNode)
} else {
this.setPendingTmNode(null)
}
}
},
methods: {
doToggleOption (option) {
const { onMenuToggleOption } = this
if (onMenuToggleOption) onMenuToggleOption(option)
},
doScroll (e) {
const { onScroll } = this
if (onScroll) onScroll(e)
},
// required, scroller sync need to be triggered manually
handleVirtualListScroll (e) {
this.scrollbarRef.sync()
this.doScroll(e)
},
handleVirtualListResize () {
this.scrollbarRef.sync()
},
getPendingOption () {
const { pendingTmNode } = this
return pendingTmNode && pendingTmNode.rawNode
},
handleOptionMouseEnter (e, tmNode) {
if (tmNode.disabled) return
this.setPendingTmNode(tmNode, false)
},
handleOptionClick (e, tmNode) {
if (tmNode.disabled) return
this.doToggleOption(tmNode.rawNode)
},
// keyboard related methods
handleKeyUpUp () {
this.prev()
},
handleKeyUpDown () {
this.next()
},
next () {
const { pendingTmNode } = this
if (pendingTmNode) {
this.setPendingTmNode(pendingTmNode.getNext({ loop: true }), true)
}
},
prev () {
const { pendingTmNode } = this
if (pendingTmNode) {
this.setPendingTmNode(pendingTmNode.getPrev({ loop: true }), true)
}
},
setPendingTmNode (tmNode, doScroll = false) {
this.pendingTmNode = tmNode
if (doScroll) {
if (this.virtualScroll) {
this.virtualListRef.scrollTo({ index: tmNode.fIndex })
} else {
this.scrollbarRef.scrollTo({
index: tmNode.fIndex,
elSize: this.itemSize
})
}
}
}
}
})
</script>

View File

@ -1,4 +1,14 @@
import { h, inject, toRef, defineComponent, Transition } from 'vue'
import {
h,
inject,
toRef,
defineComponent,
Transition,
PropType,
VNode
} from 'vue'
import { BaseSelectMenuInjection } from './SelectMenu'
import { TreeNode } from 'treemate'
import { useMemo } from 'vooks'
import { CheckmarkIcon } from '../../icons'
import NBaseIcon from '../../icon'
@ -7,7 +17,7 @@ const checkMark = h(NBaseIcon, null, {
default: () => h(CheckmarkIcon)
})
function renderCheckMark (show) {
function renderCheckMark (show: boolean): VNode {
return h(
Transition,
{
@ -22,20 +32,38 @@ function renderCheckMark (show) {
export default defineComponent({
name: 'NBaseSelectOption',
inject: {
NBaseSelectMenu: {
default: null
}
},
props: {
tmNode: {
type: Object,
type: Object as PropType<TreeNode>,
required: true
}
},
setup (props) {
const NBaseSelectMenu = inject('NBaseSelectMenu')
const NBaseSelectMenu = inject<BaseSelectMenuInjection>(
'NBaseSelectMenu'
) as BaseSelectMenuInjection
const rawNodeRef = toRef(props.tmNode, 'rawNode')
const isPendingRef = useMemo(() => {
const { pendingTmNode } = NBaseSelectMenu
if (!pendingTmNode) return false
return props.tmNode.key === pendingTmNode.key
})
function handleClick (e: MouseEvent): void {
const { tmNode } = props
if (tmNode.disabled) return
NBaseSelectMenu.handleOptionClick(e, tmNode)
}
function handleMouseEnter (e: MouseEvent): void {
const { tmNode } = props
if (tmNode.disabled) return
NBaseSelectMenu.handleOptionMouseEnter(e, tmNode)
}
function handleMouseMove (e: MouseEvent): void {
const { tmNode } = props
const { value: isPending } = isPendingRef
if (tmNode.disabled || isPending) return
NBaseSelectMenu.handleOptionMouseEnter(e, tmNode)
}
return {
NBaseSelectMenu,
rawNode: rawNodeRef,
@ -44,11 +72,7 @@ export default defineComponent({
const { parent } = tmNode
return parent && parent.rawNode.type === 'group'
}),
isPending: useMemo(() => {
const { pendingTmNode } = NBaseSelectMenu
if (!pendingTmNode) return false
return props.tmNode.key === pendingTmNode.key
}),
isPending: isPendingRef,
isSelected: useMemo(() => {
const { multiple, value } = NBaseSelectMenu
if (value === null) return false
@ -59,24 +83,10 @@ export default defineComponent({
} else {
return value === optionValue
}
})
}
},
methods: {
handleClick (e) {
const { tmNode } = this
if (tmNode.disabled) return
this.NBaseSelectMenu.handleOptionClick(e, tmNode)
},
handleMouseEnter (e) {
const { tmNode } = this
if (tmNode.disabled) return
this.NBaseSelectMenu.handleOptionMouseEnter(e, tmNode)
},
handleMouseMove (e) {
const { tmNode, isPending } = this
if (tmNode.disabled || isPending) return
this.NBaseSelectMenu.handleOptionMouseEnter(e, tmNode)
}),
handleMouseMove,
handleMouseEnter,
handleClick
}
},
render () {
@ -90,7 +100,7 @@ export default defineComponent({
handleMouseMove,
NBaseSelectMenu: { multiple }
} = this
const showCheckMark = multiple & isSelected
const showCheckMark = multiple && isSelected
const children = rawNode.render
? [rawNode.render(rawNode, isSelected), renderCheckMark(showCheckMark)]
: [rawNode.label, renderCheckMark(showCheckMark)]

View File

@ -96,7 +96,7 @@ export default cB('base-select-menu', `
transition: color .3s var(--bezier);
`, [
fadeInScaleUpTransition({
enterScale: 0.5
enterScale: '0.5'
})
])
]),

View File

@ -2,15 +2,16 @@ import { emptyDark } from '../../../empty/styles'
import { scrollbarDark } from '../../../scrollbar/styles'
import { commonDark } from '../../../_styles/new-common'
import commonVariables from './_common'
import type { BaseSelectMenuTheme } from './light'
export default {
const baseSelectMenuDark: BaseSelectMenuTheme = {
name: 'BaseSelectMenu',
common: commonDark,
peers: {
Scrollbar: scrollbarDark,
Empty: emptyDark
},
getLocalVars (vars) {
self (vars) {
const {
borderRadius,
popoverColor,
@ -42,3 +43,5 @@ export default {
}
}
}
export default baseSelectMenuDark

View File

@ -1,2 +1,3 @@
export { default as baseSelectMenuLight } from './light'
export { default as baseSelectMenuDark } from './dark'
export type { BaseSelectMenuThemeVars, BaseSelectMenuTheme } from './light'

View File

@ -1,44 +0,0 @@
import { emptyLight } from '../../../empty/styles'
import { scrollbarLight } from '../../../scrollbar/styles'
import { commonLight } from '../../../_styles/new-common'
import commonVariables from './_common'
export default {
name: 'BaseSelectMenu',
common: commonLight,
peers: {
Scrollbar: scrollbarLight,
Empty: emptyLight
},
self (vars) {
const {
borderRadius,
popoverColor,
boxShadow2,
textColor3,
dividerColorOverlay,
textColor2,
primaryColorPressed,
textColorDisabled,
primaryColor,
opacityDisabled,
hoverColorOverlay
} = vars
return {
...commonVariables,
borderRadius: borderRadius,
color: popoverColor,
boxShadow: boxShadow2,
groupHeaderTextColor: textColor3,
actionDividerColor: dividerColorOverlay,
optionTextColor: textColor2,
optionTextColorPressed: primaryColorPressed,
optionTextColorDisabled: textColorDisabled,
optionTextColorActive: primaryColor,
optionOpacityDisabled: opacityDisabled,
optionCheckColor: primaryColor,
optionColorPending: hoverColorOverlay,
actionTextColor: textColor2
}
}
}

View File

@ -0,0 +1,53 @@
import { emptyLight } from '../../../empty/styles'
import { scrollbarLight } from '../../../scrollbar/styles'
import { commonLight } from '../../../_styles/new-common'
import type { ThemeCommonVars } from '../../../_styles/new-common'
import commonVariables from './_common'
import { createTheme } from '../../../_mixins'
const self = (vars: ThemeCommonVars) => {
const {
borderRadius,
popoverColor,
boxShadow2,
textColor3,
dividerColorOverlay,
textColor2,
primaryColorPressed,
textColorDisabled,
primaryColor,
opacityDisabled,
hoverColorOverlay
} = vars
return {
...commonVariables,
borderRadius: borderRadius,
color: popoverColor,
boxShadow: boxShadow2,
groupHeaderTextColor: textColor3,
actionDividerColor: dividerColorOverlay,
optionTextColor: textColor2,
optionTextColorPressed: primaryColorPressed,
optionTextColorDisabled: textColorDisabled,
optionTextColorActive: primaryColor,
optionOpacityDisabled: opacityDisabled,
optionCheckColor: primaryColor,
optionColorPending: hoverColorOverlay,
actionTextColor: textColor2
}
}
export type BaseSelectMenuThemeVars = ReturnType<typeof self>
const baseSelectMenuLight = createTheme({
name: 'BaseSelectMenu',
common: commonLight,
peers: {
Scrollbar: scrollbarLight,
Empty: emptyLight
},
self
})
export default baseSelectMenuLight
export type BaseSelectMenuTheme = typeof baseSelectMenuLight

View File

@ -20,7 +20,7 @@ import type { BaseSelectionTheme } from '../styles'
import Suffix from './Suffix'
import style from './styles/index.cssr'
interface Option {
export interface SelectOption {
value: string | number
label: string
}
@ -46,11 +46,11 @@ export default defineComponent({
default: undefined
},
selectedOption: {
type: Object as PropType<Option | null>,
type: Object as PropType<SelectOption | null>,
default: null
},
selectedOptions: {
type: Array as PropType<Option[] | null>,
type: Array as PropType<SelectOption[] | null>,
default: null
},
multiple: {
@ -184,7 +184,7 @@ export default defineComponent({
const { onBlur } = props
if (onBlur) onBlur(e)
}
function doDeleteOption (value: Option): void {
function doDeleteOption (value: SelectOption): void {
const { onDeleteOption } = props
if (onDeleteOption) onDeleteOption(value)
}
@ -220,7 +220,9 @@ export default defineComponent({
// ', this may be a bug of naive-ui.'
// )
// }
if (e.relatedTarget && selfRef.value?.contains(e.relatedTarget as Node)) { return }
if (e.relatedTarget && selfRef.value?.contains(e.relatedTarget as Node)) {
return
}
doBlur(e)
}
function handleClear (e: MouseEvent): void {
@ -248,7 +250,7 @@ export default defineComponent({
}
}
}
function handleDeleteOption (option: Option): void {
function handleDeleteOption (option: SelectOption): void {
doDeleteOption(option)
}
function handlePatternKeyDown (e: KeyboardEvent): void {
@ -343,6 +345,7 @@ export default defineComponent({
borderActive,
arrowColor,
arrowColorDisabled,
loadingColor,
// form warning
colorActiveWarning,
boxShadowFocusWarning,
@ -393,6 +396,7 @@ export default defineComponent({
'--text-color-disabled': textColorDisabled,
'--arrow-color': arrowColor,
'--arrow-color-disabled': arrowColorDisabled,
'--loading-color': loadingColor,
// form warning
'--color-active-warning': colorActiveWarning,
'--box-shadow-focus-warning': boxShadowFocusWarning,

View File

@ -30,6 +30,7 @@ import {
// --text-color
// --text-color-disabled
// --arrow-color
// --loading-color
// ...clear vars
// ...form item vars
export default c([
@ -46,6 +47,9 @@ export default c([
line-height: var(--height);
font-size: var(--font-size);
`, [
cB('base-loading', `
color: var(--loading-color);
`),
cB('base-selection-label', `
height: var(--height);
line-height: var(--height);

View File

@ -48,6 +48,7 @@ const baseSelectionDark: BaseSelectionTheme = {
caretColor: primaryColor,
arrowColor: iconColorOverlay,
arrowColorDisabled: iconColorDisabledOverlay,
loadingColor: primaryColor,
// warning
borderWarning: `1px solid ${warningColor}`,
borderHoverWarning: `1px solid ${warningColorHover}`,

View File

@ -2,6 +2,7 @@ import { changeColor, scaleColor } from 'seemly'
import { commonLight } from '../../../_styles/new-common'
import type { ThemeCommonVars } from '../../../_styles/new-common'
import commonVariables from './_common'
import { createTheme } from '../../../_mixins'
const self = (vars: ThemeCommonVars) => {
const {
@ -46,6 +47,7 @@ const self = (vars: ThemeCommonVars) => {
caretColor: primaryColor,
arrowColor: iconColor,
arrowColorDisabled: iconColorDisabled,
loadingColor: primaryColor,
// warning
borderWarning: `1px solid ${warningColor}`,
borderHoverWarning: `1px solid ${warningColorHover}`,
@ -82,11 +84,11 @@ const self = (vars: ThemeCommonVars) => {
export type BaseSelectionThemeVars = ReturnType<typeof self>
const baseSelectionLight = {
const baseSelectionLight = createTheme({
name: 'BaseSelection',
common: commonLight,
self
}
})
export default baseSelectionLight
export type BaseSelectionTheme = typeof baseSelectionLight