@pisell/layout
Version:
基于 Fusion 设计系统的自然布局体系
145 lines (142 loc) • 6.3 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/objectWithoutPropertiesLoose";
var _excluded = ["prefix", "className", "style", "children", "minHeight", "mode", "noPadding", "contentProps", "header", "nav", "aside", "footer", "breakPoints", "sectionGap", "blockGap", "gridGap", "onBreakPointChange"];
import React, { Children, forwardRef, isValidElement, useEffect, useMemo, useRef, useState } from 'react';
import classNames from 'classnames';
import isValidArray from 'is-valid-array';
import ResizeObserver from 'resize-observer-polyfill';
import { getCurBreakPoint, getMaxNumberOfColumns, isValidGap, wrapUnit } from "../utils";
import Context from "../common/context";
import { DEFAULT_BREAK_POINTS } from "../common/constant";
import useCombinedRefs from "../hooks/use-combine-ref";
import useGuid from "../hooks/use-guid";
import PageContent from "./content";
var Page = function Page(props, ref) {
var _classNames;
var prefix = props.prefix,
className = props.className,
style = props.style,
children = props.children,
minHeight = props.minHeight,
mode = props.mode,
noPadding = props.noPadding,
contentProps = props.contentProps,
header = props.header,
nav = props.nav,
aside = props.aside,
footer = props.footer,
breakPointsProp = props.breakPoints,
sectionGap = props.sectionGap,
blockGap = props.blockGap,
gridGap = props.gridGap,
onBreakPointChange = props.onBreakPointChange,
others = _objectWithoutPropertiesLoose(props, _excluded);
var pageStyle = useMemo(function () {
return _extends({}, style, {
minHeight: minHeight
});
}, [style, minHeight]);
// 保证断点一定是有效数组
var breakPoints = isValidArray(breakPointsProp) ? breakPointsProp : DEFAULT_BREAK_POINTS;
var pageRef = useRef(null);
var combinedRef = useCombinedRefs(ref, pageRef);
var contentRef = useRef(null);
var bpRef = useRef(getCurBreakPoint(breakPoints));
var _useState = useState(getCurBreakPoint(breakPoints)),
curBreakPoint = _useState[0],
setBreakPoint = _useState[1];
var guid = useGuid('fd-layout-');
var pageSizeObsr = new ResizeObserver(function () {
var _bpRef$current;
var newBreakPoint = getCurBreakPoint(breakPoints);
if ((bpRef === null || bpRef === void 0 ? void 0 : (_bpRef$current = bpRef.current) === null || _bpRef$current === void 0 ? void 0 : _bpRef$current.width) !== newBreakPoint.width && onBreakPointChange) {
onBreakPointChange(newBreakPoint, bpRef === null || bpRef === void 0 ? void 0 : bpRef.current, breakPoints);
}
bpRef.current = newBreakPoint;
setBreakPoint(newBreakPoint);
});
useEffect(function () {
if (pageRef !== null && pageRef !== void 0 && pageRef.current) {
pageSizeObsr.observe(pageRef.current);
}
// 默认执行一次回调
if (onBreakPointChange) {
onBreakPointChange(getCurBreakPoint(breakPoints), undefined, breakPoints);
}
return function () {
if (pageRef.current) {
pageSizeObsr.unobserve(pageRef.current);
}
};
}, []);
var headerNode = header;
var footerNode = footer;
var navNode = nav;
var asideNode = aside;
var contentsNodes = [];
// 非标准节点 如 Section, P 等
var tmp = Children.map(children, function (child) {
if ( /*#__PURE__*/isValidElement(child)) {
var _child$type;
// @ts-ignore
var tm = child === null || child === void 0 ? void 0 : (_child$type = child.type) === null || _child$type === void 0 ? void 0 : _child$type.typeMark;
if (tm) {
if (tm === 'Header') {
headerNode = child;
} else if (tm === 'Footer') {
footerNode = child;
} else if (tm === 'Aside') {
asideNode = child;
} else if (tm === 'Nav') {
navNode = child;
} else if (tm === 'Content') {
contentsNodes.push(child);
} else {
return child;
}
return null;
}
}
return child;
});
var nonStdChildren = Array.isArray(tmp) ? tmp.filter(function (c) {
return !!c;
}) : null;
var pageCls = classNames(className, (_classNames = {}, _classNames[prefix + "page"] = true, _classNames[prefix + "page--col-" + curBreakPoint.numberOfColumns] = true, _classNames[prefix + "page--not-tab"] = true, _classNames[prefix + "page--headless"] = !headerNode, _classNames[prefix + "page--footless"] = !footerNode, _classNames[prefix + "page--no-padding"] = noPadding, _classNames[prefix + "bg--" + mode] = !!mode, _classNames));
var defaultContent = contentsNodes.length > 0 ? contentsNodes : /*#__PURE__*/React.createElement(PageContent
// @ts-ignore
, _extends({
ref: contentRef,
noPadding: noPadding
// @ts-ignore
}, contentProps), navNode, asideNode, nonStdChildren);
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("style", {
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML: {
__html: "\n :host,\n #" + guid + " {\n --page-max-content-width: " + wrapUnit(curBreakPoint.maxContentWidth === Infinity ? '100%' : wrapUnit(curBreakPoint.maxContentWidth)) + ";\n " + (isValidGap(sectionGap) ? "--page-section-gap: " + wrapUnit(sectionGap) + ";" : '') + "\n " + (isValidGap(blockGap) ? "--page-block-gap: " + wrapUnit(blockGap) + ";" : '') + "\n " + (isValidGap(gridGap) ? "--page-grid-gap: " + wrapUnit(gridGap) + ";" : '') + "\n }"
}
}), /*#__PURE__*/React.createElement("div", _extends({
id: guid,
ref: combinedRef,
className: pageCls,
style: pageStyle
}, others), /*#__PURE__*/React.createElement(Context.Provider, {
value: {
prefix: prefix,
noPadding: noPadding,
sectionGap: sectionGap,
gridGap: gridGap,
blockGap: blockGap,
breakPoint: curBreakPoint,
maxNumberOfColumns: getMaxNumberOfColumns(breakPoints)
}
}, headerNode, defaultContent, footerNode)));
};
var RefPage = /*#__PURE__*/forwardRef(Page);
RefPage.displayName = 'Page';
RefPage.defaultProps = {
prefix: 'fd-layout-',
mode: 'lining',
breakPoints: DEFAULT_BREAK_POINTS
};
export default RefPage;