vant/src/share-sheet/ShareSheet.tsx
neverland bd609e1df0
perf: add truthProp util (#8522)
* perf: add TruthyProp util

* chore: rename

* chore: upd
2021-04-14 10:26:21 +08:00

149 lines
3.6 KiB
TypeScript

import { PropType, defineComponent } from 'vue';
// Utils
import { truthProp, createNamespace, extend, pick } from '../utils';
import { popupSharedProps, popupSharedPropKeys } from '../popup/shared';
// Components
import { Popup } from '../popup';
export type ShareSheetOption = {
name: string;
icon: string;
className?: string;
description?: string;
};
export type ShareSheetOptions = ShareSheetOption[] | ShareSheetOption[][];
const PRESET_ICONS = [
'qq',
'link',
'weibo',
'wechat',
'poster',
'qrcode',
'weapp-qrcode',
'wechat-moments',
];
const popupKeys = [
...popupSharedPropKeys,
'closeOnPopstate',
'safeAreaInsetBottom',
] as const;
function getIconURL(icon: string) {
if (PRESET_ICONS.includes(icon)) {
return `https://img.yzcdn.cn/vant/share-sheet-${icon}.png`;
}
return icon;
}
const [name, bem, t] = createNamespace('share-sheet');
export default defineComponent({
name,
props: extend({}, popupSharedProps, {
title: String,
cancelText: String,
description: String,
closeOnPopstate: truthProp,
safeAreaInsetBottom: truthProp,
options: {
type: Array as PropType<ShareSheetOptions>,
default: () => [],
},
}),
emits: ['cancel', 'select', 'update:show'],
setup(props, { emit, slots }) {
const updateShow = (value: boolean) => emit('update:show', value);
const onCancel = () => {
updateShow(false);
emit('cancel');
};
const onSelect = (option: ShareSheetOption, index: number) =>
emit('select', option, index);
const renderHeader = () => {
const title = slots.title ? slots.title() : props.title;
const description = slots.description
? slots.description()
: props.description;
if (title || description) {
return (
<div class={bem('header')}>
{title && <h2 class={bem('title')}>{title}</h2>}
{description && (
<span class={bem('description')}>{description}</span>
)}
</div>
);
}
};
const renderOption = (option: ShareSheetOption, index: number) => {
const { name, icon, className, description } = option;
return (
<div
role="button"
tabindex={0}
class={[bem('option'), className]}
onClick={() => onSelect(option, index)}
>
<img src={getIconURL(icon)} class={bem('icon')} />
{name && <span class={bem('name')}>{name}</span>}
{description && (
<span class={bem('option-description')}>{description}</span>
)}
</div>
);
};
const renderOptions = (options: ShareSheetOption[], border?: boolean) => (
<div class={bem('options', { border })}>{options.map(renderOption)}</div>
);
const renderRows = () => {
const { options } = props;
if (Array.isArray(options[0])) {
return (options as ShareSheetOption[][]).map((item, index) =>
renderOptions(item, index !== 0)
);
}
return renderOptions(options as ShareSheetOption[]);
};
const renderCancelButton = () => {
const cancelText = props.cancelText ?? t('cancel');
if (slots.cancel || cancelText) {
return (
<button type="button" class={bem('cancel')} onClick={onCancel}>
{slots.cancel ? slots.cancel() : cancelText}
</button>
);
}
};
return () => (
<Popup
round
class={bem()}
position="bottom"
{...pick(props, popupKeys)}
{...{ 'onUpdate:show': updateShow }}
>
{renderHeader()}
{renderRows()}
{renderCancelButton()}
</Popup>
);
},
});