diff --git a/devui/panel/__tests__/panel.spec.ts b/devui/panel/__tests__/panel.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..6a7b0ce7665bc4d3dc854e8f3083e75e0c9cd7a2 --- /dev/null +++ b/devui/panel/__tests__/panel.spec.ts @@ -0,0 +1,137 @@ +import { shallowMount,mount } from "@vue/test-utils"; +import {ref,nextTick,Transition } from 'vue'; +import DButton from '../../button/index'; +import DPanel from '../src/panel' +import DPanelHeader from '../src/header/panel-header'; +import DPanelBody from '../src/body/panel-body'; +import DPanelFooter from '../src/foot/panel-footer'; + + +describe('DPanel',()=>{ + + // 渲染测试 + it('Render',()=>{ + // except(wrapper.html()) + let wrapper = mount({ + components:{ + DPanel, + DPanelBody, + DPanelHeader, + DPanelFooter, + DButton + }, + template: ` + + + Panel with foldable + + + This is body + + + `, + }); + expect(wrapper.find('transition-stub').html()).toContain(''); + }) + + it('isCollapsed', async ()=>{ + let wrapper = mount({ + components:{ + DPanel, + DPanelBody, + DPanelHeader, + DPanelFooter, + DButton + }, + template: ` + + + Panel with foldable + + + This is body + + + `, + setup(){ + let isCollapsed = ref(false); + return {isCollapsed} + } + }); + expect(wrapper.find('.devui-panel .devui-panel-default').element.children[0].innerHTML).toBe(''); + }) + // // 动态hasLeftPadding 测试 + it('padding-dynamic', async ()=>{ + let wrapper = mount({ + components:{ + DPanel, + DPanelBody, + DPanelHeader, + DPanelFooter, + DButton + }, + template: ` + + + Panel with foldable + + + This is body + + +

+ + 切换LeftPadding + + `, + setup(){ + let leftPadding = ref(false); + return { + leftPadding, + } + } + }); + expect(wrapper.find('.devui-panel-body-collapse').classes().length).toBe(3); + await wrapper.find('button').trigger('click'); + expect(wrapper.find('.devui-panel-body-collapse').classes().length).toBe(2); + }) + + + it('beforeToggle-dynamic',async ()=>{ + let wrapper = mount({ + components:{ + DPanel, + DPanelBody, + DPanelHeader, + DPanelFooter, + DButton + }, + template: ` + + + Panel with foldable + + + This is body + + +

+ + {{ panelToggle ? '阻止折叠' : '允许折叠' }} + + `, + setup(){ + let panelToggle = ref(false); + const beforeToggle = () => panelToggle.value; + return { + panelToggle, + beforeToggle, + } + } + }); + await wrapper.find('button').trigger('click'); + expect(wrapper.vm.panelToggle).toBe(true); + await wrapper.find('button').trigger('click'); + expect(wrapper.vm.panelToggle).toBe(false); + }) +}) \ No newline at end of file diff --git a/devui/panel/src/body/panel-body.tsx b/devui/panel/src/body/panel-body.tsx index 84a64108e97c252dd8c011a9e6e187a7b8f4ac02..7a7827f365ef07c05a6d6186de037011bc2ae676 100644 --- a/devui/panel/src/body/panel-body.tsx +++ b/devui/panel/src/body/panel-body.tsx @@ -1,4 +1,4 @@ -import { defineComponent,ref,onMounted,Transition,inject } from 'vue'; +import { defineComponent,ref,onMounted,Transition,inject,Ref } from 'vue'; import { PanelProps } from '../panel.type'; import Store from '../store/store'; @@ -6,9 +6,8 @@ export default defineComponent({ name: 'DPanelBody', props:PanelProps, setup(props,ctx){ - const animationName = inject('showAnimation') ? 'devui-panel' : ''; - const hasLeftPadding = !inject('hasLeftPadding') ? 'no-left-padding' : ''; - + let animationName = inject('showAnimation') as Ref; + let hasLeftPadding = inject('hasLeftPadding') as Ref; const keys = Object.keys(Store.state()); const key = keys.pop(); const isCollapsed = Store.state(); @@ -34,13 +33,12 @@ export default defineComponent({ const el = (element as HTMLElement); el.style.height = '0px'; } - return () => { return (
- + {isCollapsed[key] === undefined || isCollapsed[key] ? -
+
{ctx.slots.default?.()}
diff --git a/devui/panel/src/header/panel-header.tsx b/devui/panel/src/header/panel-header.tsx index 93f701621eff6f5dc97bd887900fdc2dfcccb0c4..9b8c7a4c15e880cfe7ee9ce05431b57f7f0aa986 100644 --- a/devui/panel/src/header/panel-header.tsx +++ b/devui/panel/src/header/panel-header.tsx @@ -10,40 +10,56 @@ export default defineComponent({ const keys = Object.keys(Store.state()); const key = keys.pop(); const isCollapsed = ref(Store.state()[key]); + // 当beforeToggle为fals时 + // 最好cursor是default 而不是 pointer; + // pointer一般用于可点击的 + // 用changeFlag + let changeFlag = ref(); + let header = null; + const canToggle = (): Promise => { - let changeResult = Promise.resolve(true); - if(beforeToggle) { - const result = beforeToggle(isCollapsed); - if(typeof result !== undefined) { - if(result instanceof Promise) { - changeResult = result; - } else { - changeResult = Promise.resolve(result); - } + let changeResult = Promise.resolve(true); + if(beforeToggle) { + const result = beforeToggle(isCollapsed); + if(typeof result !== undefined) { + if(result instanceof Promise) { + changeResult = result; + } else { + changeResult = Promise.resolve(result); } } - return changeResult; } - - const toggleBody = (): void => { - canToggle().then((val) => { - if (!val){ - return; - } - if (isCollapsed.value !== undefined) { + return changeResult; + } + + // 需要执行一次才能生效; + canToggle().then((val)=>changeFlag.value = val) + + const toggleBody = (): void => { + canToggle().then((val) => { + changeFlag.value = val; + if (!val){ + // 禁止折叠不影响展开 + if (!isCollapsed.value){ Store.setData(`${key}`, !isCollapsed.value); isCollapsed.value = !isCollapsed.value; props.toggle?.(isCollapsed.value); } - }) - - }; + return; + } + if (isCollapsed.value !== undefined) { + Store.setData(`${key}`, !isCollapsed.value); + isCollapsed.value = !isCollapsed.value; + props.toggle?.(isCollapsed.value); + } + }) + + }; return () => { - let header = null; if (ctx.slots.default){ header = ( -
+
{ctx.slots.default?.()}
) diff --git a/devui/panel/src/panel.scss b/devui/panel/src/panel.scss index 2cb1bb83b846d0ab25d96329a09c6ecc42c6d217..76ab896446dded584c1060a274f615b42c96e670 100644 --- a/devui/panel/src/panel.scss +++ b/devui/panel/src/panel.scss @@ -1,5 +1,17 @@ @import '../../style/theme/color'; +.no-left-padding { + &.devui-panel-body-collapse { + &::before { + content: none !important; + } + + .devui-panel-content { + border-left: none !important; + } + } +} + .devui-panel { line-height: 1.5; background-color: $devui-base-bg; @@ -13,17 +25,6 @@ } } - .no-left-padding { - &.devui-panel-body-collapse { - &::before { - display: none; - } - - .devui-panel-content { - border-left: none !important; - } - } - } .devui-panel-body { display: flex; diff --git a/devui/panel/src/panel.tsx b/devui/panel/src/panel.tsx index 741ebcf5505daf1891589d19f5a3e2fb699edf77..5c601aee231c63e8cf41b4c4d3e4494c55eba6cc 100644 --- a/devui/panel/src/panel.tsx +++ b/devui/panel/src/panel.tsx @@ -1,4 +1,4 @@ -import { defineComponent, ref, Transition, onMounted, provide } from 'vue'; +import { defineComponent, ref, provide, computed} from 'vue'; import './panel.scss'; import { PanelProps } from './panel.type'; import Store from './store/store'; @@ -8,31 +8,22 @@ export default defineComponent({ props: PanelProps, setup(props, ctx) { provide('beforeToggle', props.beforeToggle); - provide('showAnimation', props.showAnimation); - provide('hasLeftPadding', props.hasLeftPadding); + provide('showAnimation', computed(()=>props.showAnimation)); + provide('hasLeftPadding', computed(()=>props.hasLeftPadding)); const isCollapsed = ref(props.isCollapsed); - const bodyEl = ref(); + const type = computed(()=>props.type); + const cssClass = computed(()=>props.cssClass); const onToggle = ()=> { props.toggle?.(Store.getByKey(`isCollapsed[${timeStamp}]`)) }; - - onMounted(() => { - if(bodyEl.value) { - const dom = bodyEl.value; - if(isCollapsed.value) - dom.style.height = `${dom.offsetHeight}px`; - } - }) - const timeStamp = new Date().getTime().toString(); Store.setData(`isCollapsed[${timeStamp}]`, isCollapsed.value); - return () => { return ( -
- {ctx.slots.default()} +
+ {ctx.slots.default?.()}
) } - }, + } }) \ No newline at end of file diff --git a/devui/panel/src/panel.type.ts b/devui/panel/src/panel.type.ts index 58a80760ef8040f5b3246f0b264bb6b304f9fd2a..ed23606652499788f8776bc3d70316e5c9c95e15 100644 --- a/devui/panel/src/panel.type.ts +++ b/devui/panel/src/panel.type.ts @@ -3,34 +3,34 @@ import {ExtractPropTypes} from 'vue'; export type PanelType = 'default' | 'primary' | 'success' | 'danger' | 'warning' | 'info'; export const PanelProps = { - type: { - type: String as () => PanelType, - default: 'default' - }, - cssClass: { - type: String, - default: '' - }, - isCollapsed: { - type: Boolean, - default: undefined - }, - beforeToggle: { - type: Function as unknown as () => (value: boolean) => boolean | Promise, - default: null - }, - toggle: { - type: Function as unknown as ()=> ((value: boolean) => void), - default: null - }, - showAnimation: { - type: Boolean, - default: true, - }, - hasLeftPadding:{ - type: Boolean, - default: true, - } + type: { + type: String as () => PanelType, + default: 'default' + }, + cssClass: { + type: String, + default: '' + }, + isCollapsed: { + type: Boolean, + default: false + }, + beforeToggle: { + type: Function as unknown as () => (value: boolean) => boolean | Promise, + default: null + }, + toggle: { + type: Function as unknown as ()=> ((value: boolean) => void), + default: null + }, + showAnimation: { + type: Boolean, + default: true, + }, + hasLeftPadding:{ + type: Boolean, + default: true, + } } export type PanelPropsType = ExtractPropTypes; \ No newline at end of file diff --git a/docs/components/panel/index.md b/docs/components/panel/index.md index aeae65aa903bc4c77ce54acea91ece39eb5b3da9..0c1b61985915e59c490180ac4c7164d1135ca178 100644 --- a/docs/components/panel/index.md +++ b/docs/components/panel/index.md @@ -11,14 +11,14 @@ ```vue