forked from opentiny/tiny-vue
styles(cascader): [cascader] add cascader types (#1324)
This commit is contained in:
parent
4eeac6a614
commit
076e8369d1
|
@ -16,6 +16,14 @@ import debounce from '../common/deps/debounce'
|
|||
import { isEqual } from '../common/object'
|
||||
import { addResizeListener } from '../common/deps/resize-event'
|
||||
import { KEY_CODE, CASCADER } from '../common'
|
||||
import type {
|
||||
ICascaderState,
|
||||
ICascaderProps,
|
||||
ICascaderApi,
|
||||
ICascaderConstants,
|
||||
ICascadeRenderlessParamUtils
|
||||
} from '@/types'
|
||||
import type CascaderPanelNode from '../cascader-panel/node'
|
||||
|
||||
const initMigratingProps = () => ({
|
||||
expandTrigger: { newProp: CASCADER.PropsExpandTri, type: String },
|
||||
|
@ -30,7 +38,7 @@ const kebabCase = (str) => {
|
|||
}
|
||||
|
||||
export const getConfig =
|
||||
({ parent, props }) =>
|
||||
({ parent, props }: { parent: ICascadeRenderlessParamUtils['parent']; props: ICascaderProps }) =>
|
||||
() => {
|
||||
const config = props.props || {}
|
||||
const { $attrs } = parent
|
||||
|
@ -53,7 +61,7 @@ export const getConfig =
|
|||
}
|
||||
|
||||
export const computClearVisible =
|
||||
({ props, state }) =>
|
||||
({ props, state }: { props: ICascaderProps; state: ICascaderState }) =>
|
||||
() => {
|
||||
if (!props.clearable || state.isDisabled || state.filtering || !state.inputHover) {
|
||||
return false
|
||||
|
@ -63,7 +71,7 @@ export const computClearVisible =
|
|||
}
|
||||
|
||||
export const computePresentContent =
|
||||
({ api, state }) =>
|
||||
({ api, state }: { api: ICascaderApi; state: ICascaderState }) =>
|
||||
() => {
|
||||
if (state.config.multiple) {
|
||||
api.computePresentTags()
|
||||
|
@ -74,16 +82,16 @@ export const computePresentContent =
|
|||
}
|
||||
|
||||
export const watchValue =
|
||||
({ api, state }) =>
|
||||
({ api, state }: { api: ICascaderApi; state: ICascaderState }) =>
|
||||
(value) => {
|
||||
if (!isEqual(value, state.checkedValue)) {
|
||||
if (!isEqual(value, state.checkedValue as any)) {
|
||||
state.checkedValue = value
|
||||
setTimeout(api.computePresentContent)
|
||||
}
|
||||
}
|
||||
|
||||
export const watchCheckedValue =
|
||||
({ api, emit, state }) =>
|
||||
({ api, emit, state }: { api: ICascaderApi; emit: ICascadeRenderlessParamUtils['emit']; state: ICascaderState }) =>
|
||||
(value) => {
|
||||
const { checkStrictly, multiple } = state.config
|
||||
|
||||
|
@ -131,7 +139,19 @@ export const isEmpty = (val) => {
|
|||
}
|
||||
|
||||
export const selfMounted =
|
||||
({ api, parent, props, refs, state }) =>
|
||||
({
|
||||
api,
|
||||
parent,
|
||||
props,
|
||||
refs,
|
||||
state
|
||||
}: {
|
||||
api: ICascaderApi
|
||||
parent: ICascadeRenderlessParamUtils['parent']
|
||||
props: ICascaderProps
|
||||
refs: ICascadeRenderlessParamUtils['refs']
|
||||
state: ICascaderState
|
||||
}) =>
|
||||
() => {
|
||||
const { input } = refs
|
||||
const inputSizeMap = { medium: 36, small: 32, mini: 28 }
|
||||
|
@ -167,7 +187,19 @@ export const selfMounted =
|
|||
}
|
||||
|
||||
export const toggleDropDownVisible =
|
||||
({ emit, nextTick, refs, state, updatePopper }) =>
|
||||
({
|
||||
emit,
|
||||
nextTick: _,
|
||||
refs,
|
||||
state,
|
||||
updatePopper
|
||||
}: {
|
||||
emit: ICascadeRenderlessParamUtils['emit']
|
||||
nextTick: ICascadeRenderlessParamUtils['nextTick']
|
||||
refs: ICascadeRenderlessParamUtils['refs']
|
||||
state: ICascaderState
|
||||
updatePopper: (popperElm?: HTMLElement | undefined) => void
|
||||
}) =>
|
||||
(visible) => {
|
||||
if (state.isDisabled) {
|
||||
return
|
||||
|
@ -264,7 +296,7 @@ export const handleInput =
|
|||
}
|
||||
}
|
||||
|
||||
export const handleClear = (state) => () => {
|
||||
export const handleClear = (state: ICascaderState) => (_event) => {
|
||||
state.presentText = ''
|
||||
state.panel.clearCheckedNodes()
|
||||
}
|
||||
|
@ -285,10 +317,10 @@ export const handleExpandChange =
|
|||
}
|
||||
|
||||
export const focusFirstNode =
|
||||
({ refs, state }) =>
|
||||
({ refs, state }: { refs: ICascadeRenderlessParamUtils['refs']; state: ICascaderState }) =>
|
||||
() => {
|
||||
const { popper, suggestionPanel } = refs
|
||||
let firstNode = null
|
||||
let firstNode: HTMLLIElement | null = null
|
||||
|
||||
if (state.filtering && suggestionPanel) {
|
||||
firstNode = suggestionPanel.$el.querySelector(CASCADER.SugItem)
|
||||
|
@ -304,7 +336,7 @@ export const focusFirstNode =
|
|||
}
|
||||
|
||||
export const computePresentText =
|
||||
({ props, state }) =>
|
||||
({ props, state }: { props: ICascaderProps; state: ICascaderState }) =>
|
||||
() => {
|
||||
if (!isEmpty(state.checkedValue)) {
|
||||
const node = state.panel.getNodeByValue(state.checkedValue)
|
||||
|
@ -320,16 +352,16 @@ export const computePresentText =
|
|||
}
|
||||
|
||||
export const computePresentTags =
|
||||
({ api, props, state }) =>
|
||||
({ api, props, state }: { api: ICascaderApi; props: ICascaderProps; state: ICascaderState }) =>
|
||||
() => {
|
||||
const checkedNodes = api.getCheckedNodes(state.leafOnly)
|
||||
const tags = []
|
||||
const tags: Partial<CascaderPanelNode & { key: string | number; text: string; closable: boolean }>[] = []
|
||||
|
||||
const genTag = (node) => {
|
||||
const text = node.getText(props.showAllLevels, props.separator)
|
||||
const closable = !state.isDisabled && !node.isDisabled
|
||||
|
||||
return { node, key: node.uid, text, hitState: false, closable }
|
||||
return { node, key: node.uid, text, hitState: false, closable } as Partial<CascaderPanelNode>
|
||||
}
|
||||
|
||||
if (checkedNodes.length) {
|
||||
|
@ -355,7 +387,15 @@ export const computePresentTags =
|
|||
}
|
||||
|
||||
export const calcCollapseTags =
|
||||
({ state, refs, nextTick }) =>
|
||||
({
|
||||
state,
|
||||
refs,
|
||||
nextTick
|
||||
}: {
|
||||
state: ICascaderState
|
||||
refs: ICascadeRenderlessParamUtils['refs']
|
||||
nextTick: ICascadeRenderlessParamUtils['nextTick']
|
||||
}) =>
|
||||
() => {
|
||||
nextTick(() => {
|
||||
const content = refs['tags-content']
|
||||
|
@ -378,8 +418,10 @@ export const calcCollapseTags =
|
|||
const collapseTagWidth =
|
||||
tagsLength && parseFloat(collapseTagContentWidth) + parseFloat(marginRight) + parseFloat(marginLeft)
|
||||
|
||||
const tags = Array.from(content.querySelectorAll('.tiny-tag'))
|
||||
let { total, dom, idx } = { total: collapseTagWidth, dom: null, idx: 0 }
|
||||
const tags: HTMLDivElement[] = Array.from(content.querySelectorAll('.tiny-tag'))
|
||||
let { total, dom, idx } = { total: collapseTagWidth as number, dom: null as HTMLDivElement | null, idx: 0 }
|
||||
|
||||
// eslint-disable-next-line array-callback-return
|
||||
tags.some((tag, index) => {
|
||||
if (tag !== tagsLength) {
|
||||
const { width: tagContentWidth, marginRight, marginLeft } = tag && window.getComputedStyle(tag)
|
||||
|
@ -410,7 +452,7 @@ export const calcCollapseTags =
|
|||
}
|
||||
|
||||
export const watchInputHover =
|
||||
({ refs }) =>
|
||||
({ refs }: { refs: ICascadeRenderlessParamUtils['refs'] }) =>
|
||||
(newVal) => {
|
||||
const [inputHover, dropDownVisible] = newVal
|
||||
if (!inputHover && !dropDownVisible) {
|
||||
|
@ -420,7 +462,7 @@ export const watchInputHover =
|
|||
}
|
||||
|
||||
export const handleMouseenter =
|
||||
({ refs, state }) =>
|
||||
({ refs, state }: { refs: ICascadeRenderlessParamUtils['refs']; state: ICascaderState }) =>
|
||||
($event) => {
|
||||
const dom = $event.target
|
||||
const textNode = dom && dom.querySelector('span')
|
||||
|
@ -439,19 +481,30 @@ export const handleMouseenter =
|
|||
}
|
||||
|
||||
export const handleMouseleave =
|
||||
({ state }) =>
|
||||
({ state }: { state: ICascaderState }) =>
|
||||
() =>
|
||||
(state.tooltipVisible = false)
|
||||
|
||||
export const getSuggestions =
|
||||
({ nextTick, props, state, updatePopper }) =>
|
||||
({
|
||||
nextTick,
|
||||
props,
|
||||
state,
|
||||
updatePopper
|
||||
}: {
|
||||
nextTick: ICascadeRenderlessParamUtils['nextTick']
|
||||
props: ICascaderProps
|
||||
state: ICascaderState
|
||||
updatePopper
|
||||
}) =>
|
||||
() => {
|
||||
let filterMethod = null
|
||||
type IFilterMethod = (node: any, keyword: any) => number
|
||||
let filterMethod: IFilterMethod | null = null
|
||||
|
||||
if (!(props.filterMethod && typeof props.filterMethod === 'function')) {
|
||||
filterMethod = (node, keyword) => ~node.text.indexOf(keyword)
|
||||
} else {
|
||||
filterMethod = props.filterMethod
|
||||
filterMethod = props.filterMethod as IFilterMethod
|
||||
}
|
||||
|
||||
const suggestions = state.panel.getFlattedNodes(state.leafOnly).filter((node) => {
|
||||
|
@ -459,9 +512,9 @@ export const getSuggestions =
|
|||
return false
|
||||
}
|
||||
|
||||
node.text = node.getText(props.showAllLevels, props.separator) || ''
|
||||
;(node as typeof node & { text: string }).text = node.getText(props.showAllLevels, props.separator) || ''
|
||||
|
||||
return filterMethod(node, state.inputValue)
|
||||
return filterMethod?.(node, state.inputValue)
|
||||
})
|
||||
|
||||
if (state.multiple) {
|
||||
|
@ -470,7 +523,7 @@ export const getSuggestions =
|
|||
})
|
||||
} else {
|
||||
suggestions.forEach((node) => {
|
||||
node.checked = isEqual(state.checkedValue, node.getValueByOption())
|
||||
node.checked = isEqual(state.checkedValue as object, node.getValueByOption() as object)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -481,7 +534,7 @@ export const getSuggestions =
|
|||
}
|
||||
|
||||
export const handleSuggestionKeyDown =
|
||||
({ api }) =>
|
||||
({ api }: { api: ICascaderApi }) =>
|
||||
(event) => {
|
||||
event = event || window.event
|
||||
|
||||
|
@ -505,7 +558,7 @@ export const handleSuggestionKeyDown =
|
|||
}
|
||||
|
||||
export const handleDelete =
|
||||
({ api, state }) =>
|
||||
({ api, state }: { api: ICascaderApi; state: ICascaderState }) =>
|
||||
() => {
|
||||
const lastIndex = state.presentTags.length - 1
|
||||
const lastTag = state.presentTags[lastIndex]
|
||||
|
@ -526,8 +579,8 @@ export const handleDelete =
|
|||
}
|
||||
|
||||
export const handleSuggestionClick =
|
||||
({ api, state }) =>
|
||||
(index) => {
|
||||
({ api, state }: { api: ICascaderApi; state: ICascaderState }) =>
|
||||
(index: number) => {
|
||||
const targetNode = state.suggestions[index]
|
||||
|
||||
if (state.multiple) {
|
||||
|
@ -542,10 +595,10 @@ export const handleSuggestionClick =
|
|||
}
|
||||
|
||||
export const deleteTag =
|
||||
({ emit, state }) =>
|
||||
({ emit, state }: { emit: ICascadeRenderlessParamUtils['emit']; state: ICascaderState }) =>
|
||||
(index) => {
|
||||
const val = state.checkedValue[index]
|
||||
state.checkedValue = state.checkedValue.filter((n, i) => i !== index)
|
||||
state.checkedValue = (state.checkedValue as Array<any>).filter((n, i) => i !== index)
|
||||
|
||||
emit('remove-tag', val)
|
||||
}
|
||||
|
@ -562,16 +615,17 @@ export const updateStyle =
|
|||
}
|
||||
|
||||
const tags = $el.querySelector(CASCADER.TagClass)
|
||||
let suggestionPanelEl = null
|
||||
let suggestionPanelEl: HTMLDivElement | null = null
|
||||
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
if (suggestionPanel && (suggestionPanelEl = suggestionPanel.$el)) {
|
||||
const suggestionList = suggestionPanelEl.querySelector(CASCADER.ListClass)
|
||||
suggestionList.style.minWidth = inputInner.offsetWidth + 'px'
|
||||
const suggestionList: HTMLDivElement | null = suggestionPanelEl?.querySelector(CASCADER.ListClass)
|
||||
suggestionList && (suggestionList.style.minWidth = inputInner.offsetWidth + 'px')
|
||||
}
|
||||
|
||||
if (tags) {
|
||||
const offsetHeight = tags.offsetHeight
|
||||
let height = 0
|
||||
let height: number | string = 0
|
||||
if (props.hoverExpand && !state.inputHover && !state.dropDownVisible) {
|
||||
height = state.inputInitialHeight + 'px'
|
||||
} else {
|
||||
|
@ -590,24 +644,35 @@ export const updateStyle =
|
|||
}
|
||||
}
|
||||
|
||||
export const getCheckedNodes = (state) => (leafOnly) => state.panel.getCheckedNodes(leafOnly, state.checkedValue)
|
||||
export const getCheckedNodes = (state: ICascaderState) => (leafOnly: boolean) =>
|
||||
state.panel.getCheckedNodes(leafOnly, state.checkedValue)
|
||||
|
||||
export const setInputHeightToTag =
|
||||
({ nextTick, parent, state }) =>
|
||||
({
|
||||
nextTick,
|
||||
parent,
|
||||
state
|
||||
}: {
|
||||
nextTick: ICascadeRenderlessParamUtils['nextTick']
|
||||
parent: ICascadeRenderlessParamUtils['parent']
|
||||
state: ICascaderState
|
||||
}) =>
|
||||
() => {
|
||||
nextTick(() => {
|
||||
const parentEl = parent.$el
|
||||
const height = parentEl.querySelector(CASCADER.TagClass).offsetHeight + 6 + 'px'
|
||||
const parentEl = parent.$el as HTMLDivElement
|
||||
const height = (parentEl?.querySelector(CASCADER.TagClass) as HTMLDivElement)?.offsetHeight + 6 + 'px'
|
||||
|
||||
if (!state.isDisplayOnly) {
|
||||
parentEl.querySelector(CASCADER.InputClass).style.height = height
|
||||
const inputDom = parentEl?.querySelector(CASCADER.InputClass) as HTMLDivElement | null
|
||||
inputDom && (inputDom.style.height = height)
|
||||
} else {
|
||||
parentEl.querySelector(CASCADER.InputClass).style.height = 'auto'
|
||||
const inputDom = parentEl?.querySelector(CASCADER.InputClass) as HTMLDivElement | null
|
||||
inputDom && (inputDom.style.height = 'auto')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const presentTextHandler = ({ state, value }) => {
|
||||
export const presentTextHandler = ({ state, value }: { state: ICascaderState; value: string | null }) => {
|
||||
if (state.inputValue) {
|
||||
if (state.inputValue !== value) {
|
||||
state.inputValue = value
|
||||
|
@ -620,7 +685,7 @@ export const presentTextHandler = ({ state, value }) => {
|
|||
}
|
||||
|
||||
export const handleBeforeUpdate =
|
||||
({ props, api, state }) =>
|
||||
({ props, api, state }: { props: ICascaderProps; api: ICascaderApi; state: ICascaderState }) =>
|
||||
() => {
|
||||
if ((!isEmpty(props.modelValue) && !props.filterable) || (props.hoverExpand && state.multiple)) {
|
||||
api.computePresentContent()
|
||||
|
@ -628,9 +693,19 @@ export const handleBeforeUpdate =
|
|||
}
|
||||
|
||||
export const showPlaceholder =
|
||||
({ props, state, t, constants }) =>
|
||||
({
|
||||
props,
|
||||
state,
|
||||
t,
|
||||
constants
|
||||
}: {
|
||||
props: ICascaderProps
|
||||
state: ICascaderState
|
||||
t: ICascadeRenderlessParamUtils['t']
|
||||
constants: ICascaderConstants
|
||||
}) =>
|
||||
() => {
|
||||
let placeholder = null
|
||||
let placeholder: string | null = null
|
||||
|
||||
placeholder =
|
||||
(state.multiple && state.presentTags.length) || state.present ? '' : props.placeholder || t(constants.placeholder)
|
||||
|
|
|
@ -47,6 +47,14 @@ import {
|
|||
import { removeResizeListener } from '../common/deps/resize-event'
|
||||
import userPopper from '../common/deps/vue-popper'
|
||||
import { DATEPICKER } from '../common'
|
||||
import type {
|
||||
ICascaderProps,
|
||||
ICascaderApi,
|
||||
ICascaderState,
|
||||
ICascaderConstants,
|
||||
ISharedRenderlessFunctionParams,
|
||||
ICascadeRenderlessParamUtils
|
||||
} from '@/types'
|
||||
|
||||
export const api = [
|
||||
'state',
|
||||
|
@ -68,7 +76,27 @@ export const api = [
|
|||
'handleMouseleave'
|
||||
]
|
||||
|
||||
const initState = ({ reactive, props, computed, parent, api, t, constants, refs, inject }) => {
|
||||
const initState = ({
|
||||
reactive,
|
||||
props,
|
||||
computed,
|
||||
parent,
|
||||
api,
|
||||
t,
|
||||
constants,
|
||||
refs,
|
||||
inject
|
||||
}: {
|
||||
reactive: ISharedRenderlessFunctionParams<null>['reactive']
|
||||
props: ICascaderProps
|
||||
computed: ISharedRenderlessFunctionParams<null>['computed']
|
||||
parent: ICascadeRenderlessParamUtils['parent']
|
||||
api: ICascaderApi
|
||||
t: ICascadeRenderlessParamUtils['t']
|
||||
constants: ICascaderConstants
|
||||
refs: ICascadeRenderlessParamUtils['refs']
|
||||
inject: ISharedRenderlessFunctionParams<null>['inject']
|
||||
}) => {
|
||||
const state = reactive({
|
||||
showAutoWidth: inject('showAutoWidth', null),
|
||||
/** popper 元素是否显示。 它是通过v-show 绑定到页面上,造成隐藏时,popperJs并没有destory,有一定的性能影响 */
|
||||
|
@ -104,10 +132,34 @@ const initState = ({ reactive, props, computed, parent, api, t, constants, refs,
|
|||
tooltipContent: ''
|
||||
})
|
||||
|
||||
return state
|
||||
return state as ICascaderState
|
||||
}
|
||||
|
||||
const initApi = ({ api, state, constants, dispatch, emit, refs, props, updatePopper, nextTick, parent, t }) => {
|
||||
const initApi = ({
|
||||
api,
|
||||
state,
|
||||
constants,
|
||||
dispatch,
|
||||
emit,
|
||||
refs,
|
||||
props,
|
||||
updatePopper,
|
||||
nextTick,
|
||||
parent,
|
||||
t
|
||||
}: {
|
||||
api: ICascaderApi
|
||||
state: ICascaderState
|
||||
constants: ICascaderConstants
|
||||
dispatch: ICascadeRenderlessParamUtils['dispatch']
|
||||
emit: ICascadeRenderlessParamUtils['emit']
|
||||
refs: ICascadeRenderlessParamUtils['refs']
|
||||
props: ICascaderProps
|
||||
updatePopper: (popperElm?: HTMLElement | undefined) => void
|
||||
nextTick: ICascadeRenderlessParamUtils['nextTick']
|
||||
parent: ICascadeRenderlessParamUtils['parent']
|
||||
t: ICascadeRenderlessParamUtils['t']
|
||||
}) => {
|
||||
Object.assign(api, {
|
||||
state,
|
||||
handleFocus: handleFocus(emit),
|
||||
|
@ -144,7 +196,21 @@ const initApi = ({ api, state, constants, dispatch, emit, refs, props, updatePop
|
|||
})
|
||||
}
|
||||
|
||||
const initWatch = ({ watch, state, api, props, nextTick, updatePopper }) => {
|
||||
const initWatch = ({
|
||||
watch,
|
||||
state,
|
||||
api,
|
||||
props,
|
||||
nextTick,
|
||||
updatePopper
|
||||
}: {
|
||||
watch: ISharedRenderlessFunctionParams<null>['watch']
|
||||
state: ICascaderState
|
||||
api: ICascaderApi
|
||||
props: ICascaderProps
|
||||
nextTick: ICascadeRenderlessParamUtils['nextTick']
|
||||
updatePopper: (popperElm?: HTMLElement | undefined) => void
|
||||
}) => {
|
||||
watch(() => state.disabled, api.computePresentContent)
|
||||
|
||||
watch(() => props.modelValue, api.watchValue)
|
||||
|
@ -190,9 +256,20 @@ const initWatch = ({ watch, state, api, props, nextTick, updatePopper }) => {
|
|||
}
|
||||
|
||||
export const renderless = (
|
||||
props,
|
||||
{ computed, onMounted, onBeforeUnmount, onDeactivated, onUpdated, onBeforeUpdate, reactive, toRefs, watch, inject },
|
||||
{ t, refs, emit, nextTick, constants, parent, slots, dispatch }
|
||||
props: ICascaderProps,
|
||||
{
|
||||
computed,
|
||||
onMounted,
|
||||
onBeforeUnmount,
|
||||
onDeactivated,
|
||||
onUpdated,
|
||||
onBeforeUpdate,
|
||||
reactive,
|
||||
toRefs,
|
||||
watch,
|
||||
inject
|
||||
}: ISharedRenderlessFunctionParams<null>,
|
||||
{ t, refs, emit, nextTick, constants, parent, slots, dispatch }: ICascadeRenderlessParamUtils
|
||||
) => {
|
||||
parent.tinyForm = parent.tinyForm || inject('form', null)
|
||||
|
||||
|
@ -215,21 +292,33 @@ export const renderless = (
|
|||
nextTick,
|
||||
onBeforeUnmount,
|
||||
onDeactivated
|
||||
} as any)
|
||||
|
||||
const api: Partial<ICascaderApi> = {}
|
||||
const state = initState({ reactive, props, computed, parent, api: api as ICascaderApi, t, constants, refs, inject })
|
||||
|
||||
initApi({
|
||||
api: api as ICascaderApi,
|
||||
state,
|
||||
constants,
|
||||
dispatch,
|
||||
emit,
|
||||
refs,
|
||||
props,
|
||||
updatePopper,
|
||||
nextTick,
|
||||
parent,
|
||||
t
|
||||
})
|
||||
|
||||
const api = {}
|
||||
const state = initState({ reactive, props, computed, parent, api, t, constants, refs, inject })
|
||||
initWatch({ watch, state, api: api as ICascaderApi, props, nextTick, updatePopper })
|
||||
|
||||
initApi({ api, state, constants, dispatch, emit, refs, props, updatePopper, nextTick, parent, t })
|
||||
onBeforeUpdate((api as ICascaderApi).handleBeforeUpdate)
|
||||
onUpdated((api as ICascaderApi).updateStyle)
|
||||
onMounted((api as ICascaderApi).selfMounted)
|
||||
|
||||
initWatch({ watch, state, api, props, nextTick, updatePopper })
|
||||
|
||||
onBeforeUpdate(api.handleBeforeUpdate)
|
||||
onUpdated(api.updateStyle)
|
||||
onMounted(api.selfMounted)
|
||||
|
||||
parent.$on('handle-clear', (event) => {
|
||||
api.handleClear(event)
|
||||
parent.$on('handle-clear', (event: ICascaderState) => {
|
||||
;(api as ICascaderApi).handleClear(event)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => removeResizeListener(parent.$el, api.updateStyle))
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
import type { ISharedRenderlessParamUtils } from './shared.type'
|
||||
import type { ExtractPropTypes } from 'vue'
|
||||
import type { cascaderProps } from '@/cascader/src'
|
||||
import type { ICascaderPanelApi, ICascaderPanelNodePropValue } from '@/types'
|
||||
import type {
|
||||
getConfig,
|
||||
deleteTag,
|
||||
getCheckedNodes,
|
||||
updateStyle,
|
||||
handleSuggestionClick,
|
||||
handleDelete,
|
||||
handleSuggestionKeyDown,
|
||||
getSuggestions,
|
||||
handleExpandChange,
|
||||
computePresentText,
|
||||
focusFirstNode,
|
||||
handleClear,
|
||||
handleInput,
|
||||
handleBlur,
|
||||
handleFocus,
|
||||
handleKeyDown,
|
||||
handleDropdownLeave,
|
||||
toggleDropDownVisible,
|
||||
computePresentTags,
|
||||
selfMounted,
|
||||
watchCheckedValue,
|
||||
computClearVisible,
|
||||
computePresentContent,
|
||||
watchValue,
|
||||
setInputHeightToTag,
|
||||
handleBeforeUpdate,
|
||||
showPlaceholder,
|
||||
calcCollapseTags,
|
||||
watchInputHover,
|
||||
handleMouseenter,
|
||||
handleMouseleave
|
||||
} from '../src/cascader'
|
||||
import type CascaderPanelNode from '../src/cascader-panel/node'
|
||||
|
||||
export interface ICascaderState {
|
||||
showAutoWidth: boolean
|
||||
/** popper 元素是否显示。 它是通过v-show 绑定到页面上,造成隐藏时,popperJs并没有destory,有一定的性能影响 */
|
||||
dropDownVisible: boolean
|
||||
checkedValue: ICascaderPanelNodePropValue
|
||||
inputHover: boolean
|
||||
inputValue: string | null
|
||||
presentText: string | null
|
||||
present: string | null
|
||||
presentTags: Partial<
|
||||
CascaderPanelNode & { key: string | number; text: string; closable: boolean; hitState: boolean }
|
||||
>[]
|
||||
checkedNodes: (CascaderPanelNode & { text?: string })[]
|
||||
filtering: boolean
|
||||
suggestions: CascaderPanelNode[]
|
||||
inputInitialHeight: number
|
||||
pressDeleteCount: number
|
||||
realSize: 'medium' | 'small' | 'mini'
|
||||
formDisabled: boolean
|
||||
displayOnly: boolean
|
||||
disabled: boolean
|
||||
tagSize: 'mini' | 'small'
|
||||
isDisabled: boolean
|
||||
isDisplayOnly: boolean
|
||||
config: { multiple?: boolean; checkStrictly?: boolean }
|
||||
multiple: boolean
|
||||
leafOnly: boolean
|
||||
readonly: boolean
|
||||
clearBtnVisible: boolean
|
||||
panel: Element & ICascaderPanelApi
|
||||
placeholder: boolean
|
||||
inputValues: boolean
|
||||
collapseTagsLength: number
|
||||
isHidden: boolean
|
||||
tooltipVisible: boolean
|
||||
tooltipContent: string
|
||||
}
|
||||
export type ICascaderProps = ExtractPropTypes<typeof cascaderProps>
|
||||
export interface ICascaderApi {
|
||||
state: ICascaderState
|
||||
handleFocus: ReturnType<typeof handleFocus>
|
||||
handleClear: ReturnType<typeof handleClear>
|
||||
getCheckedNodes: ReturnType<typeof getCheckedNodes>
|
||||
deleteTag: ReturnType<typeof deleteTag>
|
||||
handleDropdownLeave: ReturnType<typeof handleDropdownLeave>
|
||||
focusFirstNode: ReturnType<typeof focusFirstNode>
|
||||
computClearVisible: ReturnType<typeof computClearVisible>
|
||||
showPlaceholder: ReturnType<typeof showPlaceholder>
|
||||
updateStyle: ReturnType<typeof updateStyle>
|
||||
getSuggestions: ReturnType<typeof getSuggestions>
|
||||
handleExpandChange: ReturnType<typeof handleExpandChange>
|
||||
getConfig: ReturnType<typeof getConfig>
|
||||
setInputHeightToTag: ReturnType<typeof setInputHeightToTag>
|
||||
handleSuggestionClick: ReturnType<typeof handleSuggestionClick>
|
||||
handleDelete: ReturnType<typeof handleDelete>
|
||||
computePresentText: ReturnType<typeof computePresentText>
|
||||
handleSuggestionKeyDown: ReturnType<typeof handleSuggestionKeyDown>
|
||||
handleInput: ReturnType<typeof handleInput>
|
||||
handleKeyDown: ReturnType<typeof handleKeyDown>
|
||||
watchValue: ReturnType<typeof watchValue>
|
||||
computePresentTags: ReturnType<typeof computePresentTags>
|
||||
computePresentContent: ReturnType<typeof computePresentContent>
|
||||
watchCheckedValue: ReturnType<typeof watchCheckedValue>
|
||||
toggleDropDownVisible: ReturnType<typeof toggleDropDownVisible>
|
||||
selfMounted: ReturnType<typeof selfMounted>
|
||||
handleBeforeUpdate: ReturnType<typeof handleBeforeUpdate>
|
||||
handleBlur: ReturnType<typeof handleBlur>
|
||||
calcCollapseTags: ReturnType<typeof calcCollapseTags>
|
||||
watchInputHover: ReturnType<typeof watchInputHover>
|
||||
handleMouseenter: ReturnType<typeof handleMouseenter>
|
||||
handleMouseleave: ReturnType<typeof handleMouseleave>
|
||||
filterHandler: Function
|
||||
}
|
||||
export type ICascaderConstants = ReturnType<typeof cascaderProps._constants.default>
|
||||
export type ICascadeRenderlessParamUtils = ISharedRenderlessParamUtils<ICascaderConstants>
|
|
@ -18,63 +18,65 @@ const $constants = {
|
|||
EVENT_NAME: { FormBlur: 'form.blur' }
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: $prefix + 'Cascader',
|
||||
props: {
|
||||
...$props,
|
||||
_constants: {
|
||||
type: Object,
|
||||
default: () => $constants
|
||||
},
|
||||
autoSize: Boolean,
|
||||
beforeFilter: {
|
||||
type: Function,
|
||||
default: () => () => {
|
||||
// do nothing
|
||||
}
|
||||
},
|
||||
clearable: Boolean,
|
||||
collapseTags: Boolean,
|
||||
debounce: {
|
||||
type: Number,
|
||||
default: 300
|
||||
},
|
||||
disabled: Boolean,
|
||||
filterMethod: Function,
|
||||
filterable: Boolean,
|
||||
modelValue: {},
|
||||
options: Array,
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
popperAppendToBody: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
popperClass: String,
|
||||
props: Object,
|
||||
separator: {
|
||||
type: String,
|
||||
default: '/'
|
||||
},
|
||||
showAllLevels: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
size: String,
|
||||
shape: String,
|
||||
label: String,
|
||||
tip: String,
|
||||
displayOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
hoverExpand: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
export const cascaderProps = {
|
||||
...$props,
|
||||
_constants: {
|
||||
type: Object,
|
||||
default: () => $constants
|
||||
},
|
||||
autoSize: Boolean,
|
||||
beforeFilter: {
|
||||
type: Function,
|
||||
default: () => () => {
|
||||
// do nothing
|
||||
}
|
||||
},
|
||||
clearable: Boolean,
|
||||
collapseTags: Boolean,
|
||||
debounce: {
|
||||
type: Number,
|
||||
default: 300
|
||||
},
|
||||
disabled: Boolean,
|
||||
filterMethod: Function,
|
||||
filterable: Boolean,
|
||||
modelValue: {},
|
||||
options: Array,
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
popperAppendToBody: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
popperClass: String,
|
||||
props: Object,
|
||||
separator: {
|
||||
type: String,
|
||||
default: '/'
|
||||
},
|
||||
showAllLevels: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
size: String,
|
||||
shape: String,
|
||||
label: String,
|
||||
tip: String,
|
||||
displayOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
hoverExpand: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: $prefix + 'Cascader',
|
||||
props: cascaderProps,
|
||||
setup(props, context) {
|
||||
return $setup({ props, context, template })
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue