feat(message): 添加 消息提示模块。

This commit is contained in:
Ivan Li 2021-03-06 23:05:16 +08:00
parent 12621fae55
commit 699a7cecd3
7 changed files with 127 additions and 3 deletions

View File

@ -0,0 +1,2 @@
import { controller } from './messages-container';
export const Message = controller;

View File

@ -0,0 +1,13 @@
.message {
@apply px-4 py-2 rounded-xl bg-white dark:bg-gray-900;
}
.error {
@apply bg-red-200 text-red-600;
}
.success {
@apply bg-green-200 text-green-600;
}
.container {
@apply mt-5;
@apply grid grid-cols-1 gap-y-2 justify-items-center;
}

View File

@ -0,0 +1,14 @@
// This file is automatically generated from your CSS. Any edits will be overwritten.
declare namespace MessageScssNamespace {
export interface IMessageScss {
container: string;
dark: string;
error: string;
message: string;
success: string;
}
}
declare const MessageScssModule: MessageScssNamespace.IMessageScss;
export = MessageScssModule;

View File

@ -0,0 +1,25 @@
import styles from './message.scss';
import classNames from 'classnames';
import { h } from 'preact';
export class MessageOptions {
message = '';
type: 'success' | 'error' | 'default' = 'default';
/**
*
*/
duration = 5000;
}
export const MessageComponent = ({ message, type }: MessageOptions) => {
return (
<section
className={classNames(styles.message, {
[styles.success]: type === 'success',
[styles.error]: type === 'error'
})}
>
{message}
</section>
);
};

View File

@ -0,0 +1,66 @@
import { MessageComponent, MessageOptions } from './message';
import { action, autorun, computed, makeObservable, observable } from 'mobx';
import { h } from 'preact';
import { createOverlay } from '../overlay/overlay';
import { observer } from 'mobx-react';
import styles from './message.scss';
class Store {
@observable
messages: MessageOptions[] = [];
isNeedCreateView = true;
constructor() {
makeObservable(this);
autorun(() => {
if (this.messageComponents.length > 0 && this.isNeedCreateView) {
this.isNeedCreateView = false;
createOverlay({
content: <MessageContainer store={this} />,
mask: false
});
}
});
}
@computed
get messageComponents() {
return this.messages.map((options, index) => (
<MessageComponent {...options} key={index} />
));
}
@action
add(options: MessageOptions) {
this.messages.push(options);
setTimeout(() => {
const index = this.messages.indexOf(options);
if (index === -1) {
return;
}
this.messages.splice(index, 1);
}, options.duration);
}
}
interface Controller {
error: (message: string) => void;
success: (message: string) => void;
}
const store = new Store();
const addMessage = (options: Partial<MessageOptions & { message: string }>) => {
store.add(Object.assign(new MessageOptions(), options));
};
export const controller: Controller = {
error(message) {
return addMessage({ message, type: 'error' });
},
success(message) {
return addMessage({ message, type: 'success' });
}
};
const MessageContainer = observer(({ store }: { store: Store }) => {
return <ol className={styles.container}>{store.messageComponents}</ol>;
});

View File

@ -2,5 +2,8 @@
@apply opacity-50 bg-white fixed top-0 bottom-0 left-0 right-0;
}
.body {
@apply fixed top-0 bottom-0 left-0 right-0;
@apply fixed top-0 bottom-0 left-0 right-0 pointer-events-none;
& > * {
@apply pointer-events-auto;
}
}

View File

@ -9,6 +9,7 @@ import { createPortal } from 'preact/compat';
interface Props {
content: ComponentChild;
overlayId?: string;
mask?: boolean;
onClose?: () => void;
onOk?: () => void;
onCancel?: () => void;
@ -59,8 +60,8 @@ export const Overlay = (props: Props) => {
isVisible ? (
<OverlayProvider value={controller}>
<Fragment>
<div class={styles.mask}></div>
<div class={styles.body}>{props.content}</div>
{props.mask ?? true ? <div class={styles.mask}></div> : null}
<div className={styles.body}>{props.content}</div>
</Fragment>
</OverlayProvider>
) : (