import { defineComponent, provide, ref, Teleport, toRef, toRefs, Transition, withModifiers, computed } from 'vue';
import { onClickOutside } from '@vueuse/core';
import type { SetupContext } from 'vue';
import { editableSelectProps, EditableSelectProps, SELECT_KEY } from './editable-select-types';
import { FlexibleOverlay } from '../../overlay';
import Dropdown from './components/dropdown/dropdown';
import { SelectArrowIcon, InputClearIcon } from '../../svg-icons';
import { useSelect, useSelectStates } from './composables/use-select';
import { useKeyboardSelect } from './composables/use-keyboard-select';
import { useInputRender } from './composables/use-input-render';
import { useInputEvent } from './composables/use-input-event';
import { useLazyLoad } from './composables/use-lazy-load';
import { useNamespace } from '../../shared/hooks/use-namespace';
import './editable-select.scss';
export default defineComponent({
name: 'DEditableSelect',
props: editableSelectProps,
emits: ['update:modelValue', 'focus', 'blur', 'clear', 'change', 'visibleChange', 'loadMore', 'inputChange'],
setup(props: EditableSelectProps, ctx: SetupContext) {
const ns = useNamespace('editable-select');
const inputRef = ref<HTMLInputElement>();
const originRef = ref<HTMLElement>();
const dropdownRef = ref<HTMLElement>();
const overlayRef = ref<HTMLElement>();
const states = useSelectStates();
const { appendToBody, disabled, modelValue, position, placeholder, maxLength } = toRefs(props);
const { onInput, onMouseenter, onMouseleave, setSoftFocus, handleBlur, handleFocus, handleClear } = useInputEvent(
inputRef,
props,
states,
ctx
);
const { filteredOptions, emptyText, showClearable, toggleMenu, handleOptionSelect, scrollToItem } = useSelect(
dropdownRef,
props,
states,
setSoftFocus,
ctx
);
const { onKeydown } = useKeyboardSelect(props, states, filteredOptions, scrollToItem, handleOptionSelect);
const { loadMore } = useLazyLoad(dropdownRef, props, ctx);
provide(SELECT_KEY, {
dropdownRef,
disabledKey: props.disabledKey,
modelValue,
inputValue: toRef(states, 'inputValue'),
query: toRef(states, 'query'),
hoveringIndex: toRef(states, 'hoveringIndex'),
loading: toRef(props, 'loading'),
emptyText,
loadMore,
handleOptionSelect,
setSoftFocus,
});
onClickOutside(
originRef,
() => {
states.visible = false;
states.isFocus = false;
},
{ ignore: [overlayRef] }
);
const { inputClasses, inputWrapperClasses, inputInnerClasses, inputSuffixClasses } = useInputRender(props, states);
const currentPosition = ref('bottom');
const handlePositionChange = (pos: string) => {
currentPosition.value = pos.includes('top') || pos.includes('right-end') || pos.includes('left-end') ? 'top' : 'bottom';
};
const styles = computed(() => ({
transformOrigin: currentPosition.value === 'top' ? '0% 100%' : '0% 0%',
'z-index': 'var(--devui-z-index-dropdown, 1052)',
}));
const renderBasicDropdown = () => {
return (
<Transition name={ns.m(`fade-${currentPosition.value}`)}>
<FlexibleOverlay
ref={overlayRef}
v-model={states.visible}
origin={originRef.value}
position={position.value}
style={styles.value}
onPositionChange={handlePositionChange}>
<Dropdown options={filteredOptions.value} width={props.width} maxHeight={props.maxHeight} v-slots={ctx.slots}></Dropdown>
</FlexibleOverlay>
</Transition>
);
};
const renderDropdown = () => {
if (appendToBody.value) {
return <Teleport to="body">{renderBasicDropdown()}</Teleport>;
} else {
return renderBasicDropdown();
}
};
return () => {
return (
<div
ref={originRef}
class={ns.b()}
style={{
width: props.width + 'px',
}}
onClick={toggleMenu}>
<div class={inputClasses.value} onMouseenter={onMouseenter} onMouseleave={onMouseleave}>
<div class={inputWrapperClasses.value}>
<input
ref={inputRef}
class={inputInnerClasses.value}
disabled={disabled.value}
placeholder={placeholder.value}
value={states.inputValue}
maxlength={maxLength?.value}
type="text"
onInput={onInput}
onFocus={handleFocus}
onBlur={handleBlur}
onKeydown={onKeydown}
/>
<span class={inputSuffixClasses.value}>
<span class={ns.e('clear-icon')} v-show={showClearable.value} onClick={withModifiers(handleClear, ['stop'])}>
<InputClearIcon />
</span>
<span class={ns.e('arrow-icon')} v-show={!showClearable.value}>
<SelectArrowIcon />
</span>
</span>
</div>
</div>
{renderDropdown()}
</div>
);
};
},
});