Слияние кода завершено, страница обновится автоматически
import React, { CSSProperties, Key, PureComponent, ReactNode } from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import classNames from 'classnames';
import { NotificationManager } from 'choerodon-ui/shared';
import noop from 'lodash/noop';
import debounce from 'lodash/debounce';
import scrollIntoView from 'scroll-into-view-if-needed';
import { NotificationInterface } from 'choerodon-ui/shared/notification-manager';
import Animate from '../animate';
import Notice, { NoticeProps } from './Notice';
import { getNoticeLocale } from './locale';
import EventManager from '../_util/EventManager';
import { getStyle } from '../rc-components/util/Dom/css';
export function newNotificationInstance(properties: NotificationProps & { getContainer?: (() => HTMLElement) | undefined }, callback: (api: NotificationInterface) => void) {
const { getContainer, ...props } = properties || {};
const div = document.createElement('div');
if (getContainer) {
const root = getContainer();
root.appendChild(div);
} else {
document.body.appendChild(div);
}
let called = false;
function ref(notification) {
if (called) {
return;
}
called = true;
callback({
notice(noticeProps) {
notification.add(noticeProps);
},
removeNotice(key) {
notification.remove(key);
},
destroy() {
unmountComponentAtNode(div);
const { parentNode } = div;
if (parentNode) {
parentNode.removeChild(div);
}
},
});
}
render(<Notification {...props} ref={ref} />, div);
}
export interface NotificationProps {
prefixCls?: string;
className?: string;
transitionName?: string;
animation?: string;
style?: CSSProperties;
contentClassName?: string;
closeIcon?: ReactNode;
maxCount?: number;
foldCount?: number;
}
export interface NotificationState {
notices: NoticeProps[];
scrollHeight: string | number;
totalHeight: number;
offset: number;
}
export default class Notification extends PureComponent<NotificationProps, NotificationState> {
static defaultProps = {
prefixCls: 'c7n-notification',
animation: 'fade',
style: {
top: 65,
left: '50%',
},
};
static newInstance = newNotificationInstance;
scrollRef: HTMLDivElement | null = null;
scrollEvent?: any;
isRemove: boolean;
state: NotificationState = {
notices: [],
scrollHeight: 'auto',
totalHeight: 0,
offset: 0,
};
dispose() {
const { scrollEvent } = this;
if (scrollEvent) {
scrollEvent.clear();
}
}
componentWillUnmount() {
this.dispose();
}
getTransitionName() {
const { transitionName, animation, prefixCls } = this.props;
if (!transitionName && animation) {
return `${prefixCls}-${animation}`;
}
return transitionName;
}
onAnimateEnd = () => {
const { notices } = this.state;
const { foldCount } = this.props;
if (foldCount) {
const { scrollRef } = this;
if (scrollRef) {
const childSpan = scrollRef.firstChild;
if (!childSpan) return;
const childNodes = childSpan.childNodes;
const lastNode = childNodes[childNodes.length - 1] as HTMLDivElement;
if (childNodes.length > foldCount && notices.length > foldCount) {
let totalHeight = 0;
for (let i = 0; i < childNodes.length; i += 1) {
const element = childNodes[i] as HTMLDivElement;
totalHeight += element.offsetHeight + getStyle(element, 'margin-bottom');
}
const scrollHeight = (totalHeight / childNodes.length) * (foldCount + 0.5);
this.setState(
{
scrollHeight,
totalHeight,
}, () => {
if (!this.isRemove) {
scrollIntoView(lastNode, {
block: 'center',
behavior: 'smooth',
scrollMode: 'if-needed',
boundary: scrollRef,
});
}
});
} else {
this.setState({
scrollHeight: 'auto',
});
}
}
}
};
add(notice: NoticeProps) {
if (!notice.key) {
notice.key = NotificationManager.getUuid();
}
const { key } = notice;
const { maxCount } = this.props;
this.setState(previousState => {
const notices = previousState.notices;
if (!notices.filter(v => v.key === key).length) {
if (maxCount && notices && notices.length > 0 && notices.length >= maxCount) {
notices.shift();
}
this.isRemove = false;
return {
...previousState,
notices: notices.concat(notice),
};
}
});
}
remove(key: Key) {
this.setState(previousState => {
this.isRemove = true;
const notices = previousState.notices.filter(notice => notice.key !== key);
return {
notices,
};
});
}
clearNotices = (): void => {
this.setState({
notices: [],
});
};
handleNoticeClose = (eventKey): void => {
const { notices } = this.state;
const notice = notices.find(({ key }) => key === eventKey);
this.remove(eventKey);
if (notice) {
const { onClose = noop } = notice;
onClose(eventKey);
}
};
saveScrollRef = (dom) => {
this.scrollRef = dom;
if (dom) {
const debouncedResize = debounce((e) => {
this.setState({
offset: e.target.scrollTop,
});
}, 200);
this.scrollEvent = new EventManager(dom).addEventListener('scroll', debouncedResize);
} else {
this.dispose();
}
};
render() {
const { notices, scrollHeight, offset, totalHeight } = this.state;
const { contentClassName, prefixCls, closeIcon, className, style, foldCount } = this.props;
const noticeNodes = notices.map((notice) => (
<Notice
prefixCls={prefixCls}
contentClassName={contentClassName}
{...notice}
onClose={this.handleNoticeClose}
closeIcon={closeIcon}
key={notice.key}
eventKey={notice.key}
foldable={!!foldCount}
offset={offset}
scrollHeight={scrollHeight}
totalHeight={totalHeight}
/>
));
const cls = classNames(`${prefixCls}`, className, [{
[`${prefixCls}-before-shadow`]: !!foldCount && notices.length > foldCount && offset > 0,
[`${prefixCls}-after-shadow`]:
foldCount && notices.length > foldCount &&
totalHeight - (typeof scrollHeight === 'number' ? scrollHeight : 0) - offset > 15,
}]);
const scrollCls = classNames({
[`${prefixCls}-scroll`]: !!foldCount && scrollHeight !== 'auto',
});
const runtimeLocale = getNoticeLocale();
return (
<div className={cls} style={style}>
<div
className={scrollCls}
style={foldCount ? {
height: scrollHeight,
} : undefined}
ref={foldCount ? this.saveScrollRef : undefined}
>
<Animate onEnd={this.onAnimateEnd} transitionName={this.getTransitionName()}>
{noticeNodes}
</Animate>
</div>
{foldCount && notices.length > foldCount && (
<div className={`${prefixCls}-alert`}>
<div className={`${prefixCls}-alert-message`}>{`${runtimeLocale.total} ${notices.length} ${runtimeLocale.message}`}</div>
<div className={`${prefixCls}-alert-close`} onClick={this.clearNotices}>{`${runtimeLocale.closeAll}`}</div>
</div>
)}
</div>
);
}
}
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарий ( 0 )