diff --git a/devui/alert/__tests__/alert.spec.ts b/devui/alert/__tests__/alert.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..08830e625075f5fe495d15abd4e63e6561d2607d --- /dev/null +++ b/devui/alert/__tests__/alert.spec.ts @@ -0,0 +1,121 @@ +import { mount } from '@vue/test-utils' +import { h } from 'vue' +import Alert from '../src/alert' +describe('alert', () => { + describe('alert basic', () => { + it('should create alert component correctly', () => { + const wrapper = mount(Alert) + expect(wrapper.find('.devui-alert').exists()).toBe(true) + }) + it('should alert show content correct', () => { + const wrapper = mount(Alert, { + slots: { + default: h('span', {}, 'Vue DevUI'), + }, + }) + expect(wrapper.find('.devui-alert').text()).toBe('Vue DevUI') + }) + }) + + describe('alert type', () => { + it('alert should has success type', () => { + const wrapper = mount(Alert, { + props: { + type: 'success', + }, + }) + expect(wrapper.find('.devui-icon-success').exists()).toBe(true) + }) + it('alert should has success type', () => { + const wrapper = mount(Alert, { + props: { + type: 'warning', + }, + }) + expect(wrapper.find('.devui-icon-warning').exists()).toBe(true) + }) + it('alert should has success type', () => { + const wrapper = mount(Alert, { + props: { + type: 'danger', + }, + }) + expect(wrapper.find('.devui-icon-error').exists()).toBe(true) + }) + it('alert should has info type', () => { + const wrapper = mount(Alert) + expect(wrapper.find('.devui-icon-info').exists()).toBe(true) + }) + it('alert should has simple type', () => { + const wrapper = mount(Alert, { + props: { + type: 'simple', + }, + }) + expect(wrapper.find('.devui-alert-icon').exists()).toBe(false) + }) + }) + + describe('alert cssClass', () => { + it('alert should append cssClass', () => { + const wrapper = mount(Alert, { + props: { + cssClass: 'cssClass', + }, + }) + expect(wrapper.find('.cssClass').exists()).toBe(true) + }) + }) + + describe('alert icon', () => { + it('alert should show icon', () => { + const wrapper = mount(Alert) + expect(wrapper.find('.devui-alert-icon').exists()).toBe(true) + }) + it('alert should not show icon', () => { + const wrapper = mount(Alert, { + props: { + showIcon: false, + }, + }) + expect(wrapper.find('.devui-alert-icon').exists()).toBe(false) + }) + }) + + describe('alert close', () => { + it('alert should close', async () => { + const wrapper = mount(Alert) + await wrapper.find('.devui-close').trigger('click') + setTimeout(() => { + expect(wrapper.find('.devui-alert').exists()).toBe(false) + }, 0) + }) + it('alert should emit close event', async () => { + const wrapper = mount(Alert) + await wrapper.find('.devui-close').trigger('click') + expect(wrapper.emitted()).toHaveProperty('close') + expect(wrapper.emitted().close).toHaveLength(1) + }) + }) + + describe('alert dismiss', () => { + beforeEach(() => { + jest.useFakeTimers() + }) + it('alert should not dismiss before 3000ms', async () => { + const wrapper = mount(Alert, { + props: { + dismissTime: 3000, + }, + }) + expect(wrapper.find('.devui-alert').exists()).toBe(true) + await wrapper.find('.devui-close').trigger('click') + jest.advanceTimersByTime(2000) + expect(wrapper.find('.devui-alert').exists()).toBe(true) + jest.advanceTimersByTime(1000) + setTimeout(() => { + expect(wrapper.find('.devui-alert').exists()).toBe(false) + }, 0) + }) + }) +}) diff --git a/devui/alert/index.ts b/devui/alert/index.ts index 8a70ee9ef7f83993ba3291513c9001f818e2e488..9d4b1075057600aff426cb8d4dff29b82e7190fb 100644 --- a/devui/alert/index.ts +++ b/devui/alert/index.ts @@ -1,7 +1,7 @@ import type { App } from 'vue' import Alert from './src/alert' -Alert.install = function(app: App) { +Alert.install = function (app: App) { app.component(Alert.name, Alert) } @@ -10,7 +10,8 @@ export { Alert } export default { title: 'Alert 警告', category: '反馈', + status: '已完成', install(app: App): void { app.use(Alert as any) - } + }, } diff --git a/devui/alert/src/alert-close-icon.tsx b/devui/alert/src/alert-close-icon.tsx index b3b98b9886fcdb47bd267a8071c035b2d31c0a3b..869b979aa6c5b416e2f5536f1b66d50b993bdbdd 100644 --- a/devui/alert/src/alert-close-icon.tsx +++ b/devui/alert/src/alert-close-icon.tsx @@ -1,20 +1,16 @@ -import { defineComponent } from 'vue' - -export default defineComponent({ - name: 'DAlertCloseIcon', - setup() { - return () => { - return ( - - - - - - - - ) - } - } -}) \ No newline at end of file +const AlertCloseIcon = () => ( + + + + + + + +) +export default AlertCloseIcon diff --git a/devui/alert/src/alert-type-icon.tsx b/devui/alert/src/alert-type-icon.tsx index ba6754bef4852a3ccc92e9d0f4ccd0e16b2840bc..e409dbb719c0046667de953d09ad7b10f4025333 100644 --- a/devui/alert/src/alert-type-icon.tsx +++ b/devui/alert/src/alert-type-icon.tsx @@ -1,90 +1,84 @@ -import { defineComponent } from 'vue'; -import { AlertType } from './alert'; +import { AlertType } from './alert' -export default defineComponent({ - name: 'DAlertTypeIcon', - props: { - type: { - type: String as () => AlertType, - default: '' - } - }, - setup(props) { - return () => { - return ( - - {(() => { - switch(props.type) { - case 'success': - return ( - - - - - ); - case 'warning': - return ( - - - - - ); - case 'info': - return ( - - - - - - - ); - case 'danger': - return ( - - - - - - - ) - default: - return null; - } - })()} - - ) - } - } -}) \ No newline at end of file +const AlertTypeIcon = (props: { type: AlertType; }) => ( + + {(() => { + switch (props.type) { + case 'success': + return ( + + + + + ) + case 'warning': + return ( + + + + + ) + case 'info': + return ( + + + + + + + ) + case 'danger': + return ( + + + + + + + ) + default: + return null + } + })()} + +) + +export default AlertTypeIcon diff --git a/devui/alert/src/alert.scss b/devui/alert/src/alert.scss index 9a944a352504b7027a9431604fa874b0b0543549..c4bd6eb234e60806aee3dc5809022119fa1fd9fd 100644 --- a/devui/alert/src/alert.scss +++ b/devui/alert/src/alert.scss @@ -78,6 +78,17 @@ } } + &.devui-alert-simple { + border-color: $devui-line; + color: $devui-text; + + .devui-close { + & > svg path { + fill: $devui-text-weak; + } + } + } + svg.devui-icon { width: 16px; height: 16px; diff --git a/devui/alert/src/alert.tsx b/devui/alert/src/alert.tsx index 06eed01a4ebad8fa3398a7ed83a653c0c1653cc9..d9e42d0ce019d033721a31bab4dbddaf7a2d50f0 100644 --- a/devui/alert/src/alert.tsx +++ b/devui/alert/src/alert.tsx @@ -1,94 +1,88 @@ -import { defineComponent, ref, Transition, onMounted, } from 'vue'; +import { defineComponent, ref, Transition, onMounted } from 'vue' -import AlertCloseIcon from './alert-close-icon'; -import AlertTypeIcon from './alert-type-icon'; +import AlertCloseIcon from './alert-close-icon' +import AlertTypeIcon from './alert-type-icon' -import './alert.scss'; +import './alert.scss' -export type AlertType = 'success' | 'danger' | 'warning' | 'info'; +export type AlertType = 'success' | 'danger' | 'warning' | 'info' | 'simple' export default defineComponent({ name: 'DAlert', props: { type: { type: String as () => AlertType, - default: 'info' + default: 'info', }, - cssClass: { - type: String, - default: '' + cssClass: { + type: String, + default: '', }, closeable: { type: Boolean, - default: true + default: true, }, showIcon: { type: Boolean, - default: true + default: true, }, dismissTime: { type: Number, - default: 0 + default: 0, }, - closeEvent: { - type: Function as unknown as () => ((event?: MouseEvent) => void), - default: null - } }, - emits:['close'], + emits: ['close'], setup(props, ctx) { - - const hide = ref(false); - const closing = ref(false); - - const alertEl = ref(); + const hide = ref(false) + const closing = ref(false) + const alertEl = ref() const close = (event?: MouseEvent) => { - const dom = alertEl.value; - dom.style.height = `${dom.offsetHeight}px`; + const dom = alertEl.value + dom.style.height = `${dom.offsetHeight}px` // 重复一次后才能正确设置 height - dom.style.height = `${dom.offsetHeight}px`; - closing.value = true; - props.closeEvent?.(event); + dom.style.height = `${dom.offsetHeight}px` + closing.value = true + ctx.emit('close', event) } const afterLeave = () => { - hide.value = true; - closing.value = false; + hide.value = true + closing.value = false } onMounted(() => { if (props.dismissTime) { setTimeout(() => { - close(); + close() }, props.dismissTime) } }) return () => { - return ( - !hide.value ? - - - {props.closeable ? - - - : null - } - {props.showIcon !== false ? - - - : null - } - {ctx.slots.default?.()} - - - : null - ) + return !hide.value ? ( + + + {props.closeable ? ( + + + + ) : null} + {props.showIcon !== false && props.type !== 'simple' ? ( + + + + ) : null} + {ctx.slots.default?.()} + + + ) : null } - } + }, }) -/* - - -*/ \ No newline at end of file diff --git a/docs/components/alert/index.md b/docs/components/alert/index.md index 498a279314bf632ce2e6373df20ab09971a3127d..d773f90c664a24b702d69d0a2781f06f7d71f53c 100644 --- a/docs/components/alert/index.md +++ b/docs/components/alert/index.md @@ -8,16 +8,113 @@ ### 基本用法 - success - danger - warning - info - simple - -```html - success - danger - warning - info - simple -``` \ No newline at end of file +共有四种样式:success、danger、warning、info。 + +:::demo + +```vue + + + success + danger + warning + info + simple + + + +``` + +::: + +### 可关闭的提示 + +显示关闭按钮,点击可关闭提示。 + +:::demo + +```vue + + + success + danger + warning + info + simple + + + + +``` + +::: + +### 不使用默认图标 + +不使用默认的类型图标。 + +:::demo + +```vue + + + success + danger + warning + info + simple + + + +``` + +::: + +### API + +### d-alert 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | +| :---------: | :-----------------------: | :----: | :-------------------------------------: | :-------------------------------- | +| type | [`AlertType`](#AlertType) | 'info' | 必选,指定警告提示的样式 | [基本用法](#基本用法) | +| cssClass | `string` | -- | 可选,自定义 class 名 | +| closeable | `boolean` | true | 可选,默认显示关闭按钮 | [基本用法](#可关闭的提示) | +| dismissTime | `number` | -- | 可选,自动关闭 alert 的延迟时间(`ms`) | +| showIcon | `boolean` | true | 可选,是否使用默认的类型图标 | [不使用默认图标](#不使用默认图标) | + +### d-alert 事件 + +| 参数 | 类型 | 说明 | 跳转 Demo | +| :---: | :----------------------------: | :------------------------- | ----------------------------- | +| close | `(event?: MouseEvent) => void` | 可选,关闭时触发的回调函数 | [可关闭的提示](#可关闭的提示) | + +### AlertType + +默认值为'info', 指定 alert 警告提示的类型 + +```ts +export type AlertType = 'success' | 'danger' | 'warning' | 'info' | 'simple' +```