diff --git a/packages/devui-vue/devui/editable-select/__tests__/editable-select.spec.ts b/packages/devui-vue/devui/editable-select/__tests__/editable-select.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..aa694a308b703f06ced6875e435057fdc97350f4
--- /dev/null
+++ b/packages/devui-vue/devui/editable-select/__tests__/editable-select.spec.ts
@@ -0,0 +1,8 @@
+import { mount } from '@vue/test-utils';
+import { EditableSelect } from '../index';
+
+describe('editable-select test', () => {
+ it('editable-select init render', async () => {
+ // todo
+ })
+})
diff --git a/packages/devui-vue/devui/editable-select/index.ts b/packages/devui-vue/devui/editable-select/index.ts
index bd343fc7d8250ac80bec524a8ac1ae4cd307c4fc..411728313716c4f53e85b39ecb87f7dc765ab8bf 100644
--- a/packages/devui-vue/devui/editable-select/index.ts
+++ b/packages/devui-vue/devui/editable-select/index.ts
@@ -1,20 +1,17 @@
import type { App } from 'vue'
import EditableSelect from './src/editable-select'
-import EditableSelectOption from './src/components/option'
-EditableSelect.install = function (app: App): void {
+EditableSelect.install = function(app: App): void {
app.component(EditableSelect.name, EditableSelect)
- app.component(EditableSelectOption.name, EditableSelectOption)
-
}
-export { EditableSelect, EditableSelectOption }
+export { EditableSelect }
export default {
title: 'EditableSelect 可输入下拉选择框',
category: '数据录入',
- status: '10%',
+ status: undefined, // TODO: 组件若开发完成则填入"已完成",并删除该注释
install(app: App): void {
- app.use(EditableSelect as any)
+ app.use(EditableSelect as any)
}
}
diff --git a/packages/devui-vue/devui/editable-select/src/components/option/index.tsx b/packages/devui-vue/devui/editable-select/src/components/option/index.tsx
deleted file mode 100644
index 1dfd5c5c9dcf4814d07c5772d37d4ff5c4cce0f3..0000000000000000000000000000000000000000
--- a/packages/devui-vue/devui/editable-select/src/components/option/index.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import { defineComponent, renderSlot, getCurrentInstance, inject } from 'vue'
-import { className } from '../../utils/index'
-import { selectKey } from '../../editable-select-types'
-export default defineComponent({
- name: 'DEditableSelectOption',
- props: {
- label: {
- type: [String, Number],
- },
- disabled: {
- type: Boolean,
- default: false,
- },
- },
- setup(props, ctx) {
- const optionsClassName = className('devui-dropdown-item', {
- disabled: props.disabled,
- })
- const instance = getCurrentInstance()
-
- const select = inject(selectKey)
-
- const selectOptionClick = () => {
- if (!props.disabled) {
- select.handleOptionSelect(instance)
- }
- }
- return () => {
- return (
-
- {props.label ? props.label : renderSlot(ctx.slots, 'default')}
-
- )
- }
- },
-})
diff --git a/packages/devui-vue/devui/editable-select/src/editable-select-types.ts b/packages/devui-vue/devui/editable-select/src/editable-select-types.ts
index cf83a584267d36446362cd7471f8bbf4aba4cdf1..4da866665772dc30d0ab009d275ba650367315d8 100644
--- a/packages/devui-vue/devui/editable-select/src/editable-select-types.ts
+++ b/packages/devui-vue/devui/editable-select/src/editable-select-types.ts
@@ -1,56 +1,49 @@
-import type { ExtractPropTypes, Ref, PropType, InjectionKey } from 'vue'
-export type ModelValue = number | string | Array
-// porps
+import type { PropType, ExtractPropTypes } from 'vue'
+export interface OptionItem {
+ name: string
+ [key: string]: any
+}
+export type Options = Array
export const editableSelectProps = {
/* test: {
type: Object as PropType<{ xxx: xxx }>
} */
- width: {
- type: Number,
- default: 450
+ modelValue: {
+ type: [String, Number] as PropType
},
- appendToBody: {
- type: Boolean,
- default: true,
+ options: {
+ type: Array as PropType,
+ default: () => []
+ },
+ width: {
+ type: Number
},
maxHeight: {
- type: Number,
- default: 300
+ type: Number
},
disabled: {
type: Boolean,
default: false
},
- modelValue: {
- type: [String, Number, Array] as PropType
+ disabledKey: {
+ type: String,
+ },
+ remote: {
+ type: Boolean,
+ default: false
},
- 'onUpdate:modelValue': {
- type: Function as PropType<(val: ModelValue) => void>,
+ loading: {
+ type: Boolean
},
+ remoteMethod: {
+ type: Function as PropType<(inputValue: string) => Array>
+ },
+ filterMethod: {
+ type: Function as PropType<(inputValue: string) => Array>
+ },
+ searchFn: {
+ type: Function as PropType<(term: string) => Array>,
+ }
} as const
export type EditableSelectProps = ExtractPropTypes
-type HorizontalConnectionPos = 'left' | 'center' | 'right';
-type VerticalConnectionPos = 'top' | 'center' | 'bottom';
-
-interface ConnectionPosition {
- originX: HorizontalConnectionPos
- originY: VerticalConnectionPos
- overlayX: HorizontalConnectionPos
- overlayY: VerticalConnectionPos
-}
-
-export interface SelectStatesReturnType {
- visible: boolean
- origin: Ref
- position: ConnectionPosition
-}
-export interface SelectReturnType {
- toggleMenu: () => void
- handleOptionSelect: (vm: unknown) => void
-}
-
-export const selectKey = 'DSelect' as unknown as InjectionKey
-export interface SelectContext {
- handleOptionSelect(vm: unknown): void
-}
diff --git a/packages/devui-vue/devui/editable-select/src/editable-select.scss b/packages/devui-vue/devui/editable-select/src/editable-select.scss
index 94567edcb2db2f0608d459a8db2d5e94ee04e624..78714927a24c4c9db4db8cc193bcd93b0118baae 100644
--- a/packages/devui-vue/devui/editable-select/src/editable-select.scss
+++ b/packages/devui-vue/devui/editable-select/src/editable-select.scss
@@ -32,7 +32,7 @@
transform: rotate(180deg);
svg path {
- fill: $devui-text-weak; // TODO: Color-Question
+ fill: $devui-text-weak;
}
}
}
diff --git a/packages/devui-vue/devui/editable-select/src/editable-select.tsx b/packages/devui-vue/devui/editable-select/src/editable-select.tsx
index f76b6e430d5eda57392572636429a9d1c7d3c077..671e6eb9d8f50f288a301937926bc30d9728323b 100644
--- a/packages/devui-vue/devui/editable-select/src/editable-select.tsx
+++ b/packages/devui-vue/devui/editable-select/src/editable-select.tsx
@@ -1,80 +1,169 @@
-import './editable-select.scss'
-import {
- defineComponent,
- reactive,
- toRefs,
- renderSlot,
- provide,
- SetupContext,
-} from 'vue'
+import { defineComponent, ref, renderSlot, computed, Transition } from "vue"
import {
+ OptionItem,
editableSelectProps,
EditableSelectProps,
- selectKey,
-} from './editable-select-types'
-import { Icon } from '../../icon'
-import { FlexibleOverlay } from '../../overlay'
-import { useSelectStates, useSelect } from './hooks/use-select'
-import { className } from './utils/index'
+} from "./editable-select-types"
+import "./editable-select.scss"
+import { Icon } from "../../icon"
+import ClickOutside from "../../shared/devui-directive/clickoutside"
+import { className } from "./utils"
+import { debounce } from "lodash"
export default defineComponent({
- name: 'DEditableSelect',
+ name: "DEditableSelect",
+ directives: { ClickOutside },
props: editableSelectProps,
- emits: ['update:modelValue'],
+ emits: ["update:modelValue"],
+ setup(props: EditableSelectProps, ctx) {
+ const inputCls = className(
+ "devui-form-control devui-dropdown-origin devui-dropdown-origin-open",
+ {
+ disabled: props.disabled,
+ }
+ )
- setup(props: EditableSelectProps, ctx: SetupContext) {
- const states = useSelectStates()
- const { origin, visible } = toRefs(states)
+ const getLiCls = (item) => {
+ const { disabledKey } = props
+ return className("devui-dropdown-item", {
+ disabled: disabledKey ? !!item[disabledKey] : false,
+ })
+ }
- const inputCls = className('devui-form-control devui-dropdown-origin', {
- disabled: props.disabled,
- })
- const { toggleMenu, handleOptionSelect } = useSelect(props, ctx, states)
+ const visible = ref(false)
+ const inputValue = ref("")
+ const query = ref(props.modelValue)
- provide(
- selectKey,
- reactive({
- handleOptionSelect,
+ const wait = computed(() => (props.remote ? 300 : 0))
+
+ const emptyText = computed(() => {
+ const options = filteredOptions.value
+ if (!props.remote && inputValue.value && options.length === 0) {
+ return "没有相关记录"
+ }
+ if (options.length === 0) {
+ return "没有数据"
+ }
+ return null
+ })
+ const normalizeOptions = computed(() => {
+ let options: OptionItem
+ const { disabledKey } = props
+ disabledKey ? disabledKey : "disabled"
+ return props.options.map((item) => {
+ if (typeof item !== "object") {
+ options = {
+ name: item,
+ }
+ return options
+ }
+ return item
})
- )
+ })
+
+ const filteredOptions = computed(() => {
+ const isValidOption = (o: OptionItem): boolean => {
+ const query = inputValue.value
+ const containsQueryString = query ? o.name.includes(query) : true
+ return containsQueryString
+ }
+ return normalizeOptions.value
+ .map((item) => {
+ if (props.remote || isValidOption(item)) {
+ return item
+ }
+ return null
+ })
+ .filter((item) => item !== null)
+ })
+
+ const handleClose = () => {
+ visible.value = false
+ }
+ const toggleMenu = () => {
+ if (!props.disabled) {
+ visible.value = !visible.value
+ }
+ }
+ const onInputChange = () => {
+ if (props.filterMethod) {
+ props.filterMethod(inputValue.value)
+ } else if (props.remote) {
+ props.remoteMethod(inputValue.value)
+ }
+ }
+ const debouncedOnInputChange = debounce(onInputChange, wait.value)
+
+ const handleInput = (event) => {
+ const value = event.target.value
+ inputValue.value = value
+ query.value = value
+ if (props.remote) {
+ debouncedOnInputChange()
+ } else {
+ onInputChange()
+ }
+ }
+ const selectOptionClick = (e, item) => {
+ const { disabledKey } = props
+ if (disabledKey && item[disabledKey]) {
+ e.stopPropagation()
+ } else {
+ query.value = item.name
+ ctx.emit("update:modelValue", item.name)
+ }
+ }
return () => {
return (
- <>
-