types(Toast): add Toast method typing (#8095)

This commit is contained in:
neverland 2021-02-07 10:24:20 +08:00 committed by GitHub
parent 7332e5201c
commit 02669ad025
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 192 additions and 164 deletions

View File

@ -30,8 +30,9 @@
</demo-block> </demo-block>
</template> </template>
<script> <script lang="ts">
import { useTranslate } from '@demo/use-translate'; import { useTranslate } from '@demo/use-translate';
import type { LoadingType } from '../../loading';
import Toast from '..'; import Toast from '..';
const i18n = { const i18n = {
@ -40,7 +41,7 @@ const i18n = {
text: '提示内容', text: '提示内容',
text2: '成功文案', text2: '成功文案',
text3: '失败文案', text3: '失败文案',
text4: (second) => `倒计时 ${second}`, text4: (second: number) => `倒计时 ${second}`,
title1: '文字提示', title1: '文字提示',
title2: '加载提示', title2: '加载提示',
title3: '成功/失败提示', title3: '成功/失败提示',
@ -58,7 +59,7 @@ const i18n = {
text: 'Some messages', text: 'Some messages',
text2: 'Success', text2: 'Success',
text3: 'Fail', text3: 'Fail',
text4: (second) => `${second} seconds`, text4: (second: number) => `${second} seconds`,
title1: 'Text', title1: 'Text',
title2: 'Loading', title2: 'Loading',
title3: 'Success/Fail', title3: 'Success/Fail',
@ -77,7 +78,7 @@ export default {
setup() { setup() {
const t = useTranslate(i18n); const t = useTranslate(i18n);
const showLoadingToast = (loadingType) => { const showLoadingToast = (loadingType: LoadingType) => {
Toast.loading({ Toast.loading({
forbidClick: true, forbidClick: true,
message: t('loading'), message: t('loading'),

View File

@ -1,160 +0,0 @@
import { ref, watch, getCurrentInstance } from 'vue';
import { isObject, inBrowser } from '../utils';
import { mountComponent, usePopupState } from '../utils/mount-component';
import VanToast from './Toast';
const defaultOptions = {
icon: '',
type: 'text',
message: '',
className: '',
overlay: false,
onClose: null,
onOpened: null,
duration: 2000,
teleport: 'body',
iconPrefix: undefined,
position: 'middle',
transition: 'van-fade',
forbidClick: false,
loadingType: undefined,
overlayClass: '',
overlayStyle: null,
closeOnClick: false,
closeOnClickOverlay: false,
};
// default options of specific type
let defaultOptionsMap = {};
let queue = [];
let allowMultiple = false;
let currentOptions = {
...defaultOptions,
};
function parseOptions(message) {
if (isObject(message)) {
return message;
}
return { message };
}
function createInstance() {
const { instance, unmount } = mountComponent({
setup() {
const message = ref();
const { open, state, close, toggle } = usePopupState();
const onClosed = () => {
if (allowMultiple) {
queue = queue.filter((item) => item !== instance);
unmount();
}
};
watch(message, (value) => {
state.message = value;
});
getCurrentInstance().render = () => (
<VanToast
{...{
...state,
onClosed,
'onUpdate:show': toggle,
}}
/>
);
return {
open,
clear: close,
message,
};
},
});
return instance;
}
function getInstance() {
/* istanbul ignore if */
if (!inBrowser) {
return {};
}
if (!queue.length || allowMultiple) {
const instance = createInstance();
queue.push(instance);
}
return queue[queue.length - 1];
}
function Toast(options = {}) {
const toast = getInstance();
options = parseOptions(options);
options = {
...currentOptions,
...defaultOptionsMap[options.type || currentOptions.type],
...options,
};
toast.open(options);
return toast;
}
const createMethod = (type) => (options) =>
Toast({
type,
...parseOptions(options),
});
['loading', 'success', 'fail'].forEach((method) => {
Toast[method] = createMethod(method);
});
Toast.clear = (all) => {
if (queue.length) {
if (all) {
queue.forEach((toast) => {
toast.clear();
});
queue = [];
} else if (!allowMultiple) {
queue[0].clear();
} else {
queue.shift().clear();
}
}
};
Toast.setDefaultOptions = (type, options) => {
if (typeof type === 'string') {
defaultOptionsMap[type] = options;
} else {
Object.assign(currentOptions, type);
}
};
Toast.resetDefaultOptions = (type) => {
if (typeof type === 'string') {
defaultOptionsMap[type] = null;
} else {
currentOptions = { ...defaultOptions };
defaultOptionsMap = {};
}
};
Toast.allowMultiple = (value = true) => {
allowMultiple = value;
};
Toast.install = (app) => {
app.use(VanToast);
app.config.globalProperties.$toast = Toast;
};
export default Toast;

187
src/toast/index.tsx Normal file
View File

@ -0,0 +1,187 @@
import { ref, App, TeleportProps, getCurrentInstance } from 'vue';
import { isObject, inBrowser } from '../utils';
import { mountComponent, usePopupState } from '../utils/mount-component';
import VanToast, { ToastType, ToastPosition } from './Toast';
import type { LoadingType } from '../loading';
export type ToastOptions = {
icon?: string;
type?: ToastType;
mask?: boolean;
message?: string | number;
onClose?: () => void;
onOpened?: () => void;
overlay?: boolean;
duration?: number;
teleport?: TeleportProps['to'];
position?: ToastPosition;
className?: any;
transition?: string;
iconPrefix?: string;
loadingType?: LoadingType;
forbidClick?: boolean;
closeOnClick?: boolean;
overlayClass?: any;
overlayStyle?: Record<string, any>;
closeOnClickOverlay?: boolean;
};
const defaultOptions: ToastOptions = {
icon: '',
type: 'text',
message: '',
className: '',
overlay: false,
onClose: undefined,
onOpened: undefined,
duration: 2000,
teleport: 'body',
iconPrefix: undefined,
position: 'middle',
transition: 'van-fade',
forbidClick: false,
loadingType: undefined,
overlayClass: '',
overlayStyle: undefined,
closeOnClick: false,
closeOnClickOverlay: false,
};
let queue: any[] = [];
let allowMultiple = false;
let currentOptions = { ...defaultOptions };
// default options of specific type
let defaultOptionsMap: Record<string, ToastOptions | null> = {};
function parseOptions(message: string | ToastOptions): ToastOptions {
if (isObject(message)) {
return message;
}
return { message };
}
function createInstance() {
const { instance, unmount } = mountComponent({
setup() {
const message = ref();
const { open, state, close, toggle } = usePopupState();
const onClosed = () => {
if (allowMultiple) {
queue = queue.filter((item) => item !== instance);
unmount();
}
};
const render = () => {
const attrs: Record<string, unknown> = {
...state,
onClosed,
'onUpdate:show': toggle,
};
if (message.value) {
attrs.message = message.value;
}
return <VanToast {...attrs} />;
};
// rewrite render function
(getCurrentInstance() as any).render = render;
return {
open,
clear: close,
message,
};
},
});
return instance;
}
function getInstance() {
/* istanbul ignore if */
if (!inBrowser) {
return {};
}
if (!queue.length || allowMultiple) {
const instance = createInstance();
queue.push(instance);
}
return queue[queue.length - 1];
}
function Toast(options: string | ToastOptions = {}) {
const toast = getInstance();
const parsedOptions = parseOptions(options);
toast.open({
...currentOptions,
...defaultOptionsMap[parsedOptions.type || currentOptions.type!],
...parsedOptions,
});
return toast;
}
const createMethod = (type: ToastType) => (options: string | ToastOptions) =>
Toast({
type,
...parseOptions(options),
});
Toast.loading = createMethod('loading');
Toast.success = createMethod('success');
Toast.fail = createMethod('fail');
Toast.clear = (all?: boolean) => {
if (queue.length) {
if (all) {
queue.forEach((toast) => {
toast.clear();
});
queue = [];
} else if (!allowMultiple) {
queue[0].clear();
} else {
queue.shift().clear();
}
}
};
function setDefaultOptions(options: ToastOptions): void;
function setDefaultOptions(type: ToastType, options: ToastOptions): void;
function setDefaultOptions(type: ToastType | ToastOptions, options?: any) {
if (typeof type === 'string') {
defaultOptionsMap[type] = options;
} else {
Object.assign(currentOptions, type);
}
}
Toast.setDefaultOptions = setDefaultOptions;
Toast.resetDefaultOptions = (type?: ToastType) => {
if (typeof type === 'string') {
defaultOptionsMap[type] = null;
} else {
currentOptions = { ...defaultOptions };
defaultOptionsMap = {};
}
};
Toast.allowMultiple = (value = true) => {
allowMultiple = value;
};
Toast.install = (app: App) => {
app.use(VanToast as any);
app.config.globalProperties.$toast = Toast;
};
export default Toast;