diff --git a/packages/devui-vue/.eslintrc.js b/packages/devui-vue/.eslintrc.js index 89aa01109ac14bcd8211d8d63e451e9ffd9e40b0..34ce586d93ea2cc2c029520c9fc5637852efdac9 100644 --- a/packages/devui-vue/.eslintrc.js +++ b/packages/devui-vue/.eslintrc.js @@ -1,29 +1,33 @@ module.exports = { - root: true, - parser: '@typescript-eslint/parser', + parser: 'vue-eslint-parser', parserOptions: { + parser: '@typescript-eslint/parser', sourceType: 'module', ecmaVersion: 6, ecmaFeatures: { jsx: true, - tsx: true - } + tsx: true, + }, }, env: { browser: true, node: true, jest: true, - es6: true + es6: true, }, plugins: ['@typescript-eslint'], extends: [ 'plugin:@typescript-eslint/recommended', 'plugin:vue/vue3-recommended', 'plugin:import/recommended', - 'plugin:import/typescript' + 'plugin:import/typescript', ], rules: { - quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: true }], + quotes: [ + 'error', + 'single', + { avoidEscape: true, allowTemplateLiterals: true }, + ], 'no-undef': 2, 'vue/max-attributes-per-line': 'off', 'vue/no-multiple-template-root': 'off', @@ -34,15 +38,13 @@ module.exports = { { multiline: { delimiter: 'none', - requireLast: false + requireLast: false, }, singleline: { delimiter: 'semi', - requireLast: true - } - } + requireLast: true, + }, + }, ], - 'no-unused-vars': 'off', - '@typescript-eslint/no-unused-vars': ['error'] - } + }, } diff --git a/packages/devui-vue/devui/alert/index.ts b/packages/devui-vue/devui/alert/index.ts index afbfed0c422892877f62c32da5d031fd47fa4fb1..9d4b1075057600aff426cb8d4dff29b82e7190fb 100644 --- a/packages/devui-vue/devui/alert/index.ts +++ b/packages/devui-vue/devui/alert/index.ts @@ -10,7 +10,7 @@ export { Alert } export default { title: 'Alert 警告', category: '反馈', - status: '100%', + status: '已完成', install(app: App): void { app.use(Alert as any) }, diff --git a/packages/devui-vue/devui/avatar/index.ts b/packages/devui-vue/devui/avatar/index.ts index d7700bf75f5b6f9a8a7abe4654d3d87ea30bacc5..ea509fcd8dab3782785243f7e52004cd02e942da 100644 --- a/packages/devui-vue/devui/avatar/index.ts +++ b/packages/devui-vue/devui/avatar/index.ts @@ -10,7 +10,7 @@ export { Avatar } export default { title: 'Avatar 头像', category: '数据展示', - status: '100%', + status: '已完成', install(app: App): void { app.use(Avatar as any) }, diff --git a/packages/devui-vue/devui/back-top/index.ts b/packages/devui-vue/devui/back-top/index.ts index cdc6e7eb8b734e768d62adc12ee73794299cfd16..3a5f745c6a7af46599e3d69424067a3c2bea361b 100644 --- a/packages/devui-vue/devui/back-top/index.ts +++ b/packages/devui-vue/devui/back-top/index.ts @@ -10,7 +10,7 @@ export { BackTop } export default { title: 'BackTop 回到顶部', category: '导航', - status: '60%', // TODO: 组件若开发完成则填入"已完成",并删除该注释 + status: '10%', // TODO: 组件若开发完成则填入"已完成",并删除该注释 install(app: App): void { app.use(BackTop as any) } diff --git a/packages/devui-vue/devui/back-top/src/back-top-types.ts b/packages/devui-vue/devui/back-top/src/back-top-types.ts index 1209ed581cdbdd9ab01fa60a170b9d5c3eeba582..6f76d1cda94731627d7ff7f283a1370b35a56c66 100644 --- a/packages/devui-vue/devui/back-top/src/back-top-types.ts +++ b/packages/devui-vue/devui/back-top/src/back-top-types.ts @@ -1,6 +1,7 @@ import type { PropType, ExtractPropTypes } from 'vue' export type Position = { + position: 'fixed' bottom: string right: string } @@ -13,14 +14,6 @@ export const backTopProps = { right: { type: String, default: '30px' - }, - target: { - type: String, - default: 'window' - }, - visibleHeight: { - type: Number, - default: 300 } } as const diff --git a/packages/devui-vue/devui/back-top/src/back-top.scss b/packages/devui-vue/devui/back-top/src/back-top.scss index e0d28a369df11ffef577729591a0fdc34e4a9dd9..18685214660f54b68cde866f7200e44b75ac0883 100644 --- a/packages/devui-vue/devui/back-top/src/back-top.scss +++ b/packages/devui-vue/devui/back-top/src/back-top.scss @@ -1,7 +1,6 @@ @import '../../styles-var/devui-var'; .devui-back-top { - position: fixed; width: 40px; height: 40px; cursor: pointer; @@ -9,10 +8,12 @@ .devui-back-top-base { width: 40px; height: 40px; + box-shadow: 0 0 8px rgba(0, 0, 0, 0.2); border-radius: 50%; display: flex; align-items: center; justify-content: center; + &:hover { opacity: 1; } @@ -20,7 +21,6 @@ .devui-back-top-content { opacity: 0.4; background-color: $devui-text-weak; - box-shadow: 0 0 8px rgba(0, 0, 0, 0.2); } .devui-backtop-custom { background-color: #fff; diff --git a/packages/devui-vue/devui/back-top/src/back-top.tsx b/packages/devui-vue/devui/back-top/src/back-top.tsx index 1939a4e0156f5d74c30d00b4159a0b0f7c12390b..f3b7314a37ef35f4bafc214c36100fb4d73aecdb 100644 --- a/packages/devui-vue/devui/back-top/src/back-top.tsx +++ b/packages/devui-vue/devui/back-top/src/back-top.tsx @@ -1,6 +1,6 @@ -import { defineComponent, onMounted, ref } from 'vue' +import { defineComponent } from 'vue' import { backTopProps, BackTopProps } from './back-top-types' -import { usePosition, useVisibility } from './hooks' +import { usePosition } from './hooks' import './back-top.scss' import IconTop from './assets/top.svg' @@ -9,14 +9,11 @@ export default defineComponent({ props: backTopProps, emits: [], setup(props: BackTopProps, ctx) { - const slots = ctx.slots - const backTopRef = ref(null) - const position = usePosition(props) - let isVisible = useVisibility(props, backTopRef) + const slots = ctx.slots const scrollToTop = () => { - // toTop方法暂定 + // 运行在浏览器则调用该方法 window && window.scrollTo({ top: 0, @@ -27,15 +24,13 @@ export default defineComponent({ return () => (
{ multipleDeleteTag(tagList, tag) } return ( -
- {tag?.label} -
- +
+ { tag?.label } +
+
) -} +} \ No newline at end of file diff --git a/packages/devui-vue/devui/checkbox/index.ts b/packages/devui-vue/devui/checkbox/index.ts index a602139f6062efaffc393a9a247b39cb5bf53f33..dc25995f5b7c82105f4e2c97c3b06d46bbc3522c 100644 --- a/packages/devui-vue/devui/checkbox/index.ts +++ b/packages/devui-vue/devui/checkbox/index.ts @@ -15,7 +15,7 @@ export { Checkbox } export default { title: 'Checkbox 复选框', category: '数据录入', - status: '100%', + status: '已完成', install(app: App): void { app.use(Checkbox as any); app.use(CheckboxGroup as any); diff --git a/packages/devui-vue/devui/dropdown/index.ts b/packages/devui-vue/devui/dropdown/index.ts index 0075b1cbba6c5f045227f2114b85291549690e3f..d3bf24e74ca37403a1eae2eed6a957f4aa85ff86 100644 --- a/packages/devui-vue/devui/dropdown/index.ts +++ b/packages/devui-vue/devui/dropdown/index.ts @@ -11,7 +11,7 @@ export { Dropdown } export default { title: 'Dropdown 下拉菜单', category: '导航', - status: '10%', // TODO: 组件若开发完成则填入"已完成",并删除该注释 + status: undefined, // TODO: 组件若开发完成则填入"已完成",并删除该注释 install(app: App): void { app.use(Dropdown as any) } diff --git a/packages/devui-vue/devui/editable-select/index.ts b/packages/devui-vue/devui/editable-select/index.ts index 5c1a9c9cd9d16124961a23a6cb751ac81c22b450..411728313716c4f53e85b39ecb87f7dc765ab8bf 100644 --- a/packages/devui-vue/devui/editable-select/index.ts +++ b/packages/devui-vue/devui/editable-select/index.ts @@ -10,7 +10,7 @@ export { EditableSelect } export default { title: 'EditableSelect 可输入下拉选择框', category: '数据录入', - status: '10%', // TODO: 组件若开发完成则填入"已完成",并删除该注释 + status: undefined, // TODO: 组件若开发完成则填入"已完成",并删除该注释 install(app: App): void { app.use(EditableSelect as any) } diff --git a/packages/devui-vue/devui/form/src/directive/d-validate-rules.ts b/packages/devui-vue/devui/form/src/directive/d-validate-rules.ts index 87edc1a694b8d03a6e91540add0499e5a5ba0e4c..f8a59f2852df6e2c035be9278fcccc2714681fae 100644 --- a/packages/devui-vue/devui/form/src/directive/d-validate-rules.ts +++ b/packages/devui-vue/devui/form/src/directive/d-validate-rules.ts @@ -235,13 +235,6 @@ function handleValidatePass(el: HTMLElement, tipEl: HTMLElement): void { handleErrorStrategyPass(el); } -// 获取ref的name -function getRefName(binding: DirectiveBinding): string { - const _refs = binding.instance.$refs; - const refName = Object.keys(_refs)[0]; - return refName; -} - // 获取表单name function getFormName(binding: DirectiveBinding): string { const _refs = binding.instance.$refs; @@ -281,23 +274,17 @@ export default { mounted(el: HTMLElement, binding: DirectiveBinding, vnode: VNode): void { const isFormTag = el.tagName === 'FORM'; const dfcUID = el.parentNode.parentNode.parentElement.dataset.uid; - const refName = getRefName(binding); const hasOptions = isObject(binding.value) && hasKey(binding.value, 'options'); // 获取指令绑定的值 - let { + const { rules: bindingRules, options = {}, messageShowType = MessageShowTypeEnum.popover }: DirectiveBindingValue = binding.value; let { errorStrategy }: DirectiveBindingValue = binding.value; - if(refName) { - // 判断d-form是否传递了messageShowType属性 - messageShowType = binding.instance[refName]["messageShowType"] ?? "popover"; - } - // errorStrategy可配置在options对象中 let { updateOn = UpdateOnEnum.change, diff --git a/packages/devui-vue/devui/form/src/form-control/form-control.tsx b/packages/devui-vue/devui/form/src/form-control/form-control.tsx index db29b3add81d57141600b97c683423ad3ac260d1..a1c0cc9979f8693f308c59bd267bbc85f765aa2e 100644 --- a/packages/devui-vue/devui/form/src/form-control/form-control.tsx +++ b/packages/devui-vue/devui/form/src/form-control/form-control.tsx @@ -1,6 +1,6 @@ import { defineComponent, inject, ref, computed, reactive, onMounted } from 'vue'; import { uniqueId } from 'lodash-es'; -import { IForm, formControlProps, formInjectionKey } from '../form-types'; +import {IForm, formControlProps, formInjectionKey} from '../form-types'; import { ShowPopoverErrorMessageEventData } from '../directive/d-validate-rules' import { EventBus } from '../util'; import Icon from '../../../icon/src/icon'; @@ -24,7 +24,7 @@ export default defineComponent({ onMounted(() => { EventBus.on("showPopoverErrorMessage", (data: ShowPopoverErrorMessageEventData) => { - if (uid === data.uid) { + if(uid === data.uid) { showPopover.value = data.showPopover; tipMessage.value = data.message; popPosition.value = data.popPosition as any; // todo: 待popover组件positionType完善类型之后再替换类型 @@ -33,18 +33,18 @@ export default defineComponent({ }); const iconData = computed(() => { - switch (props.feedbackStatus) { + switch(props.feedbackStatus) { case 'pending': - return { name: 'priority', color: '#e9edfa' }; + return {name: 'priority', color: '#e9edfa'}; case 'success': - return { name: 'right-o', color: 'rgb(61, 204, 166)' }; + return {name: 'right-o', color: 'rgb(61, 204, 166)'}; case 'error': - return { name: 'error-o', color: 'rgb(249, 95, 91)' }; + return {name: 'error-o', color: 'rgb(249, 95, 91)'}; default: - return { name: '', color: '' }; + return {name: '', color: ''}; } }) - + return () => { const { feedbackStatus, @@ -54,11 +54,9 @@ export default defineComponent({
{ctx.slots.default?.()} - {showPopover.value && -
- -
- } +
+ { showPopover.value && } +
{ (feedbackStatus || ctx.slots.suffixTemplate?.()) && diff --git a/packages/devui-vue/devui/form/src/form-types.ts b/packages/devui-vue/devui/form/src/form-types.ts index 5c0d6489bec47414d5237ecc8b970f43bef6e89e..662bfab3009698d01c20e0b42a3146a056eb41fc 100644 --- a/packages/devui-vue/devui/form/src/form-types.ts +++ b/packages/devui-vue/devui/form/src/form-types.ts @@ -30,10 +30,6 @@ export const formProps = { type: String, default: '', }, - messageShowType: { - type: String as PropType<'popover' | 'text' | 'toast' | 'none'>, - default: 'popover', - }, } as const export const formItemProps = { @@ -100,7 +96,6 @@ export interface IForm { formMitt: Emitter rules: any columnsClass: string - messageShowType: string } export interface IFormLabel { diff --git a/packages/devui-vue/devui/form/src/form.tsx b/packages/devui-vue/devui/form/src/form.tsx index f2d48877f8ceac4d9c8eaab1b202142859d407ae..e8fbe99dba86e7613b8ee03f4ba2d868a2ec5758 100644 --- a/packages/devui-vue/devui/form/src/form.tsx +++ b/packages/devui-vue/devui/form/src/form.tsx @@ -40,8 +40,7 @@ export default defineComponent({ labelAlign: props.labelAlign, }, rules: props.rules, - columnsClass: props.columnsClass, - messageShowType: "popover" + columnsClass: props.columnsClass }); const onSubmit = (e) => { diff --git a/packages/devui-vue/devui/fullscreen/index.ts b/packages/devui-vue/devui/fullscreen/index.ts index 49214f0fec1a66be4b5f3bfda4e23d33468eefea..b73d21fe20c4b388fc96d47df1e85c086da1ef88 100644 --- a/packages/devui-vue/devui/fullscreen/index.ts +++ b/packages/devui-vue/devui/fullscreen/index.ts @@ -10,7 +10,7 @@ export { Fullscreen } export default { title: 'Fullscreen 全屏', category: '通用', - status: '100%', + status: '已完成', install(app: App): void { app.use(Fullscreen as any) } diff --git a/packages/devui-vue/devui/grid/index.ts b/packages/devui-vue/devui/grid/index.ts index d5f01ab2d6db01a3b839d662cde2a9f14f588c0b..cb9577156f351ec9585a16ba63a0d0d18063409c 100644 --- a/packages/devui-vue/devui/grid/index.ts +++ b/packages/devui-vue/devui/grid/index.ts @@ -14,7 +14,7 @@ export { Row, Col } export default { title: 'Grid 栅格', category: '布局', - status: '100%', + status: '已完成', install(app: App): void { app.use(Col as any) app.use(Row as any) diff --git a/packages/devui-vue/devui/icon/index.ts b/packages/devui-vue/devui/icon/index.ts index fd1972adb86069d0ba3e83532a647b163c15e8da..299989544a1fbb26a255defac595845b53d8e72b 100644 --- a/packages/devui-vue/devui/icon/index.ts +++ b/packages/devui-vue/devui/icon/index.ts @@ -10,7 +10,7 @@ export { Icon } export default { title: 'Icon 图标', category: '通用', - status: '100%', + status: '已完成', install(app: App): void { app.use(Icon as any) } diff --git a/packages/devui-vue/devui/icon/src/icon.tsx b/packages/devui-vue/devui/icon/src/icon.tsx index d5e6d3956a95edacf255341c8ebe11feb0b62088..16e4593648a231e06a6a0f133fde0f30d57e70b9 100644 --- a/packages/devui-vue/devui/icon/src/icon.tsx +++ b/packages/devui-vue/devui/icon/src/icon.tsx @@ -18,7 +18,7 @@ export default defineComponent({ classPrefix: { type: String, default: 'icon' - } + }, }, setup(props) { return { @@ -27,22 +27,20 @@ export default defineComponent({ }, render() { const { name, size, color, classPrefix } = this - return /^((https?):)?\/\//.test(name) ? ( - {name.split('/')[name.split('/').length - ) : ( - + + return ( + <> + { + /^((https?):)?\/\//.test(name) + ? {name.split('/')[name.split('/').length + : + } + ) } -}) +}) \ No newline at end of file diff --git a/packages/devui-vue/devui/image-preview/index.ts b/packages/devui-vue/devui/image-preview/index.ts index 375a16e51c3d2db71578cd61ab42ad26a3913f4c..e1b883b96668ab2b20fb04b371e6cc8e89f17e15 100644 --- a/packages/devui-vue/devui/image-preview/index.ts +++ b/packages/devui-vue/devui/image-preview/index.ts @@ -7,7 +7,7 @@ export { ImagePreviewDirective, ImagePreviewService } export default { title: 'ImagePreview 图片预览', category: '数据展示', - status: '100%', + status: '已完成', install(app: App): void { app.directive('d-image-preview', ImagePreviewDirective) app.config.globalProperties.$imagePreviewService = ImagePreviewService diff --git a/packages/devui-vue/devui/input/__tests__/input.spec.ts b/packages/devui-vue/devui/input/__tests__/input.spec.ts index 3377eac590168c32aa4ca953230d90d553c1c191..3256372c999522de38624df244eec58974bcf5a5 100644 --- a/packages/devui-vue/devui/input/__tests__/input.spec.ts +++ b/packages/devui-vue/devui/input/__tests__/input.spec.ts @@ -1,38 +1,38 @@ -import { mount } from '@vue/test-utils' -import { ref, nextTick } from 'vue' -import DInput from '../src/input' +import { mount } from '@vue/test-utils'; +import { ref, nextTick } from 'vue'; +import DInput from '../src/input'; describe('d-input', () => { it('d-input render work', async () => { - const value = ref('abc') + const value = ref('abc'); const wrapper = mount({ components: { DInput }, template: ` - + `, - setup() { + setup () { return { value - } + }; } - }) - const input = wrapper.find('input') - expect(input.attributes('dinput')).toBe('true') - expect(input.element.value).toBe('abc') + }); + const input = wrapper.find('input'); + expect(input.attributes('dinput')).toBe('true'); + expect(input.element.value).toBe('abc'); - await input.setValue('def') - expect(value.value).toBe('def') + await input.setValue('def'); + expect(value.value).toBe('def'); - value.value = 'thx' - await nextTick() - expect(input.element.value).toBe('thx') - }) + value.value = 'thx'; + await nextTick(); + expect(input.element.value).toBe('thx'); + }); it('d-input bindEvents work', async () => { const onChange = jest.fn(), onFocus = jest.fn(), onBlur = jest.fn(), - onKeydown = jest.fn() + onKeydown = jest.fn(); const wrapper = mount({ components: { DInput }, template: ` @@ -42,88 +42,88 @@ describe('d-input', () => { @blur="onBlur" @keydown="onKeydown" /> `, - setup() { + setup () { return { onChange, onFocus, onBlur, onKeydown - } + }; } - }) - const input = wrapper.find('input') + }); + const input = wrapper.find('input'); - await input.trigger('change') - expect(onChange).toBeCalledTimes(1) + await input.trigger('change'); + expect(onChange).toBeCalledTimes(1); - await input.trigger('focus') - expect(onFocus).toBeCalledTimes(1) + await input.trigger('focus'); + expect(onFocus).toBeCalledTimes(1); - await input.trigger('blur') - expect(onBlur).toBeCalledTimes(1) + await input.trigger('blur'); + expect(onBlur).toBeCalledTimes(1); - await input.trigger('keydown') - expect(onKeydown).toBeCalledTimes(1) - }) + await input.trigger('keydown'); + expect(onKeydown).toBeCalledTimes(1); + }); it('d-input disabled work', async () => { const wrapper = mount(DInput, { props: { disabled: false } - }) - const input = wrapper.find('input') - expect(input.attributes('disabled')).toBe(undefined) + }); + const input = wrapper.find('input'); + expect(input.attributes('disabled')).toBe(undefined); await wrapper.setProps({ disabled: true - }) - expect(input.attributes('disabled')).toBe('') - }) + }); + expect(input.attributes('disabled')).toBe(''); + }); it('d-input error work', async () => { const wrapper = mount(DInput, { props: { error: false } - }) - const input = wrapper.find('input') - expect(input.classes()).not.toContain('error') + }); + const input = wrapper.find('input'); + expect(input.classes()).not.toContain('error'); await wrapper.setProps({ error: true - }) - expect(input.classes()).toContain('error') - }) + }); + expect(input.classes()).toContain('error'); + }); it('d-input size work', async () => { - const wrapper = mount(DInput) - const input = wrapper.find('input') - expect(input.classes()).not.toContain('devui-input-sm') - expect(input.classes()).not.toContain('devui-input-lg') + const wrapper = mount(DInput); + const input = wrapper.find('input'); + expect(input.classes()).not.toContain('devui-input-sm'); + expect(input.classes()).not.toContain('devui-input-lg'); await wrapper.setProps({ size: 'sm' - }) - expect(input.classes()).toContain('devui-input-sm') - expect(input.classes()).not.toContain('devui-input-lg') + }); + expect(input.classes()).toContain('devui-input-sm'); + expect(input.classes()).not.toContain('devui-input-lg'); await wrapper.setProps({ size: 'lg' - }) - expect(input.classes()).not.toContain('devui-input-sm') - expect(input.classes()).toContain('devui-input-lg') - }) + }); + expect(input.classes()).not.toContain('devui-input-sm'); + expect(input.classes()).toContain('devui-input-lg'); + }); it('d-input showPassword work', async () => { - const wrapper = mount(DInput) - const input = wrapper.find('input') + const wrapper = mount(DInput); + const input = wrapper.find('input'); - expect(input.attributes('type')).toBe('text') + expect(input.attributes('type')).toBe('text'); await wrapper.setProps({ showPassword: true - }) - expect(input.attributes('type')).toBe('password') - }) -}) + }); + expect(input.attributes('type')).toBe('password'); + }); +}); diff --git a/packages/devui-vue/devui/input/index.ts b/packages/devui-vue/devui/input/index.ts index 94c018b840051de35133fc92755a076721d41952..cd150ad09f121fee8565982445dd2ff05f7b2fab 100644 --- a/packages/devui-vue/devui/input/index.ts +++ b/packages/devui-vue/devui/input/index.ts @@ -10,7 +10,7 @@ export { Input } export default { title: 'Input 输入框', category: '数据录入', - status: '100%', + status: '已完成', install(app: App): void { app.use(Input as any) } diff --git a/packages/devui-vue/devui/input/src/input.tsx b/packages/devui-vue/devui/input/src/input.tsx index 50bcfa237aec88db3b6a7cf5eaf4034a24c0408b..22822ede377485f02af997e2424d0e5e178ca86e 100644 --- a/packages/devui-vue/devui/input/src/input.tsx +++ b/packages/devui-vue/devui/input/src/input.tsx @@ -1,7 +1,7 @@ -import { defineComponent, computed, ref, watch, inject } from 'vue' -import { inputProps, InputType } from './use-input' +import { defineComponent, computed, ref, watch, nextTick, onMounted, toRefs, inject } from 'vue'; +import { inputProps, InputType } from './use-input'; import './input.scss' -import { dFormItemEvents, IFormItem, formItemInjectionKey } from '../../form/src/form-types' +import { dFormItemEvents, IFormItem, formItemInjectionKey } from '../../form/src/form-types'; export default defineComponent({ name: 'DInput', @@ -15,11 +15,11 @@ export default defineComponent({ } }, props: inputProps, - emits: ['update:modelValue', 'focus', 'blur', 'change', 'keydown'], + emits: ['update:value', 'focus', 'blur', 'change', 'keydown'], setup(props, ctx) { - const formItem = inject(formItemInjectionKey, {} as IFormItem) - const hasFormItem = Object.keys(formItem).length > 0 - const sizeCls = computed(() => `devui-input-${props.size}`) + const formItem = inject(formItemInjectionKey, {} as IFormItem); + const hasFormItem = Object.keys(formItem).length > 0; + const sizeCls = computed(() => `devui-input-${props.size}`); const showPwdIcon = ref(false) const inputType = ref('text') const inputCls = computed(() => { @@ -30,40 +30,31 @@ export default defineComponent({ } }) const showPreviewIcon = computed(() => inputType.value === 'password') - watch( - () => props.showPassword, - (flg) => { - inputType.value = flg ? 'password' : 'text' - }, - { immediate: true } - ) + watch(() => props.showPassword, flg => { + inputType.value = flg ? 'password' : 'text' + }, { immediate: true }) - watch( - () => props.modelValue, - (value) => { - value && value.length > 0 && showPreviewIcon.value - ? (showPwdIcon.value = true) - : (showPwdIcon.value = false) - } - ) + watch(() => props.value, value => { + (value && value.length > 0 && showPreviewIcon.value) ? showPwdIcon.value = true : showPwdIcon.value = false + }) const onInput = ($event: Event) => { - ctx.emit('update:modelValue', ($event.target as HTMLInputElement).value) - hasFormItem && formItem.formItemMitt.emit(dFormItemEvents.input) - }, + ctx.emit('update:value', ($event.target as HTMLInputElement).value); + hasFormItem && formItem.formItemMitt.emit(dFormItemEvents.input); + }, onFocus = () => { - ctx.emit('focus') + ctx.emit('focus'); }, onBlur = () => { - ctx.emit('blur') - hasFormItem && formItem.formItemMitt.emit(dFormItemEvents.blur) + ctx.emit('blur'); + hasFormItem && formItem.formItemMitt.emit(dFormItemEvents.blur); }, onChange = ($event: Event) => { - ctx.emit('change', ($event.target as HTMLInputElement).value) - hasFormItem && formItem.formItemMitt.emit(dFormItemEvents.change) + ctx.emit('change', ($event.target as HTMLInputElement).value); + hasFormItem && formItem.formItemMitt.emit(dFormItemEvents.change); }, onKeydown = ($event: KeyboardEvent) => { - ctx.emit('keydown', $event) + ctx.emit('keydown', $event); }, onChangeInputType = () => { inputType.value = inputType.value === 'password' ? 'text' : 'password' @@ -79,11 +70,11 @@ export default defineComponent({ onChange, onKeydown, onChangeInputType - } + }; }, - render() { + render () { const { - modelValue, + value, showPreviewIcon, showPwdIcon, inputCls, @@ -97,14 +88,14 @@ export default defineComponent({ onBlur, onChange, onKeydown, - onChangeInputType - } = this + onChangeInputType, + } = this; return ( -
+
- {showPwdIcon && ( -
- {showPreviewIcon ? ( - - ) : ( - - )} -
- )} + { + showPwdIcon &&
+ { showPreviewIcon + ? + : + } +
}
- ) + ); } -}) +}); diff --git a/packages/devui-vue/devui/input/src/use-input.tsx b/packages/devui-vue/devui/input/src/use-input.tsx index 8a46ec40a21664206267f7e4d888667c92dfc395..5706ad2774fdfe141ad03ea954b0897d7d274e41 100644 --- a/packages/devui-vue/devui/input/src/use-input.tsx +++ b/packages/devui-vue/devui/input/src/use-input.tsx @@ -1,4 +1,4 @@ -import { PropType } from 'vue' +import { PropType } from 'vue'; export const inputProps = { placeholder: { @@ -33,31 +33,31 @@ export const inputProps = { type: Boolean, default: false }, - modelValue: { + value: { type: String, default: '' }, - 'update:modelValue': { + 'onUpdate:value': { type: Function as PropType<(v: string) => void>, default: undefined }, - onChange: { + 'onChange': { type: Function as PropType<(v: string) => void>, default: undefined }, - onKeydown: { + 'onKeydown': { type: Function as PropType<(v: KeyboardEvent) => void>, default: undefined }, - onFocus: { + 'onFocus': { type: Function as PropType<() => void>, default: undefined }, - onBlur: { + 'onBlur': { type: Function as PropType<() => void>, default: undefined } -} as const +} as const; export type PreviewIconType = 'preview' | 'icon-preview-forbidden' export type InputType = 'password' | 'text' diff --git a/packages/devui-vue/devui/layout/index.ts b/packages/devui-vue/devui/layout/index.ts index fe207d20caff1220782b0313a0e9015db43adae1..8f6ec9b64e061adaa7b5ba0c648f8320950fbacf 100644 --- a/packages/devui-vue/devui/layout/index.ts +++ b/packages/devui-vue/devui/layout/index.ts @@ -30,7 +30,7 @@ export { Layout, Content, Header, Footer, Aside } export default { title: 'Layout 布局', category: '布局', - status: '100%', + status: '已完成', install(app: App): void { app.use(Layout as any) app.use(Content as any) diff --git a/packages/devui-vue/devui/loading/index.ts b/packages/devui-vue/devui/loading/index.ts index 64c98597c66071ea2fa9944a361e7118a37901f0..61cf3112a442ed78bc2ccc146c35a1d7cc8f14b1 100644 --- a/packages/devui-vue/devui/loading/index.ts +++ b/packages/devui-vue/devui/loading/index.ts @@ -10,7 +10,7 @@ export { export default { title: 'Loading 加载提示', category: '反馈', - status: '100%', + status: '已完成', install(app: App): void { app.directive('dLoading', Loading) app.config.globalProperties.$loadingService = LoadingService diff --git a/packages/devui-vue/devui/modal/index.ts b/packages/devui-vue/devui/modal/index.ts index 8fed1156098434512800e9fdbc63cf28dc0f3bc6..806c2cc7d6e473fe6230d838cc2845e0abaf750f 100644 --- a/packages/devui-vue/devui/modal/index.ts +++ b/packages/devui-vue/devui/modal/index.ts @@ -13,7 +13,7 @@ export { Modal } export default { title: 'Modal 弹窗', category: '反馈', - status: '100%', + status: '已完成', install(app: App): void { app.use(Modal as any) diff --git a/packages/devui-vue/devui/overlay/index.ts b/packages/devui-vue/devui/overlay/index.ts index 7c9592b71253acad72a61d95d7ddb90500b5e57e..c995acc956c4db3c2c9535f6087b88579d6d25d6 100644 --- a/packages/devui-vue/devui/overlay/index.ts +++ b/packages/devui-vue/devui/overlay/index.ts @@ -16,7 +16,7 @@ export { FlexibleOverlay, FixedOverlay } export default { title: 'Overlay 遮罩层', category: '通用', - status: '100%', + status: '已完成', install(app: App): void { app.use(FixedOverlay as any); app.use(FlexibleOverlay as any); diff --git a/packages/devui-vue/devui/pagination/index.ts b/packages/devui-vue/devui/pagination/index.ts index e881885cb4b22f7ecce945cea9efe93421e8736b..fa7e383c57436c38e33ce3f8c4bebc116df9507b 100644 --- a/packages/devui-vue/devui/pagination/index.ts +++ b/packages/devui-vue/devui/pagination/index.ts @@ -10,7 +10,7 @@ export { Pagination } export default { title: 'Pagination 分页', category: '导航', - status: '100%', + status: '已完成', install(app: App): void { app.use(Pagination as any) } diff --git a/packages/devui-vue/devui/popover/index.ts b/packages/devui-vue/devui/popover/index.ts index 671476ac44ed7c09bbbb38782a0c547c9da3f428..6d9070c3656c29051f4fd1a6a1f45c62283390c6 100644 --- a/packages/devui-vue/devui/popover/index.ts +++ b/packages/devui-vue/devui/popover/index.ts @@ -10,7 +10,7 @@ export { Popover } export default { title: 'Popover 悬浮提示', category: '反馈', - status: '100%', + status: '已完成', install(app: App): void { app.use(Popover as any); } diff --git a/packages/devui-vue/devui/progress/index.ts b/packages/devui-vue/devui/progress/index.ts index 420816c02b13019ec182e336da1ae83b243f3559..d96a7ec9f3a33a8bbe8d897dbad2584a92da0819 100644 --- a/packages/devui-vue/devui/progress/index.ts +++ b/packages/devui-vue/devui/progress/index.ts @@ -10,7 +10,7 @@ export { Progress } export default { title: 'Progress 进度条', category: '数据展示', - status: '100%', + status: '已完成', install(app: App): void { app.use(Progress as any) } diff --git a/packages/devui-vue/devui/radio/index.ts b/packages/devui-vue/devui/radio/index.ts index 75c93739b45a2d0ee4719c88a3c64f48f0e322f0..154cdf1214a0e7a8490c2bbf25f8c192c9fad049 100644 --- a/packages/devui-vue/devui/radio/index.ts +++ b/packages/devui-vue/devui/radio/index.ts @@ -15,7 +15,7 @@ export { Radio, RadioGroup } export default { title: 'Radio 单选框', category: '数据录入', - status: '100%', + status: '已完成', install(app: App): void { app.use(Radio as any) app.use(RadioGroup as any) diff --git a/packages/devui-vue/devui/rate/index.ts b/packages/devui-vue/devui/rate/index.ts index e9829330d69da7f7a812f3784594168cb15844c7..ae9d10d1c0ca1035ee2f494c73ecc8f8f7ff8783 100644 --- a/packages/devui-vue/devui/rate/index.ts +++ b/packages/devui-vue/devui/rate/index.ts @@ -10,7 +10,7 @@ export { Rate } export default { title: 'Rate 评分', category: '数据展示', - status: '100%', + status: '已完成', install(app: App): void { app.use(Rate as any); }, diff --git a/packages/devui-vue/devui/ripple/__tests__/ripple.spec.ts b/packages/devui-vue/devui/ripple/__tests__/ripple.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..e4e3fddc36720ed65073df08ece25f0ff1a44128 --- /dev/null +++ b/packages/devui-vue/devui/ripple/__tests__/ripple.spec.ts @@ -0,0 +1,47 @@ +import { nextTick, createApp } from 'vue' +import { mount } from '@vue/test-utils' +import Ripple from '../index' +import { DEFAULT_PLUGIN_OPTIONS } from '../src/options' +// 全局属性 +const global = { + directives: { + ripple: Ripple + } +} +describe('ripple', () => { + it('ripple should render correctly', async () => { + const wrapper = mount( + { + template: ` +
+ ` + }, + { + global + } + ) + await nextTick() + const rippleElement = wrapper.find('.ripple-container') as any + await rippleElement.trigger('click') + console.log(rippleElement.element.childElementCount) + + expect(wrapper.find('div').exists()).toBeTruthy() + }) + it('test ripple plugin', () => { + const app = createApp({}).use(Ripple) + expect(app.directive('ripple', Ripple)).toBeTruthy() + }) + + it('ripple default options', () => { + expect(DEFAULT_PLUGIN_OPTIONS).toEqual({ + directive: 'ripple', + color: 'currentColor', + initialOpacity: 0.2, + finalOpacity: 0.1, + duration: 0.8, + easing: 'ease-out', + delayTime: 75, + disabled: false + }) + }) +}) diff --git a/packages/devui-vue/devui/ripple/index.ts b/packages/devui-vue/devui/ripple/index.ts index d7602a359f4245f5d8363b9f5e7184030d0c08ee..3ff7ce72a4c2385dcfa67ee10b51070f2e4b5f7e 100644 --- a/packages/devui-vue/devui/ripple/index.ts +++ b/packages/devui-vue/devui/ripple/index.ts @@ -6,7 +6,7 @@ export { RippleDirective } export default { title: 'Ripple 水波纹', category: '通用', - status: '100%', + status: '已完成', install(app: App): void { app.directive('Ripple', RippleDirective) } diff --git a/packages/devui-vue/devui/search/index.ts b/packages/devui-vue/devui/search/index.ts index 16f4e75180c0b300a8bc6bbffbc0fca1a3e87e9f..72e9f8f7fa5e6b63b82145bcfea5d1cc9c78e03b 100644 --- a/packages/devui-vue/devui/search/index.ts +++ b/packages/devui-vue/devui/search/index.ts @@ -10,7 +10,7 @@ export { Search } export default { title: 'Search 搜索框', category: '通用', - status: '100%', + status: '已完成', install(app: App): void { app.use(Search as any) } diff --git a/packages/devui-vue/devui/search/src/search.tsx b/packages/devui-vue/devui/search/src/search.tsx index 9a8ef570cb18d03cd5b4eb535c22d6a9a5e6a21a..6e7385279679701fde5bda0fd4d12f26cef8f43f 100644 --- a/packages/devui-vue/devui/search/src/search.tsx +++ b/packages/devui-vue/devui/search/src/search.tsx @@ -39,12 +39,12 @@ export default defineComponent({ size={props.size} disabled={props.disabled} autoFocus={props.autoFocus} - modelValue={keywords.value} + value={keywords.value} maxLength={props.maxLength} placeholder={props.placeholder} cssClass={props.cssClass} onKeydown={onInputKeydown} - onUpdate:modelValue={onInputUpdate} + onUpdate:value={onInputUpdate} > {clearIconShow.value &&
{ it('slider maxValue && minValue work', () => { const wrapper = mount(DSlider, { props: { max: 50, - min: 2 - } - }) - const max = wrapper.find('.devui-max_count') - const min = wrapper.find('.devui-min_count') - expect(min.text()).toBe('2') - expect(max.text()).toBe('50') - }) + min: 2, + }, + }); + const max = wrapper.find('.devui-max_count'); + const min = wrapper.find('.devui-min_count'); + expect(min.text()).toBe('2'); + expect(max.text()).toBe('50'); + }); it('slider v-model work', async () => { - const value = ref(5) + const value = ref(5); const wrapper = mount({ components: { DSlider }, template: ` @@ -24,54 +24,33 @@ describe('d-slider', () => { `, setup() { return { - modelValue: value - } - } - }) - const input = wrapper.find('input') - expect(input.element.value).toBe('5') - input.setValue(10) - await nextTick() - expect(value.value).toBe(10) - }) + modelValue: value, + }; + }, + }); + const input = wrapper.find('input'); + expect(input.element.value).toBe('5'); + input.setValue(10); + await nextTick(); + expect(value.value).toBe(10); + }); it('slider showInput work', () => { const wrapper = mount(DSlider, { props: { - showInput: true - } - }) - const dInput = wrapper.find('.devui-input__out-wrap') - expect(dInput.exists()).toBeTruthy() - }) + showInput: true, + }, + }); + const dInput = wrapper.find('.devui-input__out-wrap'); + expect(dInput.exists()).toBeTruthy(); + }); it('slider disabled work', () => { const wrapper = mount(DSlider, { props: { - disabled: true - } - }) - const slider = wrapper.find('.devui-slider__runway') - expect(slider.classes()).toContain('disabled') - }) - - it('slider tipsRenderer work', () => { - const wrapper = mount(DSlider, { - props: { - tipsRenderer: 'null' - } - }) - const slider = wrapper.find('.devui-slider_popover') - expect(slider.exists()).toBe(false) - }) - - it('slider popover work', () => { - const wrapper = mount(DSlider, { - props: { - tipsRenderer: 'bananas', - modelValue: 10 - } - }) - const slider = wrapper.find('.devui-slider_popover-content') - expect(slider.text()).toBe('10 bananas') - }) -}) + disabled: true, + }, + }); + const slider = wrapper.find('.devui-slider__runway'); + expect(slider.classes()).toContain('disabled'); + }); +}); diff --git a/packages/devui-vue/devui/slider/index.ts b/packages/devui-vue/devui/slider/index.ts index 52d1430fbe3f50a82dceddb4928c9c404ac9f4a2..f4596b7734eec02a4e6729d10d96a3013edc3f4b 100644 --- a/packages/devui-vue/devui/slider/index.ts +++ b/packages/devui-vue/devui/slider/index.ts @@ -1,7 +1,7 @@ import type { App } from 'vue' import Slider from './src/slider' -Slider.install = function (app: App): void { +Slider.install = function(app: App): void { app.component(Slider.name, Slider) } @@ -10,7 +10,7 @@ export { Slider } export default { title: 'Slider 滑块', category: '数据录入', - status: '100%', + status: '已完成', install(app: App): void { app.use(Slider as any) } diff --git a/packages/devui-vue/devui/splitter/index.ts b/packages/devui-vue/devui/splitter/index.ts index db6651c4495752831f4f43a58cdcb0e565dc9f47..2815770bdbea9fadc8c8b4e2b0acf0b9bad6c343 100644 --- a/packages/devui-vue/devui/splitter/index.ts +++ b/packages/devui-vue/devui/splitter/index.ts @@ -12,7 +12,7 @@ export { Splitter } export default { title: 'Splitter 分割器', category: '布局', - status: '100%', + status: '已完成', install(app: App): void { app.use(Splitter as any) }, diff --git a/packages/devui-vue/devui/splitter/src/splitter-bar.tsx b/packages/devui-vue/devui/splitter/src/splitter-bar.tsx index f98f9311bb6e2c10c85df79e9070d0b6335a3e7e..949640cc016fb7acee67fb82e12cc375da5b82e4 100644 --- a/packages/devui-vue/devui/splitter/src/splitter-bar.tsx +++ b/packages/devui-vue/devui/splitter/src/splitter-bar.tsx @@ -25,21 +25,22 @@ export default defineComponent({ wrapperClass: `devui-splitter-bar devui-splitter-bar-${props.orientation}`, }) const domRef = ref() + onMounted(() => { + watch([() => props.splitBarSize, domRef], ([curSplitBarSize, ele]) => { + if (!(ele instanceof HTMLElement)) { + return; + } + setStyle(ele, { flexBasis: curSplitBarSize }) + }, { immediate: true }) - watch([() => props.splitBarSize, domRef], ([curSplitBarSize, ele]) => { - if (!(ele instanceof HTMLElement)) { - return; - } - setStyle(ele, { flexBasis: curSplitBarSize }) - }, { immediate: true }) - - watch([() => store.state.panes, domRef], ([panes, ele]) => { - if (!store.isStaticBar(props.index)) { - state.wrapperClass += ' resizable' - } else { - setStyle(ele, { flexBasis: props.disabledBarSize }) - } - }, { deep: true }) + watch([() => store.state.panes, domRef], ([panes, ele]) => { + if (!store.isStaticBar(props.index)) { + state.wrapperClass += ' resizable' + } else { + setStyle(ele, { flexBasis: props.disabledBarSize }) + } + }, { deep: true }) + }) // 指令输入值 const coordinate = { pageX: 0, pageY: 0, originalX: 0, originalY: 0 } diff --git a/packages/devui-vue/devui/splitter/src/splitter-pane.tsx b/packages/devui-vue/devui/splitter/src/splitter-pane.tsx index 98ee3893e0c0d5fe90abda0cc64d25c855fc074c..55760c696a49337e9920e28f48b7fb38c07d5b83 100644 --- a/packages/devui-vue/devui/splitter/src/splitter-pane.tsx +++ b/packages/devui-vue/devui/splitter/src/splitter-pane.tsx @@ -2,6 +2,7 @@ import { defineComponent, ref, watch, + nextTick, inject, onMounted, onUpdated, @@ -30,10 +31,12 @@ export default defineComponent({ ); // pane 初始化大小 - const setSizeStyle = (curSize: string, ele: HTMLElement) => { + const setSizeStyle = (curSize: string) => { + const ele = domRef.value; if (!ele) { return; } + ele.style.flexBasis = curSize; const paneFixedClass = 'devui-splitter-pane-fixed'; if (curSize) { @@ -45,10 +48,8 @@ export default defineComponent({ }; watch( - [() => props.size, domRef], - ([size, ele]) => { - setSizeStyle(size, ele); - }, + () => props.size, + setSizeStyle, { immediate: true } ); diff --git a/packages/devui-vue/devui/statistic/__tests__/statistic.spec.ts b/packages/devui-vue/devui/statistic/__tests__/statistic.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..3d5cc320a744ab104a34a52676e279e58a79639d --- /dev/null +++ b/packages/devui-vue/devui/statistic/__tests__/statistic.spec.ts @@ -0,0 +1,8 @@ +import { mount } from '@vue/test-utils'; +import { Statistic } from '../index'; + +describe('statistic test', () => { + it('statistic init render', async () => { + // todo + }) +}) diff --git a/packages/devui-vue/devui/statistic/index.ts b/packages/devui-vue/devui/statistic/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..116831ee7fa9e81dfad9691db365ec9d382c0145 --- /dev/null +++ b/packages/devui-vue/devui/statistic/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue' +import Statistic from './src/statistic' + +Statistic.install = function(app: App): void { + app.component(Statistic.name, Statistic) +} + +export { Statistic } + +export default { + title: 'Statistic 统计数值', + category: '数据展示', + status: undefined, // TODO: 组件若开发完成则填入"已完成",并删除该注释 + install(app: App): void { + app.use(Statistic as any) + } +} diff --git a/packages/devui-vue/devui/statistic/src/statistic-types.ts b/packages/devui-vue/devui/statistic/src/statistic-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..988dcc8d822e39365323d7459807474b68a9e8e4 --- /dev/null +++ b/packages/devui-vue/devui/statistic/src/statistic-types.ts @@ -0,0 +1,25 @@ +import type { PropType, ExtractPropTypes, CSSProperties } from 'vue' + +export const statisticProps = { + title: { + type: String, + default: '' + }, + value: { + type: [Number, String] + }, + prefix: { + type: String + }, + suffix: { + type: String + }, + titleStyle: { + type: Object as PropType + }, + contentStyle: { + type: Object as PropType + } +} as const + +export type StatisticProps = ExtractPropTypes diff --git a/packages/devui-vue/devui/statistic/src/statistic.scss b/packages/devui-vue/devui/statistic/src/statistic.scss new file mode 100644 index 0000000000000000000000000000000000000000..bf0892b46689b6c084ac39495d1558fe3d7cef40 --- /dev/null +++ b/packages/devui-vue/devui/statistic/src/statistic.scss @@ -0,0 +1,36 @@ +.devui-statistic { + box-sizing: border-box; + margin: 0; + padding: 0; + color: #000000d9; + font-size: 14px; + font-variant: tabular-nums; + line-height: 1.5715; + list-style: none; + + &-title { + margin-bottom: 4 px; + color: #00000073; + font-size: 14px; + } + + &-content { + color: #000000d9; + font-size: 24px; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, + "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", + "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + } + + &-prefix { + margin-right: 6px; + } + + &-suffix { + margin-left: 6px; + } + + &--value { + display: inline-block; + } +} diff --git a/packages/devui-vue/devui/statistic/src/statistic.tsx b/packages/devui-vue/devui/statistic/src/statistic.tsx new file mode 100644 index 0000000000000000000000000000000000000000..23b2301424710d7f207b2318e3e81a716ae2eb83 --- /dev/null +++ b/packages/devui-vue/devui/statistic/src/statistic.tsx @@ -0,0 +1,34 @@ +import { defineComponent, computed } from 'vue' +import { statisticProps, StatisticProps } from './statistic-types' +import { analysisValueType } from './utils/separator' +import './statistic.scss' + +export default defineComponent({ + name: 'DStatistic', + props: statisticProps, + emits: [], + inheritAttrs: false, + setup(props: StatisticProps, ctx) { + const StatisticValue = computed(() => { + return analysisValueType(props.value) + }) + return () => { + return ( +
+
+ {props.title} +
+
+ {props.prefix || ctx.slots.prefix?.() ? ( + {ctx.slots.prefix?.() || props.prefix} + ) : null} + {StatisticValue.value} + {props.suffix || ctx.slots.suffix?.() ? ( + {ctx.slots.suffix?.() || props.suffix} + ) : null} +
+
+ ) + } + } +}) diff --git a/packages/devui-vue/devui/statistic/src/utils/separator.ts b/packages/devui-vue/devui/statistic/src/utils/separator.ts new file mode 100644 index 0000000000000000000000000000000000000000..320810fc4deaf278a18b6f15de64329bfcba1227 --- /dev/null +++ b/packages/devui-vue/devui/statistic/src/utils/separator.ts @@ -0,0 +1,20 @@ +export type valueType = string | number + +export const Separator = (SeparatorString: string, SplitDigit = 3): string => { + return ( + SeparatorString.slice(0, SeparatorString.length % SplitDigit) + + (SeparatorString.length % SplitDigit ? ',' : '') + + SeparatorString.slice(SeparatorString.length % SplitDigit).replace( + new RegExp(`\\d\{${SplitDigit}\}`, 'g'), + (n, i) => (i ? ',' : '') + n + ) + ) +} + +export const analysisValueType = (value: valueType): string => { + if (typeof value === 'number') { + return Separator(value.toString()) + } else { + return value + } +} diff --git a/packages/devui-vue/devui/status/index.ts b/packages/devui-vue/devui/status/index.ts index 43bcf996ce9416f7b3625e5a3899d45cf0d67bca..89c0743741475edd7f9f8434844fd522bd500b46 100644 --- a/packages/devui-vue/devui/status/index.ts +++ b/packages/devui-vue/devui/status/index.ts @@ -10,7 +10,7 @@ export { Status } export default { title: 'Status 状态', category: '通用', - status: '100%', + status: '已完成', install(app: App): void { app.use(Status as any) } diff --git a/packages/devui-vue/devui/steps-guide/hooks/use-steps-guide-ctrl.ts b/packages/devui-vue/devui/steps-guide/hooks/use-steps-guide-ctrl.ts index e7ca9d2aa6af5bb977c9853637147310aec13d3d..9c1b13a906e7d05082915e363a21dacddd82d9bc 100644 --- a/packages/devui-vue/devui/steps-guide/hooks/use-steps-guide-ctrl.ts +++ b/packages/devui-vue/devui/steps-guide/hooks/use-steps-guide-ctrl.ts @@ -1,40 +1,25 @@ -import { ref, nextTick, computed, WritableComputedRef, SetupContext } from 'vue' -import { StepsGuideProps, Step } from '../src/steps-guide-types' +import { ref, nextTick } from 'vue' -export function useStepsGuideCtrl( - props: StepsGuideProps, - ctx: SetupContext<('guide-close'|'update:stepIndex')[]>, - updateGuidePosition: Function, - stepIndex: WritableComputedRef - ) { - const stepsCount = computed(() => props.steps.length) - - const closeGuide = () => { - // 缓存关闭前的index, 并在关闭后触发事件 - const _index = stepIndex.value - stepIndex.value = -1 - nextTick(() => { - ctx.emit('guide-close', _index) - }) +export function useStepsGuideCtrl(stepsCount, stepIndex, updateGuidePosition) { + const showSteps = ref(true) + const closeSteps = ():void => { + showSteps.value = false } const setCurrentIndex = (index:number):void => { - if(index !== -1 && props.stepChange()){ - if(index > -1 && index < stepsCount.value) { - stepIndex.value = index - console.log(stepIndex.value, index, stepsCount.value) + if (index > stepsCount.value || index < 0) index = 0 + stepIndex.value = index + if (!showSteps.value) { + showSteps.value = true nextTick(() => { - console.log(stepIndex.value, index, stepsCount.value) updateGuidePosition() }) } else { - console.error(`stepIndex is not within the value range`) + updateGuidePosition() } - } - if(index === -1) closeGuide() } return { - stepsCount, - closeGuide, + showSteps, + closeSteps, setCurrentIndex } } \ No newline at end of file diff --git a/packages/devui-vue/devui/steps-guide/hooks/use-steps-guide-position.ts b/packages/devui-vue/devui/steps-guide/hooks/use-steps-guide-position.ts index 146ce4381794ebaa7cff581d4b95e7e8aa62c7e6..6120300ee6ee1e5ec239de11419aa95a81c50f17 100644 --- a/packages/devui-vue/devui/steps-guide/hooks/use-steps-guide-position.ts +++ b/packages/devui-vue/devui/steps-guide/hooks/use-steps-guide-position.ts @@ -1,19 +1,21 @@ -import { ref, reactive, ComputedRef, nextTick } from 'vue' -import { Step, positionConf, StepsGuideProps } from '../src/steps-guide-types' +import { Ref, ref, reactive, computed, nextTick } from 'vue' +import { Step, positionConf } from '../src/steps-guide-types' -export function useStepsGuidePosition( - props: StepsGuideProps, - currentStep: ComputedRef) { +export function useStepsGuideNav(steps: Step[], stepIndex:Ref) { + + const currentStep = computed(() => { + const _step = steps[stepIndex.value] + _step.position = _step.position || 'top' + return _step + }) const guideClassList = ['devui-steps-guide'] const stepsRef = ref(null) const guidePosition = reactive({ left: '', top: '', - zIndex: props.zIndex + zIndex: 1100 }) - const updateGuidePosition = () => { - if(!currentStep.value) return; const baseTop = window.pageYOffset - document.documentElement.clientTop const baseLeft = window.pageXOffset - document.documentElement.clientLeft const currentStepPosition:positionConf = currentStep.value.position @@ -61,14 +63,13 @@ export function useStepsGuidePosition( } guidePosition.left = _left + 'px' guidePosition.top = _top + 'px' - if(props.scrollToTargetSwitch) { - nextTick(() => { - // 位置更新后滚动视图 - stepGuideElement.scrollIntoView({behavior: "smooth", block: "nearest", inline: "nearest"}) - }) - } + nextTick(() => { + // 位置更新后滚动视图 + stepGuideElement.scrollIntoView({behavior: "smooth", block: "nearest", inline: "nearest"}) + }) } return { + currentStep, stepsRef, guidePosition, guideClassList, diff --git a/packages/devui-vue/devui/steps-guide/index.ts b/packages/devui-vue/devui/steps-guide/index.ts index f783ba87f370259b9443387b7eb206cd88794a9b..3e41d4912f03cb0733cabf48331284f71b49e903 100644 --- a/packages/devui-vue/devui/steps-guide/index.ts +++ b/packages/devui-vue/devui/steps-guide/index.ts @@ -1,7 +1,6 @@ import type { App } from 'vue' import StepsGuide from './src/steps-guide' -import StepsGuideDirective from './directive/steps-guide' StepsGuide.install = function(app: App): void { app.component(StepsGuide.name, StepsGuide) } @@ -11,9 +10,8 @@ export { StepsGuide } export default { title: 'StepsGuide 操作指引', category: '导航', - status: '80%', + status: '50%', install(app: App): void { app.use(StepsGuide as any) - app.directive('StepsGuide', StepsGuideDirective) } } diff --git a/packages/devui-vue/devui/steps-guide/src/steps-guide-types.ts b/packages/devui-vue/devui/steps-guide/src/steps-guide-types.ts index 83219f7933c0b565ff2384ac18e12c3a1091769e..6c712312b44318ff434c7a147053621fcb008516 100644 --- a/packages/devui-vue/devui/steps-guide/src/steps-guide-types.ts +++ b/packages/devui-vue/devui/steps-guide/src/steps-guide-types.ts @@ -14,10 +14,6 @@ export type Step = { } export const stepsGuideProps = { steps: Array as PropType, - stepIndex: { - type: Number, - default: undefined - }, showClose: { type: Boolean, default: true @@ -25,20 +21,6 @@ export const stepsGuideProps = { showDots: { type: Boolean, default: true - }, - scrollToTargetSwitch: { - type: Boolean, - default: true - }, - zIndex: { - type: Number, - default: 1100 - }, - stepChange: { - type: Function, - default(){ - return true - } } } as const diff --git a/packages/devui-vue/devui/steps-guide/src/steps-guide.tsx b/packages/devui-vue/devui/steps-guide/src/steps-guide.tsx index 14c621ce736f61686a3d0ce019933a206799b36d..93cf84bde5af5c8d04b8d810404c949f10fdd881 100644 --- a/packages/devui-vue/devui/steps-guide/src/steps-guide.tsx +++ b/packages/devui-vue/devui/steps-guide/src/steps-guide.tsx @@ -1,70 +1,77 @@ import './steps-guide.scss' -import { computed, ref, defineComponent, Teleport, onMounted } from 'vue' -import { stepsGuideProps, StepsGuideProps, Step } from './steps-guide-types' -import { useStepsGuidePosition, useStepsGuideCtrl } from '../hooks' +import { defineComponent, Teleport, ref, onMounted, computed } from 'vue' +import { stepsGuideProps, StepsGuideProps } from './steps-guide-types' +import { useStepsGuideNav, useStepsGuideCtrl } from '../hooks' export default defineComponent({ name: 'DStepsGuide', props: stepsGuideProps, - emits: ['guide-close', 'update:stepIndex'], + emits: [], setup(props: StepsGuideProps, ctx) { - const stepIndexData = ref((props.stepIndex ?? 0) as number) - const stepIndex = computed({ - set: val => { - if(props.stepIndex != null) { - ctx.emit('update:stepIndex', val) - } - stepIndexData.value = val - }, - get: () => stepIndexData.value - }) - const currentStep = computed(() => { - const _step = props.steps[stepIndex.value] - if(_step) _step.position = _step.position || 'top' - return _step - }) - + const stepsCount = computed(() => props.steps.length - 1) + const stepIndex = ref(0) const { + currentStep, stepsRef, guidePosition, guideClassList, - updateGuidePosition } = useStepsGuidePosition(props, currentStep) - const { - stepsCount, - closeGuide, - setCurrentIndex } = useStepsGuideCtrl(props, ctx, updateGuidePosition, stepIndex) + updateGuidePosition } = useStepsGuideNav(props.steps, stepIndex) + const { showSteps, + closeSteps, + setCurrentIndex } = useStepsGuideCtrl(stepsCount, stepIndex, updateGuidePosition) onMounted(() => { updateGuidePosition() }) - ctx.expose({ - closeGuide, - setCurrentIndex - }) - return () => stepIndex.value > -1 && stepsCount.value > 0 ? + + return { + stepsCount, + stepIndex, + showSteps, + guidePosition, + guideClassList, + stepsRef, + currentStep, + setCurrentIndex, + closeSteps + } + }, + render(props) { + const { showSteps, + guidePosition, + guideClassList, + currentStep, + stepIndex, + stepsCount, + setCurrentIndex, + closeSteps, + showClose, + showDots } = props + + return showSteps ? ( -
+
-

{currentStep.value.title}

- {props.showClose ?
: null} -
{currentStep.value.content}
+

{currentStep.title}

+ {showClose ?
: null} +
{currentStep.content}
{ - props.showDots ? + showDots ?
{props.steps.map((step, index) => { - return + return })}
: null }
- {stepIndex.value > 0 ?
setCurrentIndex(stepIndex.value - 1)}>{'上一步'}
: null} - {stepIndex.value === stepsCount.value - 1 ? -
{'我知道啦'}
: -
{ setCurrentIndex(stepIndex.value + 1) }}>{'我知道啦,继续'}
} + {stepIndex > 0 ?
setCurrentIndex(--props.stepIndex)}>{'上一步'}
: null} + {stepIndex === stepsCount ? +
{'我知道啦'}
: +
{ setCurrentIndex(++props.stepIndex) }}>{'我知道啦,继续'}
}
diff --git a/packages/devui-vue/devui/switch/index.ts b/packages/devui-vue/devui/switch/index.ts index c834c231e812c3e116f6002cb06acfd5da1e704b..f220103c1398dc5816aa631dd815804adc17259d 100644 --- a/packages/devui-vue/devui/switch/index.ts +++ b/packages/devui-vue/devui/switch/index.ts @@ -10,7 +10,7 @@ export { Switch } export default { title: 'Switch 开关', category: '数据录入', - status: '100%', + status: '已完成', install(app: App): void { app.use(Switch as any) } diff --git a/packages/devui-vue/devui/table/src/body/body.scss b/packages/devui-vue/devui/table/src/body/body.scss index fc9ea1f32078f75adb246e6c5316be46283dfbfd..ea2657279dfcdaccd4f275b9704afe884975afe3 100644 --- a/packages/devui-vue/devui/table/src/body/body.scss +++ b/packages/devui-vue/devui/table/src/body/body.scss @@ -8,7 +8,7 @@ border-bottom: 1px solid $devui-dividing-line; background-color: $devui-global-bg-normal; - &.hover-enabled:hover { + &:hover { background-color: $devui-list-item-hover-bg; } @@ -18,16 +18,3 @@ } } } - - -.devui-sticky-cell { - position: sticky; - z-index: 5; - background-color: inherit; - &.left { - box-shadow: rgba(0,0,0,.05) $devui-shadow-length-slide-right; - } - &.right { - box-shadow: rgba(0,0,0,.05) $devui-shadow-length-slide-left; - } -} diff --git a/packages/devui-vue/devui/table/src/body/body.tsx b/packages/devui-vue/devui/table/src/body/body.tsx index 46f0194033f69310281ec89d8ab0ae7f83700f60..9b02b8679897d1deb3d3347c868d72b6e5ad4934 100644 --- a/packages/devui-vue/devui/table/src/body/body.tsx +++ b/packages/devui-vue/devui/table/src/body/body.tsx @@ -1,76 +1,33 @@ -import { defineComponent, inject, computed, PropType, toRef } from 'vue'; -import { TABLE_TOKEN } from '../table.type'; -import { Checkbox } from '../../../checkbox'; - +import { defineComponent } from 'vue'; +import { TableBodyProps, TableBodyPropsTypes } from './body.type' +import { useTableBody } from './use-body'; import './body.scss'; -import { Column } from '../column/column.type'; -import { useFixedColumn } from '../use-table'; export default defineComponent({ name: 'DTableBody', - setup() { - const table = inject(TABLE_TOKEN); - const { - _data: data, - _columns: columns, - _checkList: checkList, - isFixedLeft - } = table.store.states; - - // 移动到行上是否高亮 - const hoverEnabled = computed(() => table.props.rowHoveredHighlight); + props: TableBodyProps, + setup(props: TableBodyPropsTypes) { + const { rowColumns } = useTableBody(props); - // 行前的 checkbox - const tdAttrs = computed(() => isFixedLeft.value ? ({ - class: 'devui-sticky-cell left', - style: "left:0;" - }) : null); - const renderCheckbox = (index: number) => table.props.checkable ? ( - - - - ) : null; + return { rowColumns }; + }, + render() { + const { rowColumns } = this; - return () => ( + return ( - {data.value.map((row, rowIndex) => { + {rowColumns.map((row, rowIndex) => { return ( - - {renderCheckbox(rowIndex)} - {columns.value.map((column, index) => ( - - ))} + + {row.columns.map((column, index) => { + return ( + {column.renderCell({ row, column, $index: index })} + ); + })} ); })} - ) - } -}); - - -const TD = defineComponent({ - props: { - column: { - type: Object as PropType - }, - row: { - type: Object - }, - index: { - type: Number, - } - }, - setup(props: { column: Column, row: any, index: number }) { - const column = toRef(props, 'column'); - - // 固定列 - const { stickyCell, offsetStyle } = useFixedColumn(column); - - return () => ( - - {column.value.renderCell(props.row, props.index)} - ); - } -}); + }, +}); \ No newline at end of file diff --git a/packages/devui-vue/devui/table/src/body/body.type.ts b/packages/devui-vue/devui/table/src/body/body.type.ts index b80250e0c5a7fb926ae6959b26754bc98fecbe98..c1febde00fb051c2b818c58fde03ba5004b0a021 100644 --- a/packages/devui-vue/devui/table/src/body/body.type.ts +++ b/packages/devui-vue/devui/table/src/body/body.type.ts @@ -1,6 +1,10 @@ import { ExtractPropTypes } from 'vue'; export const TableBodyProps = { -} as const; + store: { + type: Object, + default: {}, + }, +}; export type TableBodyPropsTypes = ExtractPropTypes; diff --git a/packages/devui-vue/devui/table/src/body/use-body.ts b/packages/devui-vue/devui/table/src/body/use-body.ts index 49d6726547e9e8aea70066e27da7b486ae8d18d8..1657a06b50646cc594957432254062c6035cd1a2 100644 --- a/packages/devui-vue/devui/table/src/body/use-body.ts +++ b/packages/devui-vue/devui/table/src/body/use-body.ts @@ -1,7 +1,15 @@ -import { computed, ComputedRef } from 'vue'; -import { Column } from '../column/column.type'; +import { computed } from 'vue'; import { TableBodyPropsTypes } from './body.type' -interface Data { - rowColumns: ComputedRef<(Record & { columns: Column[]; })[]> -} +export function useTableBody(props: TableBodyPropsTypes): any { + const storeData = props.store.states; + const rowColumns = computed(() => { + return storeData._data.value.map((row) => { + const obj = Object.assign({}, row); + obj.columns = storeData._columns.value; + return obj; + }); + }); + + return { rowColumns }; +} \ No newline at end of file diff --git a/packages/devui-vue/devui/table/src/colgroup/colgroup.tsx b/packages/devui-vue/devui/table/src/colgroup/colgroup.tsx index fa16eaea3b96fbd52197dc9af84ebbe681fa2253..93e7197d8466045978538007fbb68379a8a8992b 100644 --- a/packages/devui-vue/devui/table/src/colgroup/colgroup.tsx +++ b/packages/devui-vue/devui/table/src/colgroup/colgroup.tsx @@ -1,22 +1,23 @@ import { inject, defineComponent } from 'vue'; -import { TABLE_TOKEN } from '../table.type'; +import { Table } from '../table.type'; +import { Column } from '../column/column.type'; export default defineComponent({ name: 'DColGroup', setup() { - const parent = inject(TABLE_TOKEN); - const columns = parent.store.states._columns; - return () => ( - parent.props.tableLayout === 'fixed' ? ( - - {/* 如果是 checkable,那么需要指定 col */} - {parent.props.checkable ? : null} - {columns.value.map((column, index) => { - return ; - })} - - ) : null + const parent: Table = inject('table'); + const columns: Column[] = parent.store.states._columns; + return { columns }; + }, + render() { + const { columns } = this; + return ( + + {columns.map((column, index) => { + return ; + })} + ); - } + }, }); \ No newline at end of file diff --git a/packages/devui-vue/devui/table/src/column/column.tsx b/packages/devui-vue/devui/table/src/column/column.tsx index bf92f239ec1c4a1c6f1cb405089950dec5252870..60ef5e04cf8e85ae459d43673fd1ce60219978ab 100644 --- a/packages/devui-vue/devui/table/src/column/column.tsx +++ b/packages/devui-vue/devui/table/src/column/column.tsx @@ -1,34 +1,30 @@ -import { inject, defineComponent, onBeforeUnmount, onMounted, toRefs, watch } from 'vue'; +import { inject, defineComponent, onBeforeMount, onMounted } from 'vue'; import { Column, TableColumnProps, TableColumnPropsTypes, } from './column.type' -import { TABLE_TOKEN } from '../table.type'; -import { createColumn } from './use-column'; +import { Table } from '../table.type'; +import { useRender } from './use-column'; export default defineComponent({ name: 'DColumn', props: TableColumnProps, - setup(props: TableColumnPropsTypes, ctx) { - /* - ctx.slots : { - customFilterTemplate: Slot - } - */ - const column = createColumn(toRefs(props), ctx.slots); + setup(props: TableColumnPropsTypes) { + const column: Column = { + field: props.field, + header: props.header, + }; + const parent: Table = inject('table'); + const { setColumnWidth, setColumnRender } = useRender(props); - const parent = inject(TABLE_TOKEN); + onBeforeMount(() => { + setColumnWidth(column); + setColumnRender(column); + }); onMounted(() => { parent.store.insertColumn(column); - watch(() => column.order, () => { - parent.store.sortColumn(); - }); - }); - - onBeforeUnmount(() => { - parent.store.removeColumn(column); }); }, render() { diff --git a/packages/devui-vue/devui/table/src/column/column.type.ts b/packages/devui-vue/devui/table/src/column/column.type.ts index 99b4700ad11ef7d3fc150d7551406bea9ed4441d..cdab04098202602701a11228536e6d9339695253 100644 --- a/packages/devui-vue/devui/table/src/column/column.type.ts +++ b/packages/devui-vue/devui/table/src/column/column.type.ts @@ -1,4 +1,4 @@ -import { PropType, ExtractPropTypes, VNode, Slot } from 'vue'; +import { PropType, ExtractPropTypes, VNode } from 'vue'; export const TableColumnProps = { header: { @@ -18,78 +18,21 @@ export const TableColumnProps = { default: 80, }, formatter: { - type: Function as PropType, - }, - order: { - type: Number, - default: 0 - }, - sortable: { - type: Boolean, - default: false - }, - compareFn: { - type: Function as PropType, - default: (field: string, a: any, b: any): boolean => a[field] < b[field] - }, - filterable: { - type: Boolean, - default: false - }, - filterMultiple: { - type: Boolean, - default: false - }, - filterList: { - type: Array as PropType, - default: [] - }, - fixedLeft: { - type: String, - }, - fixedRight: { - type: String, + type: Function as PropType< + (row: any, column: Column, cellValue, index: number) => VNode + >, }, }; export type TableColumnPropsTypes = ExtractPropTypes; -export type Formatter = (row: T, cellValue: R, index: number) => VNode[]; - -export type CompareFn = (field: string, a: T, b: T) => boolean; - -export type FilterResults = (string | number)[]; - -export interface CustomFilterProps { - value: FilterResults - onChange: (value: FilterResults) => void -} - -export type CustomFilterSlot = (props: CustomFilterProps) => VNode[]; - -export interface FilterConfig { - id: number | string - name: string - value: any - checked?: boolean -} -export interface Column = any> { +export interface Column { field?: string width?: number minWidth?: number realWidth?: number header?: string - order?: number - sortable?: boolean - filterable?: boolean - filterMultiple?: boolean - filterList?: FilterConfig[] - fixedLeft?: string - fixedRight?: string renderHeader?: () => void - renderCell?: (row: T, index: number) => void - formatter?: Formatter - compareFn?: CompareFn - customFilterTemplate?: CustomFilterSlot - subColumns?: Slot + renderCell?: (data: any) => void + formatter?: (row: any, column: Column, cellValue, index: number) => VNode } \ No newline at end of file diff --git a/packages/devui-vue/devui/table/src/column/use-column.ts b/packages/devui-vue/devui/table/src/column/use-column.ts index 3c63818d2f2a657e683cdf233d604ec84891cee3..7c5fc4ce546f06d6694a7e4f318cb9b0309565bb 100644 --- a/packages/devui-vue/devui/table/src/column/use-column.ts +++ b/packages/devui-vue/devui/table/src/column/use-column.ts @@ -1,85 +1,45 @@ -import { watch, reactive, onBeforeMount, ToRefs, Slots, h } from 'vue'; +import { ref } from 'vue'; import { Column, TableColumnPropsTypes } from './column.type' import { formatWidth, formatMinWidth } from '../utils'; - -export function createColumn = any>( - props: ToRefs, - templates: Slots -): Column { - const { - field, - header, - sortable, - width, - minWidth, - formatter, - compareFn, - filterable, - filterList, - filterMultiple, - order, - fixedLeft, - fixedRight - } = props; - const column: Column = reactive({}); - - watch([field, header, order], ([field, header, order]) => { - column.field = field; - column.header = header; - column.order = order; - }, { immediate: true }); - - // 排序功能 - watch([sortable, compareFn], ([sortable, compareFn]) => { - column.sortable = sortable; - column.compareFn = compareFn; - }) - - // 过滤功能 - watch([ - filterable, - filterList, - filterMultiple, - ], ([filterable, filterList, filterMultiple]) => { - column.filterable = filterable; - column.filterMultiple = filterMultiple; - column.filterList = filterList; - }, { immediate: true }) - - // 固定左右功能 - watch([fixedLeft, fixedRight], ([left, right]) => { - column.fixedLeft = left; - column.fixedRight = right; - }, { immediate: true }); - - // 宽度 - watch([width, minWidth], ([width, minWidth]) => { - column.width = formatWidth(width); - column.minWidth = formatMinWidth(minWidth); +export function useRender(props: TableColumnPropsTypes): any { + const formatedWidth = ref(formatWidth(props.width)); + const formatedMinWidth = ref(formatMinWidth(props.minWidth)); + const setColumnWidth = (column: Column) => { + column.width = formatedWidth.value; + column.minWidth = formatedMinWidth.value; column.realWidth = column.width || column.minWidth; - }); - - // 基础渲染功能 - onBeforeMount(() => { - column.renderHeader = defaultRenderHeader; - column.renderCell = defaultRenderCell; - column.formatter = formatter.value; - column.customFilterTemplate = templates.customFilterTemplate; - column.subColumns = templates.subColumns; - }); - - return column; + return column; + }; + + const setColumnRender = (column: Column) => { + column.renderHeader = () => { + return defaultRenderHeader(column); + }; + column.renderCell = (data) => { + return defaultRenderCell(data); + }; + }; + + return { setColumnWidth, setColumnRender }; } -function defaultRenderHeader(this: Column) { - return h('span', { class: 'title' }, this.header); +function defaultRenderHeader(column: Column) { + return column.header; } -function defaultRenderCell>(this: Column, rowData: T, index: number) { - const value = rowData[this.field]; - if (this.formatter) { - return this.formatter(rowData, value, index); +function defaultRenderCell({ + row, + column, + $index, +}: { + row: any + column: Column + $index: number +}) { + const value = row[column.field]; + if (column.formatter) { + return column.formatter(row, column, value, $index); } - return value?.toString?.() ?? ''; -} + return value?.toString?.() || ''; +} \ No newline at end of file diff --git a/packages/devui-vue/devui/table/src/header/header.scss b/packages/devui-vue/devui/table/src/header/header.scss index 9a467e994f131cd5fa68a710cc92a4f694652141..21e88bf495006c749a79c1782c1d840f70b134b0 100644 --- a/packages/devui-vue/devui/table/src/header/header.scss +++ b/packages/devui-vue/devui/table/src/header/header.scss @@ -11,28 +11,10 @@ th { text-align: left; - padding: 0; + padding: 12px 10px; border: none; } } - - .header-container { - position: relative; - display: flex; - align-items: center; - padding-left: 2px; - padding-right: 8px; - - .title { - display: inline-block; - line-height: 36px; - vertical-align: middle; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - cursor: default; - } - } } .header-bg { diff --git a/packages/devui-vue/devui/table/src/header/header.tsx b/packages/devui-vue/devui/table/src/header/header.tsx index 610a002fe77eadcd50bcb1cc4b080176584145a6..a05a80b7ae6f8189134368ea1d71f4a2cb582f9f 100644 --- a/packages/devui-vue/devui/table/src/header/header.tsx +++ b/packages/devui-vue/devui/table/src/header/header.tsx @@ -1,89 +1,28 @@ -import { defineComponent, inject, computed, PropType, toRefs } from 'vue'; -import { TABLE_TOKEN } from '../table.type'; -import { Column } from '../column/column.type'; - -import { Checkbox } from '../../../checkbox'; -import { Sort } from './sort'; -import { Filter } from './filter'; - +import { defineComponent, toRefs } from 'vue'; +import { TableHeaderProps, TableHeaderPropsTypes } from './header.type' import './header.scss'; -import '../body/body.scss'; -import { useFliter, useSort } from './use-header'; -import { useFixedColumn } from '../use-table'; - export default defineComponent({ name: 'DTableHeader', - setup() { - const table = inject(TABLE_TOKEN); - const { - _checkAll: checkAll, - _halfChecked: halfChecked, - _columns: columns, - isFixedLeft - } = table.store.states; + props: TableHeaderProps, + setup(props: TableHeaderPropsTypes) { + const { store } = toRefs(props) + const columns = store.value.states._columns.value; - const thAttrs = computed(() => isFixedLeft.value ? ({ - class: 'devui-sticky-cell left', - style: "left:0;" - }) : null); - const checkbox = computed(() => table.props.checkable ? ( - - - - ) : null); - - return () => { - return ( - - - {checkbox.value} - {columns.value.map((column, index) => ( - - ))} - - - ) - } - } -}); - -const Th = defineComponent({ - props: { - column: { - type: Object as PropType, - required: true + return { + columns, } }, - setup(props: { column: Column; }) { - const table = inject(TABLE_TOKEN); - const { column } = toRefs(props); - - // 排序功能 - const directionRef = useSort(table.store, column); - - // 过滤器 - const filteredRef = useFliter(table.store, column); - - // 固定列功能 - const { stickyCell, offsetStyle } = useFixedColumn(column); - - return () => ( - -
- {props.column.renderHeader()} - {props.column.filterable && } -
- {props.column.sortable && } - + render() { + const { columns } = this + return ( + + + {columns.map((column, index) => { + return {column.renderHeader()}; + })} + + ) } }); \ No newline at end of file diff --git a/packages/devui-vue/devui/table/src/header/header.type.ts b/packages/devui-vue/devui/table/src/header/header.type.ts index e51c2ad264452e1ca745036ec58dbe4468e28056..3369aa9d76063355dcfc33c108438a50279b2226 100644 --- a/packages/devui-vue/devui/table/src/header/header.type.ts +++ b/packages/devui-vue/devui/table/src/header/header.type.ts @@ -1,6 +1,10 @@ import { ExtractPropTypes } from 'vue'; export const TableHeaderProps = { -} as const; + store: { + type: Object, + default: {}, + }, +}; export type TableHeaderPropsTypes = ExtractPropTypes; diff --git a/packages/devui-vue/devui/table/src/store/index.ts b/packages/devui-vue/devui/table/src/store/index.ts index 205ff0fac236ed86e1ca6988f014bd68924b738a..b7138064c7b394b6ba8e68e79d6a4c5c1cd194c2 100644 --- a/packages/devui-vue/devui/table/src/store/index.ts +++ b/packages/devui-vue/devui/table/src/store/index.ts @@ -1,218 +1,30 @@ -import { watch, Ref, ref, computed } from 'vue'; -import { Column, CompareFn, FilterResults } from '../column/column.type'; -import { SortDirection } from '../table.type'; -export interface TableStore> { - states: { - _data: Ref - _columns: Ref - _checkList: Ref - _checkAll: Ref - _halfChecked: Ref - isFixedLeft: Ref - } - insertColumn(column: Column): void - sortColumn(): void - removeColumn(column: Column): void - getCheckedRows(): T[] - sortData(field: string, direction: SortDirection, compareFn: CompareFn): void - filterData(field: string, results: FilterResults): void - resetFilterData(): void -} - -export function createStore(dataSource: Ref): TableStore { - const _data: Ref = ref([]); - watch(dataSource, (value: T[]) => { - _data.value = [...value]; - }, { deep: true, immediate: true }); - - const { _columns, insertColumn, removeColumn, sortColumn } = createColumnGenerator(); - const { _checkAll, _checkList, _halfChecked, getCheckedRows } = createSelection(dataSource, _data); - const { sortData } = createSorter(dataSource, _data); - const { filterData, resetFilterData } = createFilter(dataSource, _data); +import { ref, watch } from 'vue'; +import { TablePropsTypes } from '../table.type'; +import { Column } from '../column/column.type'; - const { isFixedLeft } = createFixedLogic(_columns); +export function createStore(props: TablePropsTypes): any { + const _data = ref([]); + const _columns = ref([]); + updateData(); - return { - states: { - _data, - _columns, - _checkList, - _checkAll, - _halfChecked, - isFixedLeft - }, - insertColumn, - sortColumn, - removeColumn, - getCheckedRows, - sortData, - filterData, - resetFilterData - }; -} + watch(() => props.data, updateData, { deep: true }); -/** - * 列生成器 - * @returns - */ -const createColumnGenerator = () => { - const _columns: Ref = ref([]); + function updateData() { + _data.value = []; + props.data.forEach((item) => { + _data.value.push(item); + }); + } - /** - * 插入当前列 - * @param {Column} column - */ const insertColumn = (column: Column) => { _columns.value.push(column); - // 实际上就是插入排序 - _columns.value.sort((a, b) => a.order > b.order ? 1 : -1); }; - /** - * 对 column 进行排序 - */ - const sortColumn = () => { - _columns.value.sort((a, b) => a.order > b.order ? 1 : -1); - } - - /** - * 移除当前列 - * @param {Column} column - * @returns - */ - const removeColumn = (column: Column) => { - const i = _columns.value.findIndex((v) => v === column); - if (i === -1) { - return; - } - _columns.value.splice(i, 1); - } - return { _columns, insertColumn, removeColumn, sortColumn }; -} - -/** - * 选择功能 - * @param dataSource - * @param _data - * @returns - */ -const createSelection = (dataSource: Ref, _data: Ref) => { - const _checkList: Ref = ref([]); - const _checkAllRecord: Ref = ref(false); - const _checkAll: Ref = computed({ - get: () => _checkAllRecord.value, - set: (val: boolean) => { - _checkAllRecord.value = val; - // 只有在 set 的时候变更 _checkList 的数据 - for (let i = 0; i < _checkList.value.length; i++) { - _checkList.value[i] = val; - } - } - }); - const _halfChecked = ref(false); - - watch(dataSource, (value: T[]) => { - _checkList.value = new Array(value.length).fill(false); - }, { deep: true, immediate: true }); - - // checkList 只有全为true的时候 - watch(_checkList, (list) => { - if (list.length === 0) { - return; - } - let allTrue = true; - let allFalse = true; - for (let i = 0; i < list.length; i++) { - allTrue &&= list[i]; - allFalse &&= !list[i]; - } - - _checkAllRecord.value = allTrue; - _halfChecked.value = !(allFalse || allTrue); - - }, { immediate: true, deep: true }); - - /** - * 获取当前已选数据 - * @returns {T[]} - */ - const getCheckedRows = (): T[] => { - return _data.value.filter((_, index) => _checkList.value[index]); - } - return { - _checkList, - _checkAll, - _halfChecked, - getCheckedRows + insertColumn, + states: { + _data, + _columns, + }, }; -} - -/** - * 排序功能 - * @template T - * @param dataSource - * @param _data - */ -const createSorter = (dataSource: Ref, _data: Ref) => { - /** - * 对数据进行排序 - * @param {string} field - * @param {SortDirection} direction - * @param {CompareFn} compareFn - */ - const sortData = ( - field: string, - direction: SortDirection, - compareFn: CompareFn = (field: string, a: T, b: T) => a[field] > b[field] - ) => { - if (direction === 'ASC') { - _data.value = _data.value.sort((a, b) => compareFn(field, a, b) ? 1 : -1); - } else if (direction === 'DESC') { - _data.value = _data.value.sort((a, b) => !compareFn(field, a, b) ? 1 : -1); - } else { - _data.value = [...dataSource.value]; - } - } - return { sortData }; -} - -/** - * 过滤功能 - * @template T - * @param dataSource - * @param _data - * @returns - */ -const createFilter = (dataSource: Ref, _data: Ref) => { - // 过滤数据所需要的 - const fieldSet = new Set(); - /** - * 过滤数据 - */ - const filterData = (field: string, results: FilterResults) => { - fieldSet.add(field); - const fields = [...fieldSet]; - _data.value = dataSource.value.filter(item => { - return fields.reduce((prev, field) => { - return prev && (results.indexOf(item[field]) !== -1) - }, true); - }); - } - /** - * 重置数据为最开始的状态 - */ - const resetFilterData = () => { - fieldSet.clear(); - _data.value = [...dataSource.value]; - } - return { filterData, resetFilterData }; -} - -const createFixedLogic = (columns: Ref) => { - const isFixedLeft = computed(() => { - return columns.value.reduce((prev, current) => prev || !!current.fixedLeft, false); - }); - - return { isFixedLeft } -} +} \ No newline at end of file diff --git a/packages/devui-vue/devui/table/src/table.scss b/packages/devui-vue/devui/table/src/table.scss index 125f13cc1f246a333059eb53fae0cdded2686eec..48d9e7cf3180dea7646f67175ebe7ba3268b574f 100644 --- a/packages/devui-vue/devui/table/src/table.scss +++ b/packages/devui-vue/devui/table/src/table.scss @@ -6,13 +6,10 @@ width: 100%; border-spacing: 0; border: none; - margin: 0; - padding: 0; &-wrapper { width: 100%; overflow-x: auto; - padding-top: 8px; } &-striped { @@ -26,22 +23,6 @@ font-size: $devui-font-size; text-align: center; } - - &-view { - display: flex; - flex-direction: column; - position: relative; - height: 100%; - - & .scroll-view { - flex: 1; - overflow: scroll; - } - } -} - -.table-layout-auto { - table-layout: auto; } .table-layout-auto { diff --git a/packages/devui-vue/devui/table/src/table.tsx b/packages/devui-vue/devui/table/src/table.tsx index 4e52c19a62217c8b368dbfbb6c68b1ef2ddef476..83146778b7d6595233b33ac52a0b792113a2ab9f 100644 --- a/packages/devui-vue/devui/table/src/table.tsx +++ b/packages/devui-vue/devui/table/src/table.tsx @@ -1,68 +1,36 @@ -import { provide, defineComponent, getCurrentInstance, computed, toRef } from 'vue'; -import { Table, TableProps, TablePropsTypes, TABLE_TOKEN } from './table.type'; +import { provide, defineComponent, getCurrentInstance } from 'vue'; +import { Table, TableProps, TablePropsTypes } from './table.type'; import { useTable } from './use-table'; import { createStore } from './store'; import ColGroup from './colgroup/colgroup'; import TableHeader from './header/header'; import TableBody from './body/body'; - import './table.scss'; - export default defineComponent({ name: 'DTable', props: TableProps, - setup(props: TablePropsTypes, ctx) { + setup(props: TablePropsTypes) { const table = getCurrentInstance() as Table; - const store = createStore(toRef(props, 'data')); + const store = createStore(props); table.store = store; - provide(TABLE_TOKEN, table); - - const { classes, style } = useTable(props); - - const isEmpty = computed(() => props.data.length === 0); - - const fixHeaderCompo = computed(() => { - return ( -
-
- - - -
-
-
- - - {!isEmpty.value && } -
-
-
- ); - }); - - const normalHeaderCompo = computed(() => { - return ( - + const { classes } = useTable(props); + provide('table', table); + + return { classes, store }; + }, + render() { + const { classes, data, store, $slots } = this; + return ( +
+ {$slots.default()} +
- - {!isEmpty.value && } + + {!!data.length && }
- ) - }); - - ctx.expose({ - getCheckedRows() { - return store.getCheckedRows(); - } - }); - - return () => ( -
- {ctx.slots.default()} - {props.fixHeader ? fixHeaderCompo.value : normalHeaderCompo.value} - {isEmpty.value &&
No Data
} + {!data.length &&
No Data
}
); - } + }, }); diff --git a/packages/devui-vue/devui/table/src/table.type.ts b/packages/devui-vue/devui/table/src/table.type.ts index 369441f95e8bcf231ba9b4cba75163371a9697b5..b9132f45ec9a57251db60d09b475cab66b56bf1c 100644 --- a/packages/devui-vue/devui/table/src/table.type.ts +++ b/packages/devui-vue/devui/table/src/table.type.ts @@ -1,94 +1,26 @@ -import { PropType, ExtractPropTypes, ComponentInternalInstance, InjectionKey } from 'vue'; -import { TableStore } from './store'; - -export type TableSize = 'sm' | 'md' | 'lg'; +import { PropType, ExtractPropTypes, ComponentInternalInstance } from 'vue'; export const TableProps = { data: { - type: Array as PropType[]>, + type: Array as PropType, default: [], }, striped: { type: Boolean, default: false, }, - scrollable: { + headerBg:{ type: Boolean, default: false }, - maxWidth: { - type: String, - }, - maxHeight: { - type: String, - }, - tableWidth: { - type: String, - }, - tableHeight: { - type: String, - }, - size: { - type: String as PropType, - validator(value: string): boolean { - return value === 'sm' || value === 'md' || value === 'lg'; - } - }, - rowHoveredHighlight: { - type: Boolean, - default: true - }, - fixHeader: { - type: Boolean, - default: false - }, - checkable: { - type: Boolean, - default: true - }, - tableLayout: { + tableLayout:{ type: String as PropType<'fixed' | 'auto'>, - default: 'auto', - validator(v: string) { - return v === 'fixed' || v === 'auto'; - } - }, - showLoading: { - type: Boolean, - default: false - }, - headerBg: { - type: Boolean, - default: false + default: 'fixed' } }; export type TablePropsTypes = ExtractPropTypes; -export interface Table> extends ComponentInternalInstance { - store: TableStore - props: TablePropsTypes +export interface Table extends ComponentInternalInstance { + store: any } - -// export interface TableCheckStatusArg { -// pageAllChecked?: boolean; // 全选 -// pageHalfChecked?: boolean; // 半选 -// } - -// export interface RowToggleStatusEventArg { -// rowItem: any; // 行数据 -// open: boolean; // 子表格是否展开 -// } - -export interface TableMethods> { - getCheckedRows(): T[] - // setRowCheckStatus(arg: TableCheckStatusArg): void - // setTableCheckStatus(arg: RowToggleStatusEventArg): void - // setRowChildToggleStatus(): void - // setTableChildrenToggleStatus(): void - // cancelEditingStatus(): void -} - -export const TABLE_TOKEN: InjectionKey = Symbol(); - -export type SortDirection = 'ASC' | 'DESC' | ''; diff --git a/packages/devui-vue/devui/table/src/use-table.ts b/packages/devui-vue/devui/table/src/use-table.ts index 641e775f5f1def690cb521826f9508cc3647a2c9..e375cbbb4ca06fb68921d87c421407cb381883f2 100644 --- a/packages/devui-vue/devui/table/src/use-table.ts +++ b/packages/devui-vue/devui/table/src/use-table.ts @@ -1,57 +1,13 @@ -import { computed, ComputedRef, CSSProperties, Ref, ToRefs } from 'vue'; -import { Column } from './column/column.type'; +import { computed } from 'vue'; import { TablePropsTypes } from './table.type'; -interface TableConfig { - classes: ComputedRef> - style: ComputedRef -} - -export function useTable(props: TablePropsTypes): TableConfig { +export function useTable(props: TablePropsTypes): any { const classes = computed(() => ({ 'devui-table': true, 'devui-table-striped': props.striped, 'header-bg': props.headerBg, 'table-layout-auto': props.tableLayout === 'auto' })); - const style: ComputedRef = computed(() => ({ - maxHeight: props.maxHeight, - maxWidth: props.maxWidth, - height: props.tableHeight, - width: props.tableWidth - })); - return { classes, style }; -} - - -export const useFixedColumn = (column: Ref): ToRefs<{ stickyCell: string; offsetStyle: string; }> => { - const stickyCell = computed(() => { - const col = column.value; - if (col.fixedLeft) { - return `devui-sticky-cell left`; - } - - if (col.fixedRight) { - return `devui-sticky-cell right`; - } - return undefined; - }); - - const offsetStyle = computed(() => { - const col = column.value; - if (col.fixedLeft) { - return `left:${col.fixedLeft}`; - } - - if (col.fixedRight) { - return `right:${col.fixedRight}`; - } - - return undefined; - }); - return { - stickyCell, - offsetStyle - }; -} + return { classes }; +} \ No newline at end of file diff --git a/packages/devui-vue/devui/tag-input/index.ts b/packages/devui-vue/devui/tag-input/index.ts index 45a127cf3275dc331b9fa3cba95a7c6dbfa05ba7..414add7d0417c370cab4b8cb71ad50f668b6ae9a 100644 --- a/packages/devui-vue/devui/tag-input/index.ts +++ b/packages/devui-vue/devui/tag-input/index.ts @@ -10,7 +10,7 @@ export { TagInput } export default { title: 'TagInput 标签输入框', category: '数据录入', - status: '100%', + status: '已完成', install(app: App): void { app.use(TagInput as any) } diff --git a/packages/devui-vue/devui/tag/index.ts b/packages/devui-vue/devui/tag/index.ts index d3b5f9167e0ce43c41936c8e1b44ab788ae50af9..43310285f5c37a45fdbee30011f4ca0b4bb64b92 100644 --- a/packages/devui-vue/devui/tag/index.ts +++ b/packages/devui-vue/devui/tag/index.ts @@ -10,7 +10,7 @@ export { Tag } export default { title: 'Tag 标签', category: '数据展示', - status: '70%', // TODO: 组件若开发完成则填入"已完成",并删除该注释 + status: '20%', // TODO: 组件若开发完成则填入"已完成",并删除该注释 install(app: App): void { app.use(Tag as any) } diff --git a/packages/devui-vue/devui/tag/src/hooks/index.ts b/packages/devui-vue/devui/tag/src/hooks/index.ts index ff702f1951e71c1a6cadfd5319b47675852dd153..4f2a81330a29bc727b263472411883487b12f5f4 100644 --- a/packages/devui-vue/devui/tag/src/hooks/index.ts +++ b/packages/devui-vue/devui/tag/src/hooks/index.ts @@ -1,4 +1,3 @@ -import useClass from './use-class' -import useColor from './use-color' +import useStyle from './use-style' -export { useClass, useColor } +export { useStyle } diff --git a/packages/devui-vue/devui/tag/src/hooks/use-style.ts b/packages/devui-vue/devui/tag/src/hooks/use-style.ts new file mode 100644 index 0000000000000000000000000000000000000000..2dbb29d72cc7711ee2481484387b90a5ae9d0a01 --- /dev/null +++ b/packages/devui-vue/devui/tag/src/hooks/use-style.ts @@ -0,0 +1,10 @@ +import { computed } from 'vue' +import { tagProps, TagProps } from '../tag-types' + +export default function (props: TagProps) { + return computed(() => { + const { type } = props + + return `devui-tag devui-tag-${type || 'default'}` + }) +} diff --git a/packages/devui-vue/devui/tag/src/tag-types.ts b/packages/devui-vue/devui/tag/src/tag-types.ts index cccdb2f1470d87d800dbf4ffd4b0e1a5382e1961..f8fd95a57f4f119dcc6f936a55362e4121b9a462 100644 --- a/packages/devui-vue/devui/tag/src/tag-types.ts +++ b/packages/devui-vue/devui/tag/src/tag-types.ts @@ -10,18 +10,6 @@ export const tagProps = { color: { type: String as PropType, default: '' - }, - titleContent: { - type: String as PropType, - default: '' - }, - checked: { - type: Boolean as PropType, - default: false - }, - deletable: { - type: Boolean as PropType, - default: false } } as const diff --git a/packages/devui-vue/devui/tag/src/tag.scss b/packages/devui-vue/devui/tag/src/tag.scss index 0ef0d58515fdb73d651df94f080a92170f70c73e..8c4fab2446c573f8a75ca71c8f6f9721c5eef1fc 100644 --- a/packages/devui-vue/devui/tag/src/tag.scss +++ b/packages/devui-vue/devui/tag/src/tag.scss @@ -25,9 +25,6 @@ $devui-tag-normal-config: ( color: $devui-danger, background-color: $devui-danger-bg, border-color: $devui-danger-line - ), - colorful: ( - background-color: #fff ) ); @@ -48,7 +45,7 @@ $devui-tag-normal-config: ( position: relative; cursor: default; - @each $type in default, primary, success, warning, danger, colorful { + @each $type in default, primary, success, warning, danger { &.devui-tag-#{$type} { @each $key, $value in map-get($devui-tag-normal-config, $type) { #{$key}: $value; @@ -56,18 +53,4 @@ $devui-tag-normal-config: ( } } } - .remove-button { - display: inline-block; - margin-left: 12px; - font-size: $devui-font-size-icon; - cursor: pointer; - width: 12px; - height: 12px; - line-height: 12px; - border-radius: 50%; - text-align: center; - position: relative; - top: -0.22em; - vertical-align: middle; - } } diff --git a/packages/devui-vue/devui/tag/src/tag.tsx b/packages/devui-vue/devui/tag/src/tag.tsx index 7d86daa1677c4e9cd47514ae1c462f15a038a69b..615641197e99bcea75035dbb35a61d70c551cfc3 100644 --- a/packages/devui-vue/devui/tag/src/tag.tsx +++ b/packages/devui-vue/devui/tag/src/tag.tsx @@ -1,62 +1,23 @@ -import { defineComponent, toRefs, ref, watch, onUnmounted } from 'vue' +import { defineComponent } from 'vue' import { tagProps, TagProps } from './tag-types' -import { useClass, useColor } from './hooks' +import { useStyle } from './hooks' import './tag.scss' // 类型声明 export default defineComponent({ name: 'DTag', props: tagProps, - emits: ['click', 'tagDelete', 'checkedChange'], - setup(props: TagProps, { slots, emit }) { - const { type, color, checked, titleContent, deletable } = toRefs(props) - const tagClass = useClass(props) - const themeColor = useColor(props) - const tagTitle = titleContent.value || '' - const isDefaultTag = () => !type.value && !color.value - const isShow = ref(true) - // 子组件的点击事件 - const handleClick = () => { - emit('click') - } - const handleDelete = () => { - isShow.value = false - emit('tagDelete') - } - const closeIconEl = () => { - return deletable.value ? ( - - {isDefaultTag() ? ( - - ) : ( - - )} - - ) : null - } - //tag 的 check 状态改变时触发的事件checkedChange - const unWatch = watch(checked, (newVal) => { - console.log('checkedChange') + emits: [], + setup(props: TagProps, { slots }) { + //获取type对应样式 + const tagClass = useStyle(props) - emit('checkedChange', newVal) - }) - onUnmounted(() => unWatch()) - return () => - isShow.value && ( -
- - {slots.default?.()} - {closeIconEl()} - -
- ) + return () => ( +
+ + {slots.default?.()} + +
+ ) } }) diff --git a/packages/devui-vue/devui/textarea/index.ts b/packages/devui-vue/devui/textarea/index.ts index ef2b47cc9a1466210d9b538392dd715443575d2c..03e83245a0c71c9c6c29e274dbd948d1b7663085 100644 --- a/packages/devui-vue/devui/textarea/index.ts +++ b/packages/devui-vue/devui/textarea/index.ts @@ -10,7 +10,7 @@ export { Textarea } export default { title: 'Textarea 多行文本框', category: '数据录入', - status: '100%', // TODO: 组件若开发完成则填入"已完成",并删除该注释 + status: '已完成', // TODO: 组件若开发完成则填入"已完成",并删除该注释 install(app: App): void { app.use(Textarea as any) } diff --git a/packages/devui-vue/devui/time-axis/index.ts b/packages/devui-vue/devui/time-axis/index.ts index 511794c29c4d7fe4e6a082ed5064375b68f1742e..e5c509402abb90f2e5ca9a7a9bc086b0b39c32e2 100644 --- a/packages/devui-vue/devui/time-axis/index.ts +++ b/packages/devui-vue/devui/time-axis/index.ts @@ -2,20 +2,19 @@ import type { App } from 'vue' import TimeAxis from './src/time-axis' import TimeAxisItem from './src/components/time-axis-item' -TimeAxis.install = function (app: App): void { +TimeAxis.install = function(app: App): void { app.component(TimeAxis.name, TimeAxis) -} -TimeAxisItem.install = function (app: App): void { app.component(TimeAxisItem.name, TimeAxisItem) } -export { TimeAxis, TimeAxisItem } + +export { TimeAxis,TimeAxisItem } export default { title: 'TimeAxis 时间轴', category: '数据展示', - status: '100%', + status: '已完成', install(app: App): void { - app.use(TimeAxis as any) - app.use(TimeAxisItem as any) + app.use(TimeAxis as any) + app.use(TimeAxisItem as any) } } diff --git a/packages/devui-vue/devui/toast/index.ts b/packages/devui-vue/devui/toast/index.ts index 705ee20d4ad2b8acb6f88a27156122c985004558..6d091b1558be1ebd0a63148e84960d334c16369b 100644 --- a/packages/devui-vue/devui/toast/index.ts +++ b/packages/devui-vue/devui/toast/index.ts @@ -11,7 +11,7 @@ export { Toast, ToastService } export default { title: 'Toast 全局提示', category: '反馈', - status: '100%', + status: '已完成', install(app: App): void { app.use(Toast as any) app.config.globalProperties.$toastService = ToastService diff --git a/packages/devui-vue/devui/transfer/common/use-transfer-base.ts b/packages/devui-vue/devui/transfer/common/use-transfer-base.ts index 4c3b613112e32ced47329884630cb35f9615bbab..ff58c15297aea7accbffc91caa9a348455be3817 100644 --- a/packages/devui-vue/devui/transfer/common/use-transfer-base.ts +++ b/packages/devui-vue/devui/transfer/common/use-transfer-base.ts @@ -33,14 +33,10 @@ export const transferBaseProps = { type: Boolean, default: (): boolean => false }, - filter: { + query: { type: String, default: (): string => '' }, - height: { - type: String, - default: (): string => '320px' - }, alltargetState: { type: Boolean, default: (): boolean => false @@ -57,14 +53,6 @@ export const transferBaseProps = { type: Number, default: (): number => 0 }, - showTooltip: { - type: Boolean, - default: (): boolean => false - }, - tooltipPosition: { - type: String as PropType<'top' | 'right' | 'bottom' | 'left'>, - default: (): string => 'top' - }, scopedSlots: { type: Object }, @@ -121,7 +109,7 @@ export const initState = (props: TransferProps, type: string): TState => { allChecked: false, disabled: false, checkedNum: initModel.model.length, - keyword: '', + query: '', checkedValues: initModel.model, filterData: initModel.data } @@ -135,6 +123,6 @@ export const TransferBaseClass = (props: TransferOperationProps): ComputedRef => } export const Query = ((props: TransferOperationProps): ComputedRef => { - return computed(() => props.filter) + return computed(() => props.query) }) diff --git a/packages/devui-vue/devui/transfer/common/use-transfer.ts b/packages/devui-vue/devui/transfer/common/use-transfer.ts index 414d2dfc5bd3dcea213e9d5a8ca45f46bc42312b..42eee67d6467e8360e35629dc0b6717906d8b467 100644 --- a/packages/devui-vue/devui/transfer/common/use-transfer.ts +++ b/packages/devui-vue/devui/transfer/common/use-transfer.ts @@ -1,5 +1,5 @@ import { ExtractPropTypes, PropType, SetupContext } from 'vue' -import { IItem, ITitles, IModel, TState } from '../types' +import { IItem, ITitles, IModel } from '../types' export const transferProps = { sourceOption: { @@ -26,52 +26,30 @@ export const transferProps = { }, height: { type: String, - default: (): string => '320px' + default: '320px' }, isSearch: { type: Boolean, - default: (): boolean => false + default: false }, isSourceDroppable: { type: Boolean, - default: (): boolean => false + default: false }, isTargetDroppable: { type: Boolean, - default: (): boolean => false + default: false }, disabled: { type: Boolean, - default: (): boolean => false + default: false }, - showTooltip: { + showOptionTitle: { type: Boolean, - default: (): boolean => false - }, - tooltipPosition: { - type: String as PropType<'top' | 'right' | 'bottom' | 'left'>, - default: (): string => 'top' - }, - beforeTransfer: { - type: Function as unknown as () => ((sourceOption: TState, targetOption: TState) => boolean | Promise) + default: false }, slots: { type: Object - }, - searching: { - type: Function as unknown as () => ((direction: string, keyword: string, targetOption: TState) => void) - }, - transferToSource: { - type: Function as unknown as () => ((sourceOption: TState, targetOption: TState) => void) - }, - transferToTarget: { - type: Function as unknown as () => ((sourceOption: TState, targetOption: TState) => void) - }, - transferring: { - type: Function as unknown as () => ((targetOption: TState) => void) - }, - afterTransfer: { - type: Function as unknown as () => ((targetOption: TState) => void) } } diff --git a/packages/devui-vue/devui/transfer/src/transfer-base.tsx b/packages/devui-vue/devui/transfer/src/transfer-base.tsx index 10ec9f607d7e6ce88fe151662783f3d56f01bc21..605057afef26349ad7188ae0ec8841e919b35610 100644 --- a/packages/devui-vue/devui/transfer/src/transfer-base.tsx +++ b/packages/devui-vue/devui/transfer/src/transfer-base.tsx @@ -1,51 +1,35 @@ import { defineComponent, computed } from 'vue' -import { transferBaseProps, TransferBaseClass, TransferBaseProps } from '../common/use-transfer-base' +import { transferBaseProps, TransferBaseClass , TransferBaseProps } from '../common/use-transfer-base' import DCheckbox from '../../checkbox/src/checkbox' import DCheckboxGroup from '../../checkbox/src/checkbox-group' import DSearch from '../../search/src/search' -import DTooltip from '../../tooltip/src/tooltip' export default defineComponent({ name: 'DTransferBase', components: { DSearch, DCheckboxGroup, - DCheckbox, - DTooltip + DCheckbox }, props: transferBaseProps, setup(props: TransferBaseProps, ctx) { /** data start **/ - const modelValues = computed(() => props.checkedValues as Array) - const searchQuery = computed(() => props.filter) + const modelValues = computed(() => props.checkedValues) + const searchQuery = computed(() => props.query) const baseClass = TransferBaseClass(props) /** data end **/ /** watch start **/ - /** watch end **/ + /** watch start **/ /** methods start **/ const updateSearchQuery = (val: string): void => ctx.emit('changeQuery', val) - - const renderCheckbox = (props, key, showTooltip = false, tooltipPosition = 'top') => { - const checkbox = - - return !showTooltip ? checkbox : {checkbox} - } /** methods start **/ return { baseClass, searchQuery, modelValues, - updateSearchQuery, - renderCheckbox + updateSearchQuery } }, render() { @@ -59,13 +43,9 @@ export default defineComponent({ updateSearchQuery, search, searchQuery, - modelValues, - height, - showTooltip, - tooltipPosition, - renderCheckbox, + modelValues } = this - + return (
{ @@ -81,27 +61,33 @@ export default defineComponent({
) } { - this.$slots.body ? this.$slots.body() : -
- {search && } -
- { - sourceOption.length ? this.$emit('updateCheckeds', values)}> - { - sourceOption.map((item, idx) => { - return renderCheckbox(item, idx, showTooltip, tooltipPosition) - }) - } - : -
无数据
- } -
+ this.$slots.body ? this.$slots.body() :
+ {search && } +
+ { + sourceOption.length ? this.$emit('updateCheckeds', values)}> + { + sourceOption.map((item, idx) => { + return + + }) + } + : +
无数据
+ }
+
}
) diff --git a/packages/devui-vue/devui/transfer/src/transfer-operation.tsx b/packages/devui-vue/devui/transfer/src/transfer-operation.tsx index 4815a474019636940c3ab2f6c33f14fbd1b1c0d9..388024b4a5f44e350ae7f0469587dcd1a532d19a 100644 --- a/packages/devui-vue/devui/transfer/src/transfer-operation.tsx +++ b/packages/devui-vue/devui/transfer/src/transfer-operation.tsx @@ -1,4 +1,4 @@ -import { defineComponent } from 'vue'; +import { defineComponent, computed } from 'vue'; import DButton from '../../button/src/button' import { transferOperationProps } from '../common/use-transfer-operation' diff --git a/packages/devui-vue/devui/transfer/src/transfer.scss b/packages/devui-vue/devui/transfer/src/transfer.scss index 8a6bb867a2c3a19db405bbe008b640f60ff7553c..9328c50e46fc8cacec585a5ba9dd7b26f60b72c3 100644 --- a/packages/devui-vue/devui/transfer/src/transfer.scss +++ b/packages/devui-vue/devui/transfer/src/transfer.scss @@ -4,6 +4,7 @@ $devui-transfer-border-color: #adb0b8; $devui-transfer-border-radius: 2px; $devui-transfer-header-height: 40px; $devui-transfer-header-border-line-color:#dfe1e6; +$devui-transfer-body-search-height: 42px; $devui-transfer-body-list-item-height: 36px; .devui-transfer { @@ -32,16 +33,15 @@ $devui-transfer-body-list-item-height: 36px; } &-body { - display: flex; - flex-direction: column; height: 100%; &-search { + height: $devui-transfer-body-search-height; display: flex; justify-content: center; + width: calc(100% - 40px); align-items: center; - width: 100%; - padding: 7px 20px; + margin: 0 auto; .devui-search, .devui-input__wrap { @@ -51,32 +51,13 @@ $devui-transfer-body-list-item-height: 36px; &-list { overflow: auto; + height: calc(100% - #{$devui-transfer-header-height} - #{$devui-transfer-body-search-height}); width: 100%; - padding: 0 20px; &-item { + margin: 0 20px; height: $devui-transfer-body-list-item-height; line-height: $devui-transfer-body-list-item-height; - width: min-content; - max-width: 100%; - - label { - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - height: auto; - } - } - - &-tooltip { - // display: flex; - // max-width: calc(100% - 20px); - // overflow: hidden; - // text-overflow: ellipsis; - // white-space: nowrap; - .slotElement { - max-width: 100%; - } } &-empty { diff --git a/packages/devui-vue/devui/transfer/src/transfer.tsx b/packages/devui-vue/devui/transfer/src/transfer.tsx index e857d12b828726fb08c1615e54ac468773cc05de..e05273d0cc6a1e663f17720f0b3b40246298411e 100644 --- a/packages/devui-vue/devui/transfer/src/transfer.tsx +++ b/packages/devui-vue/devui/transfer/src/transfer.tsx @@ -17,28 +17,14 @@ export default defineComponent({ props: transferProps, setup(props: TransferProps, ctx: SetupContext) { /** data start **/ - let leftOptions = reactive(initState(props, 'source')) - let rightOptions = reactive(initState(props, 'target')) + const leftOptions = reactive(initState(props, 'source')) + const rightOptions = reactive(initState(props, 'target')) const origin = ref(null); /** data end **/ /** watch start **/ watch( - () => props.sourceOption, - () => { - leftOptions = reactive(initState(props, 'source')) - } - ) - - watch( - () => props.targetOption, - () => { - rightOptions = reactive(initState(props, 'target')) - } - ) - - watch( - () => leftOptions.keyword, + () => leftOptions.query, (nVal: string): void => { searchFilterData(leftOptions) } @@ -56,7 +42,7 @@ export default defineComponent({ ) watch( - () => rightOptions.keyword, + () => rightOptions.query, (nVal: string): void => { searchFilterData(rightOptions) }, @@ -84,36 +70,19 @@ export default defineComponent({ } } - const updateFilterData = async (source: TState, target: TState, direction: string): Promise => { - if (isFunction('beforeTransfer')) { - const res: boolean = await props.beforeTransfer.call(null, source, target) - if (typeof res === 'boolean' && res === false) { - return - } - } - - const hasToSource = isFunction('transferToSource') - const hasToTarget = isFunction('transferToTarget') - const hasTransfering = isFunction('transferring') - if (hasToSource || hasToTarget) { - direction === 'right' && props.transferToSource.call(null, source, target) - direction === 'left' && props.transferToTarget.call(null, source, target) - } else { - source.data = source.data.filter(item => { - const hasInclues = source.checkedValues.includes(item.value) - hasInclues && target.data.push(item) - return !hasInclues - }) - } - if (hasTransfering) { - props.transferring.call(null, target) - } + const updateFilterData = (source: TState, target: TState): void => { + const newData = [] + source.data = source.data.filter(item => { + const hasInclues = source.checkedValues.includes(item.value) + hasInclues && newData.push(item) + return !hasInclues + }) + target.data = target.data.concat(newData) source.checkedValues = [] target.disabled = !target.disabled searchFilterData(source, target) searchFilterData(target, source) setOrigin('click') - isFunction('afterTransfer') && props.afterTransfer.call(null, target) } const changeAllSource = (source: TState, value: boolean): void => { if (source.filterData.every(item => item.disabled)) return @@ -135,43 +104,31 @@ export default defineComponent({ setOrigin('change') } const searchFilterData = (source: TState, target?: TState): void => { - source.filterData = source.data.filter(item => item.key.indexOf(source.keyword) !== -1) + source.filterData = source.data.filter(item => item.key.indexOf(source.query) !== -1) if (target) { target.allChecked = false } } - const setOrigin = (value: string): void => { origin.value = value } - const changeQueryHandle = (source: TState, direction: string, value: string): void => { - if (props?.searching && typeof props.searching === 'function') { - props.searching.call(null, direction, value, source) - return - } - source.keyword = value - } - - const isFunction = (type: string): boolean => { - return props[type] && typeof props[type] === 'function' - } /** methods end **/ return () => { return
changeAllSource(leftOptions, value)} onUpdateCheckeds={updateLeftCheckeds} - onChangeQuery={(value) => changeQueryHandle(leftOptions, 'left', value)} + onChangeQuery={(value) => leftOptions.query = value} /> 0 ? false : true} targetDisabled={leftOptions.checkedNum > 0 ? false : true} - onUpdateSourceData={() => { updateFilterData(rightOptions, leftOptions, 'left') }} - onUpdateTargetData={() => { updateFilterData(leftOptions, rightOptions, 'right') }} + onUpdateSourceData={() => { updateFilterData(rightOptions, leftOptions) }} + onUpdateTargetData={() => { updateFilterData(leftOptions, rightOptions) }} /> changeAllSource(rightOptions, value)} onUpdateCheckeds={updateRightCheckeds} - onChangeQuery={(value) => changeQueryHandle(rightOptions, 'right', value)} + onChangeQuery={(value) => rightOptions.query = value} />
} diff --git a/packages/devui-vue/devui/transfer/types.ts b/packages/devui-vue/devui/transfer/types.ts index 3846d0da756be610617dd7910cc1371095e36910..c527d74e6661facaf96f8b1c9ec507305194df46 100644 --- a/packages/devui-vue/devui/transfer/types.ts +++ b/packages/devui-vue/devui/transfer/types.ts @@ -17,7 +17,7 @@ export interface TState { data: IItem[] allChecked: boolean checkedNum: number - keyword: string + query: string checkedValues: string[] filterData: IItem[] disabled: boolean @@ -30,3 +30,25 @@ export interface TResult { +// import { ComputedRef } from 'vue' +// export type TItem = { +// key: string +// value: string +// disabled: boolean +// checked?: boolean +// } + +// export type TState = { +// data: TItem[] +// allChecked: boolean +// // disabled: boolean // ComputedRef// +// checkedNum: number +// query: string +// checkedValues: string[] +// filterData: TItem[] +// } + +// export type TResult = { +// model: string[] +// data: TItem[] +// } diff --git a/packages/devui-vue/devui/upload/index.ts b/packages/devui-vue/devui/upload/index.ts index 3eed211d068f49430d7fb5948c635220a1ed3890..01f70902ad0d70ea773c1db79deac0d6dc641c33 100644 --- a/packages/devui-vue/devui/upload/index.ts +++ b/packages/devui-vue/devui/upload/index.ts @@ -14,8 +14,8 @@ export { Upload, MultiUpload } export default { title: 'Upload 上传', category: '数据录入', - status: '100%', + status: '80%', install(app: App): void { app.use(Upload as any) - } + }, } diff --git a/packages/devui-vue/docs/.vitepress/config/enNav.ts b/packages/devui-vue/docs/.vitepress/config/enNav.ts index 3ef33ffec0cd3b702c4cf8109a8cfca87310ecba..4522ec9bd14315692f7e5bdfc21b4c25c737a0f7 100644 --- a/packages/devui-vue/docs/.vitepress/config/enNav.ts +++ b/packages/devui-vue/docs/.vitepress/config/enNav.ts @@ -1,7 +1,8 @@ const enNav = [ - { text: 'Component', link: '/en-US/' }, - { text: 'Version history', link: 'https://gitee.com/devui/vue-devui/releases' }, - { text: 'Design disciplines', link: 'https://devui.design/design-cn/start' }, -] + { text: 'Design disciplines', link: '/en-US/design' }, + { text: 'Component', link: '/en-US/' }, + { text: 'Version history', link: '/en-US/version' }, + { text: 'Theme', link: '/en-US/theme' }, + ] export default enNav \ No newline at end of file diff --git a/packages/devui-vue/docs/.vitepress/config/enSidebar.ts b/packages/devui-vue/docs/.vitepress/config/enSidebar.ts index 4f814fef10adede3ade044596c936706d44a719c..00c336177b60d0d33adc44eed92baeb417cf3224 100644 --- a/packages/devui-vue/docs/.vitepress/config/enSidebar.ts +++ b/packages/devui-vue/docs/.vitepress/config/enSidebar.ts @@ -33,15 +33,15 @@ const enSidebar = { { text: 'Feedback', children: [ - { text: 'Alert', link: '/en-US/components/alert/', status: 'completed' }, - { text: 'Drawer', link: '/en-US/components/drawer/' }, - { text: 'Loading', link: '/en-US/components/loading/', status: 'completed' }, - { text: 'Mention', link: '/en-US/components/mention/' }, - { text: 'Modal', link: '/en-US/components/modal/' }, - { text: 'Popover', link: '/en-US/components/popover/', status: "progress" }, - { text: 'ReadTip', link: '/en-US/components/read-tip/' }, - { text: 'Toast', link: '/en-US/components/toast/', status: 'completed' }, - { text: 'Tooltip', link: '/en-US/components/tooltip/', status: 'completed' }, + { text: 'Alert', link: '/components/alert/', status: 'completed' }, + { text: 'Drawer', link: '/components/drawer/' }, + { text: 'Loading', link: '/components/loading/', status: 'completed' }, + { text: 'Mention', link: '/components/mention/' }, + { text: 'Modal', link: '/components/modal/' }, + { text: 'Popover', link: '/components/popover/', status: "progress" }, + { text: 'ReadTip', link: '/components/read-tip/' }, + { text: 'Toast', link: '/components/toast/', status: 'completed' }, + { text: 'Tooltip', link: '/components/tooltip/', status: 'completed' }, ] }, { diff --git a/packages/devui-vue/docs/.vitepress/config/nav.ts b/packages/devui-vue/docs/.vitepress/config/nav.ts index 8f723b036adfcb073cb968e58634e156302b8c3f..25c08b19632cfbb61c573155ca4cb26f1fda2a02 100644 --- a/packages/devui-vue/docs/.vitepress/config/nav.ts +++ b/packages/devui-vue/docs/.vitepress/config/nav.ts @@ -1,7 +1,8 @@ const nav = [ + { text: '设计规范', link: '/design' }, { text: '组件', link: '/' }, - { text: '版本历程', link: 'https://gitee.com/devui/vue-devui/releases' }, - { text: '设计规范', link: 'https://devui.design/design-cn/start' }, + { text: '版本历程', link: '/version' }, + { text: '主题', link: '/theme' }, ] export default nav \ No newline at end of file diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/Layout.vue b/packages/devui-vue/docs/.vitepress/devui-theme/Layout.vue index 5a6a85b1e73511bb23591b0c526a776e6b812e89..47ca81faae4f1cb7a970faee30f580f842a40be0 100644 --- a/packages/devui-vue/docs/.vitepress/devui-theme/Layout.vue +++ b/packages/devui-vue/docs/.vitepress/devui-theme/Layout.vue @@ -2,7 +2,7 @@ import { ref, computed, watch, defineAsyncComponent } from 'vue' import { useRoute, useData } from 'vitepress' import { isSideBarEmpty, getSideBarConfig } from './support/sideBar' -import lang from '../config/lang'; + // components import NavBar from './components/NavBar.vue' import SideBar from './components/SideBar.vue' @@ -82,13 +82,11 @@ const pageClasses = computed(() => { }) // layout组件加载,初始化国际化语言. -const result = location.pathname.match(/[a-zA-Z]*-[A-Z]*/) -const langList = Object.keys(lang); -// 避免短横线分隔 (kebab-case)形式的路由命名导致读取语言错误 -if (result && langList.includes(result[0])) { - localStorage.setItem('preferred_lang', result[0]) -} else { - localStorage.setItem('preferred_lang', navigator.language); +if (location.pathname.indexOf('-') >= 0){ + const result = location.pathname.match(/[a-zA-Z]*-[A-Z]*/) + localStorage.setItem('preferred_lang', result[0]) +}else { + localStorage.setItem('preferred_lang', navigator.language); } diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/BackToTop.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/BackToTop.vue index 91c519cd9237b3f7d17ede456a870e8128e2daf9..77ad149f2adc20316f84c9ea9237fe04a1e44373 100644 --- a/packages/devui-vue/docs/.vitepress/devui-theme/components/BackToTop.vue +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/BackToTop.vue @@ -1,32 +1,29 @@ @@ -80,10 +77,9 @@ export default defineComponent({ .go-to-top { cursor: pointer; position: fixed; - display: flex; bottom: 2rem; - right: calc((100vw - 1440px) / 2 + 144px); - width: 22px; + right: 2.5rem; + width: 2rem; color: var(--devui-brand); z-index: 1; } diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/NavBar.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/NavBar.vue index 250bfe84784418687029c08d3ded79004700c159..a1fc72290c4fe3620b4305260ccacf2df4a1cb9f 100644 --- a/packages/devui-vue/docs/.vitepress/devui-theme/components/NavBar.vue +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/NavBar.vue @@ -1,25 +1,23 @@ @@ -85,7 +68,7 @@ defineEmits(['toggle']) top: 0; right: 0; left: 0; - z-index: 20; + z-index: var(--z-index-navbar); display: flex; justify-content: space-between; align-items: center; @@ -113,15 +96,4 @@ defineEmits(['toggle']) display: block; } } - -.custom-nav svg { - fill: $devui-text; -} - -.custom-nav-item:hover { - svg, - path { - fill: $devui-brand; - } -} diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/NavBarTitle.vue b/packages/devui-vue/docs/.vitepress/devui-theme/components/NavBarTitle.vue index bbed5db97c35e0042897d210c6189b3bf84f98e1..4c54558a1a6253da09f3f4d4d4ff6d3b122ad53a 100644 --- a/packages/devui-vue/docs/.vitepress/devui-theme/components/NavBarTitle.vue +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/NavBarTitle.vue @@ -1,17 +1,13 @@