@@ -62,10 +62,10 @@ export default defineComponent({
const renderHorizontalBody = (actionData: ActionData, parentIndex: number) =>
actionData.actions?.map((item, index) => (
-
+ {ctx.slots.iconContent?.({ option: item }) ||
+
}
{ctx.slots.content?.({ option: item })}
{item.createdAt}
{!(actionData.actions && data?.value && index === actionData.actions.length - 1 && parentIndex === data?.value?.length - 1) && (
diff --git a/packages/devui-vue/devui/breadcrumb/src/utils.ts b/packages/devui-vue/devui/breadcrumb/src/utils.ts
index 1ae12867c9..a38470f7a9 100644
--- a/packages/devui-vue/devui/breadcrumb/src/utils.ts
+++ b/packages/devui-vue/devui/breadcrumb/src/utils.ts
@@ -1,3 +1,3 @@
-export const getPropsSlot = (slots, props, prop = 'default') => {
+export const getPropsSlot = (slots: any, props: any, prop = 'default') => {
return props[prop] ?? slots[prop]?.();
};
diff --git a/packages/devui-vue/devui/category-search/src/components/text-input-menu.tsx b/packages/devui-vue/devui/category-search/src/components/text-input-menu.tsx
index ac83d0fabd..01bd1a97a3 100644
--- a/packages/devui-vue/devui/category-search/src/components/text-input-menu.tsx
+++ b/packages/devui-vue/devui/category-search/src/components/text-input-menu.tsx
@@ -28,6 +28,7 @@ export default defineComponent({
diff --git a/packages/devui-vue/devui/category-search/src/composables/use-category-search.ts b/packages/devui-vue/devui/category-search/src/composables/use-category-search.ts
index 0577414f55..52431aca34 100644
--- a/packages/devui-vue/devui/category-search/src/composables/use-category-search.ts
+++ b/packages/devui-vue/devui/category-search/src/composables/use-category-search.ts
@@ -1,6 +1,6 @@
import { ref, computed, toRefs, provide, watch, onMounted, reactive } from 'vue';
import type { Ref, SetupContext } from 'vue';
-import { mergeWith, cloneDeep, merge } from 'lodash-es';
+import { mergeWith, cloneDeep, merge } from 'lodash';
import RadioMenu from '../components/radio-menu';
import CheckboxMenu from '../components/checkbox-menu';
import LabelMenu from '../components/label-menu';
diff --git a/packages/devui-vue/devui/editor-md/src/components/toolbar.tsx b/packages/devui-vue/devui/editor-md/src/components/toolbar.tsx
index b0f19946c1..1939527b1f 100644
--- a/packages/devui-vue/devui/editor-md/src/components/toolbar.tsx
+++ b/packages/devui-vue/devui/editor-md/src/components/toolbar.tsx
@@ -6,20 +6,20 @@ import './toolbar.scss';
export default defineComponent({
name: 'DMdToolbar',
setup() {
- const { toolbars, toolbarConfig } = useToolbar();
-
+ const { toolbars, toolbarConfig, customToolbars } = useToolbar();
+ const tempToolbars = { ...toolbars, ...customToolbars?.value };
return () => (
{toolbarConfig.value.map((item, index) =>
Array.isArray(item) ? (
<>
{item.map((key, idx) => (
-
+
))}
>
) : (
-
+
)
)}
diff --git a/packages/devui-vue/devui/editor-md/src/composables/use-editor-md-toolbar.ts b/packages/devui-vue/devui/editor-md/src/composables/use-editor-md-toolbar.ts
index 7e823c44f7..3c8c6bba69 100644
--- a/packages/devui-vue/devui/editor-md/src/composables/use-editor-md-toolbar.ts
+++ b/packages/devui-vue/devui/editor-md/src/composables/use-editor-md-toolbar.ts
@@ -2,7 +2,7 @@ import { inject } from 'vue';
import { EditorMdInjectionKey, IEditorMdInjection } from '../editor-md-types';
export function useToolbar() {
- const { toolbars, toolbarConfig } = inject(EditorMdInjectionKey) as IEditorMdInjection;
+ const { toolbars, toolbarConfig, customToolbars } = inject(EditorMdInjectionKey) as IEditorMdInjection;
- return { toolbars, toolbarConfig };
+ return { toolbars, toolbarConfig, customToolbars };
}
diff --git a/packages/devui-vue/devui/editor-md/src/composables/use-editor-md.ts b/packages/devui-vue/devui/editor-md/src/composables/use-editor-md.ts
index 72b8925632..65d0c0a00e 100644
--- a/packages/devui-vue/devui/editor-md/src/composables/use-editor-md.ts
+++ b/packages/devui-vue/devui/editor-md/src/composables/use-editor-md.ts
@@ -414,8 +414,10 @@ export function useEditorMd(props: EditorMdProps, ctx: SetupContext) {
renderRef,
containerRef,
toolbars,
+ toolbarConfig,
previewHtmlList,
isHintShow,
+ customToolbars,
getEditorIns,
onPaste,
previewContentChange,
diff --git a/packages/devui-vue/devui/editor-md/src/editor-md-types.ts b/packages/devui-vue/devui/editor-md/src/editor-md-types.ts
index c6b4fa3b4e..9598190711 100644
--- a/packages/devui-vue/devui/editor-md/src/editor-md-types.ts
+++ b/packages/devui-vue/devui/editor-md/src/editor-md-types.ts
@@ -136,6 +136,7 @@ export interface IEditorMdInjection {
showFullscreen: Ref
;
toolbars: Record;
toolbarConfig: Ref;
+ customToolbars: Ref | undefined> | undefined;
getEditorIns: () => any;
t: (name: string) => string;
}
diff --git a/packages/devui-vue/devui/editor-md/src/editor-md.tsx b/packages/devui-vue/devui/editor-md/src/editor-md.tsx
index 662a6a6398..1d2b2cff30 100644
--- a/packages/devui-vue/devui/editor-md/src/editor-md.tsx
+++ b/packages/devui-vue/devui/editor-md/src/editor-md.tsx
@@ -17,6 +17,7 @@ export default defineComponent({
const {
mode,
toolbarConfig,
+ customToolbars,
editorContainerHeight,
hidePreviewView,
placeholder,
@@ -66,6 +67,7 @@ export default defineComponent({
showFullscreen,
toolbars,
toolbarConfig,
+ customToolbars,
getEditorIns,
t: locale,
});
diff --git a/packages/devui-vue/devui/editor-md/src/utils.ts b/packages/devui-vue/devui/editor-md/src/utils.ts
index 05acbc88fc..a3ffb3be3f 100644
--- a/packages/devui-vue/devui/editor-md/src/utils.ts
+++ b/packages/devui-vue/devui/editor-md/src/utils.ts
@@ -84,5 +84,5 @@ export function locale(key: string): string {
loading: '正在加载中...',
pasting: '您粘贴内容较多, 正在努力加载中,请耐心等待...',
};
- return localeMap[key];
+ return localeMap[key] || key;
}
diff --git a/packages/devui-vue/devui/input-number/__tests__/input-number.spec.tsx b/packages/devui-vue/devui/input-number/__tests__/input-number.spec.tsx
index b562c29147..cc519dde5a 100644
--- a/packages/devui-vue/devui/input-number/__tests__/input-number.spec.tsx
+++ b/packages/devui-vue/devui/input-number/__tests__/input-number.spec.tsx
@@ -279,3 +279,20 @@ describe('d-input-number', () => {
expect(selectFn).toBeCalledTimes(2);
});
});
+
+
+it('allowEmpty', async () => {
+ const num = ref();
+ const wrapper = mount({
+ setup() {
+ return () => ;
+ },
+ });
+ num.value = undefined;
+ const inputInner = wrapper.find(ns.e('input-box'));
+ expect((inputInner.element as HTMLInputElement).value).toBeNull;
+ num.value = 51;
+ expect((inputInner.element as HTMLInputElement).value).toBe('51');
+ num.value = '';
+ expect((inputInner.element as HTMLInputElement).value).toBeNull;
+});
diff --git a/packages/devui-vue/devui/input-number/index.ts b/packages/devui-vue/devui/input-number/index.ts
index 5ff9dae71f..2c097498ac 100644
--- a/packages/devui-vue/devui/input-number/index.ts
+++ b/packages/devui-vue/devui/input-number/index.ts
@@ -8,6 +8,6 @@ export default {
category: '数据录入',
status: '50%',
install(app: App): void {
- app.component(InputNumber.name, InputNumber);
+ app.component(InputNumber.name as string, InputNumber);
}
};
diff --git a/packages/devui-vue/devui/input-number/src/input-number-types.ts b/packages/devui-vue/devui/input-number/src/input-number-types.ts
index d0e52a4566..6750a7de21 100644
--- a/packages/devui-vue/devui/input-number/src/input-number-types.ts
+++ b/packages/devui-vue/devui/input-number/src/input-number-types.ts
@@ -3,6 +3,9 @@ import type { PropType, ExtractPropTypes, ComputedRef, Ref, CSSProperties, Input
export type ISize = 'lg' | 'md' | 'sm';
export const inputNumberProps = {
+ modelValue: {
+ type: [Number, String] as PropType,
+ },
placeholder: {
type: String,
},
@@ -25,9 +28,6 @@ export const inputNumberProps = {
size: {
type: String as PropType,
},
- modelValue: {
- type: Number,
- },
precision: {
type: Number,
},
@@ -39,13 +39,17 @@ export const inputNumberProps = {
type: Boolean,
default: true,
},
+ allowEmpty: {
+ type: Boolean,
+ default: false,
+ }
} as const;
export type InputNumberProps = ExtractPropTypes;
export interface IState {
- currentValue: number | string | undefined;
- userInputValue: number | string | undefined;
+ currentValue: number | string | undefined | null;
+ userInputValue: number | string | undefined | null;
}
export interface UseExpose {
@@ -62,7 +66,7 @@ export interface UseRender {
}
export interface UseEvent {
- inputVal: ComputedRef;
+ inputVal: ComputedRef;
minDisabled: ComputedRef;
maxDisabled: ComputedRef;
onAdd: () => void;
diff --git a/packages/devui-vue/devui/input-number/src/use-input-number.ts b/packages/devui-vue/devui/input-number/src/use-input-number.ts
index 31c1244071..ea5a80621d 100644
--- a/packages/devui-vue/devui/input-number/src/use-input-number.ts
+++ b/packages/devui-vue/devui/input-number/src/use-input-number.ts
@@ -1,17 +1,16 @@
-import { computed, reactive, toRefs, watch, ref, inject } from 'vue';
+import { computed, reactive, toRefs, watch, ref, inject, InjectionKey } from 'vue';
import type { SetupContext, Ref, CSSProperties } from 'vue';
import { InputNumberProps, UseEvent, UseRender, IState, UseExpose } from './input-number-types';
import { useNamespace } from '../../shared/hooks/use-namespace';
import { isNumber, isUndefined } from '../../shared/utils';
-import { FORM_TOKEN } from '../../form';
+import { FORM_TOKEN, type FormProps } from '../../form';
const ns = useNamespace('input-number');
export function useRender(props: InputNumberProps, ctx: SetupContext): UseRender {
- const formContext = inject(FORM_TOKEN, undefined);
+ const formContext: FormProps | undefined | any = inject(FORM_TOKEN, undefined); // 修复ts语法错误组件不被d-from组件引用时,formContext未被定义
const { style, class: customClass, ...otherAttrs } = ctx.attrs;
const customStyle = { style: style as CSSProperties };
-
const inputNumberSize = computed(() => props.size || formContext?.size || 'md');
const wrapClass = computed(() => [
@@ -56,12 +55,12 @@ export function useExpose(ctx: SetupContext): UseExpose {
return { inputRef };
}
-function getPrecision(pre: number | undefined): number {
+function getPrecision(pre: string | number | undefined | null): number {
let precision = 0;
if (isUndefined(pre)) {
return precision;
}
- const preString = pre.toString();
+ const preString = (pre as string).toString();
const dotIndex = preString.indexOf('.');
if (dotIndex !== -1) {
precision = preString.length - dotIndex - 1;
@@ -89,8 +88,8 @@ export function useEvent(props: InputNumberProps, ctx: SetupContext, inputRef: R
return state.userInputValue;
}
let currentValue = state.currentValue;
- if (currentValue === '' || isUndefined(currentValue) || Number.isNaN(currentValue)) {
- return '';
+ if (!currentValue && currentValue !== 0) {
+ return null;
}
if (isNumber(currentValue)) {
// todo 小数精度 确认是否应该以正则处理
@@ -111,6 +110,9 @@ export function useEvent(props: InputNumberProps, ctx: SetupContext, inputRef: R
};
const correctValue = (value: number | string | undefined | null) => {
+ if ((!value && value !== 0) && props.allowEmpty) { // 当用户开始允许空值时 value不为0的false全返回null(即'',null,undefined,NaN都会反回null设计与dev_ui_ag版本一致)
+ return null;
+ }
// 校验正则
const valueStr = value + '';
if (props.reg && !valueStr.match(new RegExp(props.reg))) {
@@ -118,10 +120,6 @@ export function useEvent(props: InputNumberProps, ctx: SetupContext, inputRef: R
}
let newVal = Number(value);
- // 不是0 是假值或者是NaN返回undefined
- if (newVal !== 0 && (!Number(value) || Number.isNaN(newVal))) {
- return undefined;
- }
// 精度限制存在才做转换
if (!isUndefined(props.precision)) {
@@ -135,14 +133,14 @@ export function useEvent(props: InputNumberProps, ctx: SetupContext, inputRef: R
return newVal;
};
- const setCurrentValue = (value: number | string | undefined) => {
+ const setCurrentValue = (value: number | string | undefined | null) => {
const oldVal = state.currentValue;
const newVal = correctValue(value);
state.userInputValue = undefined;
- // 0 可以被更新
- if (newVal !== 0 && !newVal) {
+ // 0 和 '' 可以被更新
+ if (newVal !== 0 && newVal !== null && !newVal) {
ctx.emit('update:modelValue', oldVal);
return;
}
diff --git a/packages/devui-vue/devui/mention/src/mention.tsx b/packages/devui-vue/devui/mention/src/mention.tsx
index 9b96511ca3..eeb7621d6c 100644
--- a/packages/devui-vue/devui/mention/src/mention.tsx
+++ b/packages/devui-vue/devui/mention/src/mention.tsx
@@ -20,30 +20,51 @@ export default defineComponent({
const showSuggestions = ref(false);
const currentIndex = ref(0);
const suggestionsTop = ref();
+ const suggestionsLeft = ref();
const suggestions = ref([]);
const filteredSuggestions = ref([]);
const suggestionsDom = ref();
const loading = computed(() => props.loading);
const instance = getCurrentInstance();
+ function getLastTriggerIndex(val: string) {
+ let lastTriggerIndex = -1;
+ for (const trigger of props.trigger) {
+ lastTriggerIndex = Math.max(lastTriggerIndex, val.lastIndexOf(trigger));
+ }
+ return lastTriggerIndex;
+ }
+
+ function handleCompleteText(val: string | number) {
+ const lastTriggerIndex = getLastTriggerIndex(textContext.value);
+ textContext.value = textContext.value.substring(0, lastTriggerIndex + 1) + val.toLocaleString() + ' ';
+ showSuggestions.value = false;
+ }
+
const handleUpdate = debounce((val: string) => {
- if (props.trigger.includes(val[0])) {
+ const lastChar = val.charAt(val.length - 1);
+ if (props.trigger.includes(lastChar)) {
showSuggestions.value = true;
+ }
+ if (lastChar === ' ' || lastChar === '') {
+ showSuggestions.value = false;
+ }
+ if (showSuggestions.value) {
+ const prefix = val.slice(getLastTriggerIndex(val) + 1, val.length - 1);
if (props.position === 'top') {
setTimeout(() => {
- const height = window.getComputedStyle(suggestionsDom.value as Element, null).height;
+ const element = window.getComputedStyle(suggestionsDom.value as Element, null);
+ const { height, width } = element;
suggestionsTop.value = -Number(height.replace('px', ''));
+ suggestionsLeft.value = Number(width.replace('px', ''));
}, 0);
}
- filteredSuggestions.value = (suggestions.value as IMentionSuggestionItem[]).filter((item: IMentionSuggestionItem) =>
- String(item[props.dmValueParse.value as keyof IMentionSuggestionItem])
- .toLocaleLowerCase()
- .includes(val.slice(1).toLocaleLowerCase())
- );
- } else {
- showSuggestions.value = false;
+ filteredSuggestions.value = (suggestions.value as IMentionSuggestionItem[]).filter((item: IMentionSuggestionItem) => {
+ const string = String(item[props.dmValueParse.value as keyof IMentionSuggestionItem]).toLocaleLowerCase();
+ return string.includes(prefix);
+ });
}
- emit('change', val.slice(1));
+ emit('change', lastChar);
}, 300);
const handleBlur = (e: Event) => {
@@ -57,7 +78,9 @@ export default defineComponent({
};
const handleFocus = () => {
- if (props.trigger.includes(textContext.value)) {
+ const val = textContext.value;
+ const lastChar = val.charAt(val.length - 1);
+ if (props.trigger.includes(lastChar)) {
showSuggestions.value = true;
}
};
@@ -67,11 +90,18 @@ export default defineComponent({
e.stopPropagation();
e.preventDefault();
showSuggestions.value = false;
- textContext.value = textContext.value.substring(0, 1) + item[props.dmValueParse.value as keyof IMentionSuggestionItem];
+ handleCompleteText(item[props.dmValueParse.value as keyof IMentionSuggestionItem]);
};
const arrowKeyDown = (e: KeyboardEvent) => {
if (showSuggestions.value && filteredSuggestions.value.length) {
+ if (e.key === 'Enter') {
+ e.stopPropagation();
+ e.preventDefault();
+ showSuggestions.value = false;
+ handleCompleteText(filteredSuggestions.value[currentIndex.value][props.dmValueParse.value as keyof IMentionSuggestionItem]);
+ emit('select', filteredSuggestions.value[currentIndex.value]);
+ }
if (e.key === 'ArrowDown') {
currentIndex.value++;
if (currentIndex.value === filteredSuggestions.value.length) {
@@ -96,20 +126,6 @@ export default defineComponent({
}
};
- const enterKeyDown = (e: KeyboardEvent) => {
- if (showSuggestions.value && filteredSuggestions.value.length) {
- if (e.key === 'Enter') {
- e.stopPropagation();
- e.preventDefault();
- showSuggestions.value = false;
- textContext.value =
- textContext.value.substring(0, 1) +
- filteredSuggestions.value[currentIndex.value][props.dmValueParse.value as keyof IMentionSuggestionItem];
- emit('select', filteredSuggestions.value[currentIndex.value]);
- }
- }
- };
-
watch(
() => props.suggestions,
(val) => {
@@ -121,14 +137,13 @@ export default defineComponent({
onMounted(() => {
window.addEventListener('keydown', arrowKeyDown);
- window.addEventListener('keydown', enterKeyDown);
document.addEventListener('click', handleBlur);
});
onUnmounted(() => {
window.removeEventListener('keydown', arrowKeyDown);
- window.removeEventListener('keydown', enterKeyDown);
document.removeEventListener('click', handleBlur);
+ showSuggestions.value = false;
});
return () => {
@@ -149,6 +164,7 @@ export default defineComponent({
style={{
marginTop: props.position === 'top' ? '0px' : '-16px',
top: suggestionsTop.value ? suggestionsTop.value + 'px' : 'inherit',
+ left: suggestionsLeft.value ? suggestionsLeft.value + 'px' : 'inherit',
}}>
{filteredSuggestions.value.length > 0 ? (
filteredSuggestions.value?.map((item, index) => {
diff --git a/packages/devui-vue/devui/select/src/select.tsx b/packages/devui-vue/devui/select/src/select.tsx
index aacfa8be38..087256190c 100644
--- a/packages/devui-vue/devui/select/src/select.tsx
+++ b/packages/devui-vue/devui/select/src/select.tsx
@@ -147,7 +147,7 @@ export default defineComponent({
style={styles.value}
class={props.menuClass}>
-
+
{isShowCreateOption.value && (
-
```
@@ -82,50 +93,59 @@ const handleSelect = (val) => {