import React from 'react'; import {Renderer, RendererProps} from '../factory'; import {SchemaNode, Action} from '../types'; import {getScrollParent, autobind} from '../utils/helper'; import {findDOMNode} from 'react-dom'; import {resizeSensor} from '../utils/resize-sensor'; import { BaseSchema, SchemaClassName, SchemaCollection, SchemaTpl } from '../Schema'; import {ActionSchema} from './Action'; /** * Panel渲染器。 * 文档:https://baidu.gitee.io/amis/docs/components/panel */ export interface PanelSchema extends BaseSchema { /** * 指定为Panel渲染器。 */ type: 'panel'; /** * 按钮集合 */ actions?: Array; /** * 按钮集合外层类名 */ actionsClassName?: SchemaClassName; /** * 内容区域 */ body?: SchemaCollection; /** * 配置 Body 容器 className */ bodyClassName?: SchemaClassName; /** * 底部内容区域 */ footer?: SchemaCollection; /** * 配置 footer 容器 className */ footerClassName?: SchemaClassName; /** * footer 和 actions 外层 div 类名。 */ footerWrapClassName?: SchemaClassName; /** * 头部内容, 和 title 二选一。 */ header?: SchemaCollection; /** * 配置 header 容器 className */ headerClassName?: SchemaClassName; /** * Panel 标题 */ title?: SchemaTpl; /** * 固定底部, 想要把按钮固定在底部的时候配置。 */ affixFooter?: boolean | 'always'; } export interface PanelProps extends RendererProps, Omit< PanelSchema, 'type' | 'className' | 'panelClassName' | 'bodyClassName' > {} export default class Panel extends React.Component { static propsList: Array = [ 'header', 'headerClassName', 'footerClassName', 'footerWrapClassName', 'actionsClassName', 'bodyClassName' ]; static defaultProps = { // className: 'Panel--default', // headerClassName: 'Panel-heading', // footerClassName: 'Panel-footer bg-light lter Wrapper', // actionsClassName: 'Panel-footer', // bodyClassName: 'Panel-body' }; parentNode?: any; unSensor: Function; affixDom: React.RefObject = React.createRef(); footerDom: React.RefObject = React.createRef(); timer: ReturnType; componentDidMount() { const dom = findDOMNode(this) as HTMLElement; let parent: HTMLElement | Window | null = dom ? getScrollParent(dom) : null; if (!parent || parent === document.body) { parent = window; } this.parentNode = parent; parent.addEventListener('scroll', this.affixDetect); this.unSensor = resizeSensor(dom as HTMLElement, this.affixDetect); this.affixDetect(); } componentWillUnmount() { const parent = this.parentNode; parent && parent.removeEventListener('scroll', this.affixDetect); this.unSensor && this.unSensor(); clearTimeout(this.timer); } @autobind affixDetect() { if ( !this.props.affixFooter || !this.affixDom.current || !this.footerDom.current ) { return; } const affixDom = this.affixDom.current; const footerDom = this.footerDom.current; const offsetBottom = this.props.affixOffsetBottom ?? this.props.env.affixOffsetBottom ?? 0; let affixed = false; if (footerDom.offsetWidth) { affixDom.style.cssText = `bottom: ${offsetBottom}px;width: ${footerDom.offsetWidth}px`; } else { this.timer = setTimeout(this.affixDetect, 250); return; } if (this.props.affixFooter === 'always') { affixed = true; footerDom.classList.add('invisible2'); } else { const clip = footerDom.getBoundingClientRect(); const clientHeight = window.innerHeight; // affixed = clip.top + clip.height / 2 > clientHeight; affixed = clip.bottom > clientHeight - offsetBottom; } affixed ? affixDom.classList.add('in') : affixDom.classList.remove('in'); } renderBody(): JSX.Element | null { const { type, className, data, header, body, render, bodyClassName, headerClassName, actionsClassName, footerClassName, children, title, actions, footer, classPrefix: ns, ...rest } = this.props; const subProps = { data, ...rest }; return children ? typeof children === 'function' ? children(this.props) : children : body ? render('body', body, subProps) : null; } renderActions() { const {actions, render} = this.props; if (Array.isArray(actions) && actions.length) { return actions.map((action, key) => render('action', action, { type: action.type || 'button', key: key }) ); } return null; } render() { const { type, className, data, header, body, render, bodyClassName, headerClassName, actionsClassName, footerClassName, footerWrapClassName, children, title, footer, affixFooter, classPrefix: ns, classnames: cx, ...rest } = this.props; const subProps = { data, ...rest }; const footerDoms = []; const actions = this.renderActions(); actions && footerDoms.push(
{actions}
); footer && footerDoms.push(
{render('footer', footer, subProps)}
); let footerDom = footerDoms.length ? (
{footerDoms}
) : null; return (
{header ? (
{render('header', header, subProps)}
) : title ? (

{render('title', title, subProps)}

) : null}
{this.renderBody()}
{footerDom} {affixFooter && footerDoms.length ? (
{footerDoms}
) : null}
); } } @Renderer({ type: 'panel', name: 'panel' }) export class PanelRenderer extends Panel {}