mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
feat(Dialog): allow to render JSX message (#8420)
* feat(Dialog): allow to render JSX message * types: add DialogMessage type
This commit is contained in:
parent
1a6930fa73
commit
eec186ac19
@ -2,7 +2,13 @@ import { PropType, reactive, defineComponent } from 'vue';
|
|||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import { callInterceptor, Interceptor } from '../utils/interceptor';
|
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 { BORDER_TOP, BORDER_LEFT } from '../utils/constant';
|
||||||
import { popupSharedProps, popupSharedPropKeys } from '../popup/shared';
|
import { popupSharedProps, popupSharedPropKeys } from '../popup/shared';
|
||||||
|
|
||||||
@ -16,6 +22,7 @@ const [name, bem, t] = createNamespace('dialog');
|
|||||||
|
|
||||||
export type DialogTheme = 'default' | 'round-button';
|
export type DialogTheme = 'default' | 'round-button';
|
||||||
export type DialogAction = 'confirm' | 'cancel';
|
export type DialogAction = 'confirm' | 'cancel';
|
||||||
|
export type DialogMessage = string | (() => JSX.Element);
|
||||||
export type DialogMessageAlign = 'left' | 'center' | 'right';
|
export type DialogMessageAlign = 'left' | 'center' | 'right';
|
||||||
|
|
||||||
const popupKeys = [
|
const popupKeys = [
|
||||||
@ -32,7 +39,7 @@ export default defineComponent({
|
|||||||
title: String,
|
title: String,
|
||||||
theme: String as PropType<DialogTheme>,
|
theme: String as PropType<DialogTheme>,
|
||||||
width: [Number, String],
|
width: [Number, String],
|
||||||
message: String,
|
message: [String, Function] as PropType<DialogMessage>,
|
||||||
callback: Function as PropType<(action?: DialogAction) => void>,
|
callback: Function as PropType<(action?: DialogAction) => void>,
|
||||||
allowHtml: Boolean,
|
allowHtml: Boolean,
|
||||||
className: UnknownProp,
|
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 <div class={classNames} innerHTML={message} />;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div class={classNames}>
|
||||||
|
{isFunction(message) ? message() : message}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const renderContent = () => {
|
const renderContent = () => {
|
||||||
if (slots.default) {
|
if (slots.default) {
|
||||||
return <div class={bem('content')}>{slots.default()}</div>;
|
return <div class={bem('content')}>{slots.default()}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { title, message, allowHtml, messageAlign } = props;
|
const { title, message, allowHtml } = props;
|
||||||
if (message) {
|
if (message) {
|
||||||
const hasTitle = title || slots.title;
|
const hasTitle = !!(title || slots.title);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
// add key to force re-render
|
// add key to force re-render
|
||||||
@ -135,15 +158,7 @@ export default defineComponent({
|
|||||||
key={allowHtml ? 1 : 0}
|
key={allowHtml ? 1 : 0}
|
||||||
class={bem('content', { isolated: !hasTitle })}
|
class={bem('content', { isolated: !hasTitle })}
|
||||||
>
|
>
|
||||||
<div
|
{renderMessage(hasTitle)}
|
||||||
class={bem('message', {
|
|
||||||
'has-title': hasTitle,
|
|
||||||
[messageAlign as string]: messageAlign,
|
|
||||||
})}
|
|
||||||
{...{
|
|
||||||
[allowHtml ? 'innerHTML' : 'textContent']: message,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ export default {
|
|||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| title | Title | _string_ | - |
|
| title | Title | _string_ | - |
|
||||||
| width | Dialog width | _number \| string_ | `320px` |
|
| 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` |
|
| messageAlign | Message text align,can be set to `left` `right` | _string_ | `center` |
|
||||||
| theme | Theme style,can be set to `round-button` | _string_ | `default` |
|
| theme | Theme style,can be set to `round-button` | _string_ | `default` |
|
||||||
| className | Custom className | _string \| Array \| object_ | - |
|
| className | Custom className | _string \| Array \| object_ | - |
|
||||||
@ -170,7 +170,7 @@ export default {
|
|||||||
| v-model:show | Whether to show dialog | _boolean_ | - |
|
| v-model:show | Whether to show dialog | _boolean_ | - |
|
||||||
| title | Title | _string_ | - |
|
| title | Title | _string_ | - |
|
||||||
| width | Width | _number \| string_ | `320px` |
|
| 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` |
|
| message-align | Message align,can be set to `left` `right` | _string_ | `center` |
|
||||||
| theme | Theme style,can be set to `round-button` | _string_ | `default` |
|
| theme | Theme style,can be set to `round-button` | _string_ | `default` |
|
||||||
| show-confirm-button | Whether to show confirm button | _boolean_ | `true` |
|
| show-confirm-button | Whether to show confirm button | _boolean_ | `true` |
|
||||||
|
@ -175,7 +175,7 @@ export default {
|
|||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| title | 标题 | _string_ | - |
|
| title | 标题 | _string_ | - |
|
||||||
| width | 弹窗宽度,默认单位为 `px` | _number \| string_ | `320px` |
|
| width | 弹窗宽度,默认单位为 `px` | _number \| string_ | `320px` |
|
||||||
| message | 文本内容,支持通过 `\n` 换行 | _string_ | - |
|
| message | 文本内容,支持通过 `\n` 换行 | _string \| () => JSX.ELement_ | - |
|
||||||
| messageAlign | 内容对齐方式,可选值为 `left` `right` | _string_ | `center` |
|
| messageAlign | 内容对齐方式,可选值为 `left` `right` | _string_ | `center` |
|
||||||
| theme | 样式风格,可选值为 `round-button` | _string_ | `default` |
|
| theme | 样式风格,可选值为 `round-button` | _string_ | `default` |
|
||||||
| className | 自定义类名 | _string \| Array \| object_ | - |
|
| className | 自定义类名 | _string \| Array \| object_ | - |
|
||||||
@ -205,8 +205,8 @@ export default {
|
|||||||
| v-model:show | 是否显示弹窗 | _boolean_ | - |
|
| v-model:show | 是否显示弹窗 | _boolean_ | - |
|
||||||
| title | 标题 | _string_ | - |
|
| title | 标题 | _string_ | - |
|
||||||
| width | 弹窗宽度,默认单位为 `px` | _number \| string_ | `320px` |
|
| width | 弹窗宽度,默认单位为 `px` | _number \| string_ | `320px` |
|
||||||
| message | 文本内容,支持通过 `\n` 换行 | _string_ | - |
|
| message | 文本内容,支持通过 `\n` 换行 | _string \| () => JSX.ELement_ | - |
|
||||||
| message-align | 内容对齐方式,可选值为 `left` `right` | _string_ | `center` |
|
| message-align | 内容水平对齐方式,可选值为 `left` `right` | _string_ | `center` |
|
||||||
| theme | 样式风格,可选值为 `round-button` | _string_ | `default` |
|
| theme | 样式风格,可选值为 `round-button` | _string_ | `default` |
|
||||||
| show-confirm-button | 是否展示确认按钮 | _boolean_ | `true` |
|
| show-confirm-button | 是否展示确认按钮 | _boolean_ | `true` |
|
||||||
| show-cancel-button | 是否展示取消按钮 | _boolean_ | `false` |
|
| show-cancel-button | 是否展示取消按钮 | _boolean_ | `false` |
|
||||||
|
@ -5,6 +5,7 @@ import { mountComponent, usePopupState } from '../utils/mount-component';
|
|||||||
import VanDialog, {
|
import VanDialog, {
|
||||||
DialogTheme,
|
DialogTheme,
|
||||||
DialogAction,
|
DialogAction,
|
||||||
|
DialogMessage,
|
||||||
DialogMessageAlign,
|
DialogMessageAlign,
|
||||||
} from './Dialog';
|
} from './Dialog';
|
||||||
|
|
||||||
@ -12,7 +13,7 @@ export type DialogOptions = {
|
|||||||
title?: string;
|
title?: string;
|
||||||
width?: string | number;
|
width?: string | number;
|
||||||
theme?: DialogTheme;
|
theme?: DialogTheme;
|
||||||
message?: string;
|
message?: DialogMessage;
|
||||||
overlay?: boolean;
|
overlay?: boolean;
|
||||||
teleport?: TeleportProps['to'];
|
teleport?: TeleportProps['to'];
|
||||||
className?: unknown;
|
className?: unknown;
|
||||||
@ -128,4 +129,4 @@ Dialog.Component = withInstall<typeof VanDialog>(VanDialog);
|
|||||||
|
|
||||||
export default Dialog;
|
export default Dialog;
|
||||||
export { Dialog };
|
export { Dialog };
|
||||||
export type { DialogTheme, DialogMessageAlign };
|
export type { DialogTheme, DialogMessage, DialogMessageAlign };
|
||||||
|
9
src/dialog/test/__snapshots__/funciton-call.spec.js.snap
Normal file
9
src/dialog/test/__snapshots__/funciton-call.spec.js.snap
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`should allow to render JSX message 1`] = `
|
||||||
|
<div class="van-dialog__message">
|
||||||
|
<div>
|
||||||
|
foo
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
@ -49,3 +49,17 @@ test('should close dialog after calling Dialog.call', async () => {
|
|||||||
'van-dialog-bounce-leave-active'
|
'van-dialog-bounce-leave-active'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should allow to render JSX message', async () => {
|
||||||
|
const wrapper = document.createElement('div');
|
||||||
|
Dialog.alert({
|
||||||
|
message: () => <div>foo</div>,
|
||||||
|
teleport: wrapper,
|
||||||
|
});
|
||||||
|
|
||||||
|
await later();
|
||||||
|
const dialog = wrapper.querySelector('.van-dialog');
|
||||||
|
expect(
|
||||||
|
dialog.querySelector('.van-dialog__message').outerHTML
|
||||||
|
).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user