From eec186ac19be63b0586d545b92e11e9f7e569271 Mon Sep 17 00:00:00 2001 From: neverland Date: Mon, 29 Mar 2021 15:51:02 +0800 Subject: [PATCH] feat(Dialog): allow to render JSX message (#8420) * feat(Dialog): allow to render JSX message * types: add DialogMessage type --- src/dialog/Dialog.tsx | 43 +++++++++++++------ src/dialog/README.md | 4 +- src/dialog/README.zh-CN.md | 6 +-- src/dialog/index.tsx | 5 ++- .../__snapshots__/funciton-call.spec.js.snap | 9 ++++ src/dialog/test/funciton-call.spec.js | 14 ++++++ 6 files changed, 60 insertions(+), 21 deletions(-) create mode 100644 src/dialog/test/__snapshots__/funciton-call.spec.js.snap diff --git a/src/dialog/Dialog.tsx b/src/dialog/Dialog.tsx index 7c29fad3b..20a6332e9 100644 --- a/src/dialog/Dialog.tsx +++ b/src/dialog/Dialog.tsx @@ -2,7 +2,13 @@ import { PropType, reactive, defineComponent } from 'vue'; // Utils import { callInterceptor, Interceptor } from '../utils/interceptor'; -import { createNamespace, addUnit, pick, UnknownProp } from '../utils'; +import { + pick, + addUnit, + isFunction, + UnknownProp, + createNamespace, +} from '../utils'; import { BORDER_TOP, BORDER_LEFT } from '../utils/constant'; import { popupSharedProps, popupSharedPropKeys } from '../popup/shared'; @@ -16,6 +22,7 @@ const [name, bem, t] = createNamespace('dialog'); export type DialogTheme = 'default' | 'round-button'; export type DialogAction = 'confirm' | 'cancel'; +export type DialogMessage = string | (() => JSX.Element); export type DialogMessageAlign = 'left' | 'center' | 'right'; const popupKeys = [ @@ -32,7 +39,7 @@ export default defineComponent({ title: String, theme: String as PropType, width: [Number, String], - message: String, + message: [String, Function] as PropType, callback: Function as PropType<(action?: DialogAction) => void>, allowHtml: Boolean, className: UnknownProp, @@ -119,15 +126,31 @@ export default defineComponent({ } }; + const renderMessage = (hasTitle: boolean) => { + const { message, allowHtml, messageAlign } = props; + const classNames = bem('message', { + 'has-title': hasTitle, + [messageAlign as string]: messageAlign, + }); + + if (allowHtml && typeof message === 'string') { + return
; + } + return ( +
+ {isFunction(message) ? message() : message} +
+ ); + }; + const renderContent = () => { if (slots.default) { return
{slots.default()}
; } - const { title, message, allowHtml, messageAlign } = props; + const { title, message, allowHtml } = props; if (message) { - const hasTitle = title || slots.title; - + const hasTitle = !!(title || slots.title); return (
-
+ {renderMessage(hasTitle)}
); } diff --git a/src/dialog/README.md b/src/dialog/README.md index 504028b24..bde86747a 100644 --- a/src/dialog/README.md +++ b/src/dialog/README.md @@ -142,7 +142,7 @@ export default { | --- | --- | --- | --- | | title | Title | _string_ | - | | width | Dialog width | _number \| string_ | `320px` | -| message | Message | _string_ | - | +| message | Message | _string \| () => JSX.ELement_ | - | | messageAlign | Message text align,can be set to `left` `right` | _string_ | `center` | | theme | Theme style,can be set to `round-button` | _string_ | `default` | | className | Custom className | _string \| Array \| object_ | - | @@ -170,7 +170,7 @@ export default { | v-model:show | Whether to show dialog | _boolean_ | - | | title | Title | _string_ | - | | width | Width | _number \| string_ | `320px` | -| message | Message | _string_ | - | +| message | Message | _string \| () => JSX.ELement_ | - | | message-align | Message align,can be set to `left` `right` | _string_ | `center` | | theme | Theme style,can be set to `round-button` | _string_ | `default` | | show-confirm-button | Whether to show confirm button | _boolean_ | `true` | diff --git a/src/dialog/README.zh-CN.md b/src/dialog/README.zh-CN.md index bedad1ed9..96817ba66 100644 --- a/src/dialog/README.zh-CN.md +++ b/src/dialog/README.zh-CN.md @@ -175,7 +175,7 @@ export default { | --- | --- | --- | --- | | title | 标题 | _string_ | - | | width | 弹窗宽度,默认单位为 `px` | _number \| string_ | `320px` | -| message | 文本内容,支持通过 `\n` 换行 | _string_ | - | +| message | 文本内容,支持通过 `\n` 换行 | _string \| () => JSX.ELement_ | - | | messageAlign | 内容对齐方式,可选值为 `left` `right` | _string_ | `center` | | theme | 样式风格,可选值为 `round-button` | _string_ | `default` | | className | 自定义类名 | _string \| Array \| object_ | - | @@ -205,8 +205,8 @@ export default { | v-model:show | 是否显示弹窗 | _boolean_ | - | | title | 标题 | _string_ | - | | width | 弹窗宽度,默认单位为 `px` | _number \| string_ | `320px` | -| message | 文本内容,支持通过 `\n` 换行 | _string_ | - | -| message-align | 内容对齐方式,可选值为 `left` `right` | _string_ | `center` | +| message | 文本内容,支持通过 `\n` 换行 | _string \| () => JSX.ELement_ | - | +| message-align | 内容水平对齐方式,可选值为 `left` `right` | _string_ | `center` | | theme | 样式风格,可选值为 `round-button` | _string_ | `default` | | show-confirm-button | 是否展示确认按钮 | _boolean_ | `true` | | show-cancel-button | 是否展示取消按钮 | _boolean_ | `false` | diff --git a/src/dialog/index.tsx b/src/dialog/index.tsx index 2a6ecaa79..87a561ab9 100644 --- a/src/dialog/index.tsx +++ b/src/dialog/index.tsx @@ -5,6 +5,7 @@ import { mountComponent, usePopupState } from '../utils/mount-component'; import VanDialog, { DialogTheme, DialogAction, + DialogMessage, DialogMessageAlign, } from './Dialog'; @@ -12,7 +13,7 @@ export type DialogOptions = { title?: string; width?: string | number; theme?: DialogTheme; - message?: string; + message?: DialogMessage; overlay?: boolean; teleport?: TeleportProps['to']; className?: unknown; @@ -128,4 +129,4 @@ Dialog.Component = withInstall(VanDialog); export default Dialog; export { Dialog }; -export type { DialogTheme, DialogMessageAlign }; +export type { DialogTheme, DialogMessage, DialogMessageAlign }; diff --git a/src/dialog/test/__snapshots__/funciton-call.spec.js.snap b/src/dialog/test/__snapshots__/funciton-call.spec.js.snap new file mode 100644 index 000000000..4b6c3bfc2 --- /dev/null +++ b/src/dialog/test/__snapshots__/funciton-call.spec.js.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should allow to render JSX message 1`] = ` +
+
+ foo +
+
+`; diff --git a/src/dialog/test/funciton-call.spec.js b/src/dialog/test/funciton-call.spec.js index 34517e860..5c89ec29a 100644 --- a/src/dialog/test/funciton-call.spec.js +++ b/src/dialog/test/funciton-call.spec.js @@ -49,3 +49,17 @@ test('should close dialog after calling Dialog.call', async () => { 'van-dialog-bounce-leave-active' ); }); + +test('should allow to render JSX message', async () => { + const wrapper = document.createElement('div'); + Dialog.alert({ + message: () =>
foo
, + teleport: wrapper, + }); + + await later(); + const dialog = wrapper.querySelector('.van-dialog'); + expect( + dialog.querySelector('.van-dialog__message').outerHTML + ).toMatchSnapshot(); +});