wix-style-react
Version:
wix-style-react
654 lines (646 loc) • 23.8 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.default = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
var _react = _interopRequireDefault(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _cssElementQueries = require("css-element-queries");
var _PageSt = require("./Page.st.css");
var _PageContext = require("./PageContext");
var _PageHeader = _interopRequireDefault(require("../PageHeader"));
var _PageSection = _interopRequireDefault(require("../PageSection"));
var _PageFooter = _interopRequireDefault(require("../PageFooter"));
var _Content = _interopRequireDefault(require("./Content"));
var _Tail = _interopRequireDefault(require("./Tail"));
var _PageSticky = require("./PageSticky");
var _FixedFooter = _interopRequireDefault(require("./FixedFooter"));
var _ScrollableContainer = _interopRequireDefault(require("../common/ScrollableContainer"));
var _ScrollableContainerCommon = require("../common/PropTypes/ScrollableContainerCommon");
var _excluded = ["className", "horizontalScroll", "style"];
var _jsxFileName = "/home/builduser/work/a9c1ac8876d5057c/packages/wix-style-react/dist/cjs/Page/Page.js";
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
/*
* Page structure without mini-header-overlay:
*
* + PageWrapper (Horizontal Scroll) --
* | +- Page --------------------------
* | | +-- ScrollableContainer (Vertical Scroll)
* | | | +-- MinimizationPlaceholder
* | | | |
* | | | +-----------------------------
* | | | +-- HeaderContainer ------ (position: fixed - when minimized)
* | | | | +-- Page.Header ------------
* | | | | |
* | | | | +---------------------------
* | | | | +-- Page.Tail --------------
* | | | | |
* | | | | +---------------------------
* | | | +-----------------------------
* | | | +-- ContentWrapper------------
* | | | | +-- Page.FixedContent (Deprecated)
* | | | | |
* | | | | +---------------------------
* | | | | +-- Page.Content -----------
* | | | | | +-- Page.Section ---------
* | | | | |
* | | | | +---------------------------
* | | | +-----------------------------
* | | +-------------------------------
* | +--------------------------------- (Page - End)
* +----------------------------------- (PageWrapper - End)
*
* - ScrollableContainer has a data-classnamed 'scrollable-content', and should NOT be renamed, since
* Tooltip is hard-coded-ly using a selector like this: [data-class="page-scrollable-content"]
*/
class Page extends _react.default.PureComponent {
constructor(props) {
super(props);
this._renderFixedFooter = () => {
var {
children
} = this.props;
var childrenObject = getChildrenObject(children);
var {
FixedFooter: FixedFooterChild,
PageContent
} = childrenObject;
var contentFullScreen = PageContent && PageContent.props.fullScreen;
var pageDimensionsStyle = contentFullScreen ? null : this._getPageDimensionsStyle();
if (FixedFooterChild) {
return /*#__PURE__*/_react.default.createElement("div", {
className: _PageSt.classes.fixedFooter,
ref: _ref => {
this.footerWrapperRef = _ref;
},
style: pageDimensionsStyle,
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 491,
columnNumber: 9
}
}, /*#__PURE__*/_react.default.cloneElement(FixedFooterChild, {}));
}
};
this.scrollableContainerRef = /*#__PURE__*/_react.default.createRef();
this._handleScroll = this._handleScroll.bind(this);
this._handleWidthResize = this._handleWidthResize.bind(this);
this._handleWindowResize = this._handleWindowResize.bind(this);
this._calculateComponentsHeights = this._calculateComponentsHeights.bind(this);
this.state = {
headerContainerHeight: 0,
headerWrapperHeight: 0,
tailHeight: 0,
footerHeight: 0,
minimized: false
};
}
componentDidMount() {
this._calculateComponentsHeights();
this.contentResizeListener = new _cssElementQueries.ResizeSensor(this._getScrollContainer().childNodes[0], this._handleWidthResize);
this._handleWidthResize();
window.addEventListener('resize', this._handleWindowResize);
// TODO: Hack to fix cases where initial measurement of headerWrapperHeight is not correct (need to investigate)
// Happens in PageTestStories -> PageWithScroll -> 5. Scroll - Trigger Mini Header
// Maybe there is a transition
var ARBITRARY_SHORT_DURATION_MS = 100;
this.timerId = setTimeout(this._calculateComponentsHeights, ARBITRARY_SHORT_DURATION_MS);
// This is done for backward compatibility only,
// Notifying current users that passed the `scrollableContentRef` prop about the ref current value.
// New users should be encouraged to use the new event handlers onScrollChanged/onScrollAreaChanged
// according to their use case.
this.props.scrollableContentRef && this.props.scrollableContentRef(this.scrollableContainerRef.current);
}
componentDidUpdate(prevProps) {
this._calculateComponentsHeights();
}
componentWillUnmount() {
window.removeEventListener('resize', this._handleWindowResize);
this.contentResizeListener.detach(this._handleResize);
if (this.timerId) {
clearTimeout(this.timerId);
}
}
_getNamedChildren() {
return getChildrenObject(this.props.children);
}
_calculateComponentsHeights() {
var {
headerContainerHeight,
headerWrapperHeight,
tailHeight,
pageHeight,
footerHeight,
minimized
} = this.state;
var newHeaderWrapperHeight = this.headerWrapperRef && !minimized ? this.headerWrapperRef.getBoundingClientRect().height : headerWrapperHeight;
var newHeaderContainerHeight = this.headerWrapperRef && !minimized ? this.headerContainerRef.getBoundingClientRect().height : headerContainerHeight;
var newTailHeight = this.pageHeaderTailRef ? this.pageHeaderTailRef.offsetHeight : 0;
var newPageHeight = this.pageRef ? this.pageRef.offsetHeight : 0;
var newFooterHeight = this.footerWrapperRef ? this.footerWrapperRef.offsetHeight : 0;
if (headerContainerHeight !== newHeaderContainerHeight || headerWrapperHeight !== newHeaderWrapperHeight || tailHeight !== newTailHeight || pageHeight !== newPageHeight || footerHeight !== newFooterHeight) {
this.setState({
headerContainerHeight: newHeaderContainerHeight,
headerWrapperHeight: newHeaderWrapperHeight,
tailHeight: newTailHeight,
pageHeight: newPageHeight,
footerHeight: newFooterHeight
});
}
}
_getScrollContainer() {
return this.scrollableContainerRef.current;
}
_getMinimizedHeaderWrapperHeight() {
if (!this._hasHeader()) {
return 0;
}
return this._hasTail() ? parseInt(_PageSt.stVars.minimizedHeaderWrapperWithTailHeightPx, 10) : parseInt(_PageSt.stVars.minimizedHeaderWrapperHeightPx, 10);
}
_getMinimizationDiff() {
var {
headerWrapperHeight
} = this.state;
return headerWrapperHeight ? headerWrapperHeight - this._getMinimizedHeaderWrapperHeight() : null;
}
_handleScroll(e) {
var containerScrollTop = this._getScrollContainer().scrollTop;
var {
minimized
} = this.state;
var minimizationDiff = this._getMinimizationDiff();
var nextDisplayMiniHeader = minimizationDiff && containerScrollTop >= minimizationDiff;
if (minimized !== nextDisplayMiniHeader) {
this.setState({
minimized: nextDisplayMiniHeader
});
}
var {
scrollProps: {
onScrollChanged
}
} = this.props;
if (onScrollChanged) {
onScrollChanged(e);
}
}
_handleWidthResize() {}
_handleWindowResize() {
// TODO: Optimize : https://developer.mozilla.org/en-US/docs/Web/Events/resize
// Taken from here: https://github.com/kunokdev/react-window-size-listener/blob/d64c077fba4d4e0ce060464078c5fc19620528e6/src/index.js#L66
var windowHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
if (this.state.windowHeight !== windowHeight) {
// We are not using windowHeight directly, since we need to measure the `<Page/>`'s height,
// But we hold it in the state to avoid rendering when only window.width changes
this.setState({
windowHeight
});
}
}
_safeGetChildren(element) {
if (!element || !element.props || !element.props.children) {
return [];
}
return element.props.children;
}
_getPageDimensionsStyle() {
var {
maxWidth,
sidePadding
} = this.props;
// TODO: Simplify - maxWidth is always truthy (from defaultProp)
if (!maxWidth && !sidePadding && sidePadding !== 0) {
return null;
}
var styles = {};
if (maxWidth) {
styles.maxWidth = "".concat(maxWidth, "px");
}
if (sidePadding || sidePadding === 0) {
styles.paddingLeft = "".concat(sidePadding, "px");
styles.paddingRight = "".concat(sidePadding, "px");
}
return styles;
}
_hasBackgroundImage() {
return !!this.props.backgroundImageUrl;
}
_hasGradientClassName() {
return !!this.props.gradientClassName && !this.props.backgroundImageUrl;
}
_renderContentHorizontalLayout(props) {
var {
PageContent
} = this._getNamedChildren();
var contentFullScreen = PageContent && PageContent.props.fullScreen;
var {
className,
horizontalScroll,
style
} = props,
rest = (0, _objectWithoutProperties2.default)(props, _excluded);
var pageDimensionsStyle = contentFullScreen ? null : this._getPageDimensionsStyle();
return /*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({
className: (0, _PageSt.st)(_PageSt.classes.contentHorizontalLayout, {
contentFullWidth: contentFullScreen,
horizontalScroll
}, className),
style: _objectSpread(_objectSpread({}, pageDimensionsStyle), style)
}, rest, {
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 272,
columnNumber: 7
}
}), props.children);
}
_renderHeader() {
var {
minimized
} = this.state;
var {
PageHeader: PageHeaderChild
} = this._getNamedChildren();
var dataHook = 'page-header-wrapper';
return PageHeaderChild && /*#__PURE__*/_react.default.createElement("div", {
key: dataHook,
"data-hook": dataHook,
className: (0, _PageSt.st)(_PageSt.classes.headerWrapper, {
minimized
}),
ref: _ref2 => this.headerWrapperRef = _ref2,
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 296,
columnNumber: 9
}
}, /*#__PURE__*/_react.default.cloneElement(PageHeaderChild, {
minimized,
hasBackgroundImage: this._hasBackgroundImage()
}));
}
_renderHeaderContainer() {
var {
minimized
} = this.state;
// placeholder when header is minimized
var placeholder = /*#__PURE__*/_react.default.createElement("div", {
key: "placeholder",
style: {
height: "".concat(minimized ? this._getMinimizationDiff() : 0, "px")
},
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 318,
columnNumber: 7
}
});
/**
* HeaderContainer has position sticky. The `top` value is negative, in order to let
* the container scroll out of view before the minimization occurs.
*/
var top = minimized ? "-".concat(this._getMinimizationDiff(), "px") : 0;
return /*#__PURE__*/_react.default.createElement("div", {
"data-hook": "page-header-container",
className: (0, _PageSt.st)(_PageSt.classes.pageHeaderContainer, {
minimized,
hasTail: this._hasTail()
}),
style: {
[_PageSt.vars.minimizationTop]: top
},
ref: _ref3 => this.headerContainerRef = _ref3,
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 333,
columnNumber: 7
}
}, this._renderContentHorizontalLayout({
children: [placeholder, this._renderHeader(), this._renderTail()]
}));
}
_renderScrollableContainer() {
var {
scrollProps: {
onScrollAreaChanged
}
} = this.props;
return /*#__PURE__*/_react.default.createElement(_ScrollableContainer.default, {
className: (0, _PageSt.st)(_PageSt.classes.scrollableContainer, {
hasTail: this._hasTail()
}),
dataHook: "page-scrollable-content",
"data-class": "page-scrollable-content",
ref: this.scrollableContainerRef,
onScrollAreaChanged: onScrollAreaChanged,
onScrollChanged: this._handleScroll,
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 356,
columnNumber: 7
}
}, /*#__PURE__*/_react.default.createElement("div", {
"data-hook": "safari-12-13-sticky-fix",
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 366,
columnNumber: 9
}
}, this._renderScrollableBackground(), this._renderHeaderContainer(), this._renderContentContainer(), this._renderFixedFooter()));
}
_hasTail() {
return !!this._getNamedChildren().PageTail;
}
_hasHeader() {
return !!this._getNamedChildren().PageHeader;
}
_renderScrollableBackground() {
var {
headerContainerHeight,
tailHeight
} = this.state;
var backgroundHeight = "".concat(headerContainerHeight - tailHeight + (this._hasTail() ? 0 : parseInt(_PageSt.stVars.backgroundCoverContentPx, 10)), "px");
if (this._hasBackgroundImage()) {
return /*#__PURE__*/_react.default.createElement("div", {
className: _PageSt.classes.imageBackgroundContainer,
style: {
height: backgroundHeight
},
"data-hook": "page-background-image",
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 396,
columnNumber: 9
}
}, /*#__PURE__*/_react.default.createElement("div", {
className: _PageSt.classes.imageBackground,
style: {
backgroundImage: "url(".concat(this.props.backgroundImageUrl, ")")
},
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 401,
columnNumber: 11
}
}));
}
if (this._hasGradientClassName()) {
return /*#__PURE__*/_react.default.createElement("div", {
"data-hook": "page-gradient-class-name",
className: (0, _PageSt.st)(_PageSt.classes.gradientBackground, {}, this.props.gradientClassName),
style: {
height: backgroundHeight
},
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 411,
columnNumber: 9
}
});
}
}
_renderTail() {
var {
PageTail
} = this._getNamedChildren();
var dataHook = 'page-tail';
return PageTail && /*#__PURE__*/_react.default.createElement("div", {
"data-hook": dataHook,
key: dataHook,
className: _PageSt.classes.tail,
ref: r => this.pageHeaderTailRef = r,
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 430,
columnNumber: 9
}
}, PageTail);
}
_renderContentContainer() {
var {
footerHeight
} = this.state;
var {
children
} = this.props;
var childrenObject = getChildrenObject(children);
var {
PageContent,
PageFixedContent
} = childrenObject;
return /*#__PURE__*/_react.default.createElement(_PageContext.PageContext.Provider, {
value: {
stickyStyle: {
top: "".concat(this._getMinimizedHeaderWrapperHeight() + this.state.tailHeight, "px")
}
},
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 449,
columnNumber: 7
}
}, this._renderContentHorizontalLayout({
className: _PageSt.classes.contentContainer,
style: {
paddingBottom: footerHeight || '48px'
},
horizontalScroll: this.props.horizontalScroll,
children: /*#__PURE__*/_react.default.createElement("div", {
className: _PageSt.classes.contentFloating,
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 465,
columnNumber: 13
}
}, PageFixedContent && /*#__PURE__*/_react.default.createElement(_PageSticky.PageSticky, {
"data-hook": "page-fixed-content",
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 467,
columnNumber: 17
}
}, /*#__PURE__*/_react.default.cloneElement(PageFixedContent)), this._safeGetChildren(PageContent))
}));
}
render() {
var {
dataHook,
className,
minWidth,
zIndex,
height
} = this.props;
return /*#__PURE__*/_react.default.createElement("div", {
"data-hook": dataHook,
className: (0, _PageSt.st)(_PageSt.classes.root, {}, className),
style: {
zIndex,
height
},
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 508,
columnNumber: 7
}
}, /*#__PURE__*/_react.default.createElement("div", {
"data-hook": "page",
className: _PageSt.classes.page,
style: {
minWidth: minWidth + 2 * parseInt(_PageSt.stVars.pageSidePadding, 10)
},
ref: _ref4 => this.pageRef = _ref4,
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 513,
columnNumber: 9
}
}, this._renderScrollableContainer()));
}
/**
* Scrolls the page to a particular set of coordinates
* @param {ScrollToOptions} scrollTo { left: number, top: number, behavior: 'smooth' | 'auto' }
*/
scrollTo(scrollTo) {
var scrollContainer = this._getScrollContainer();
scrollContainer.scrollTo(scrollTo);
}
}
Page.defaultProps = {
minWidth: parseInt(_PageSt.stVars.mainContainerMinWidth, 10),
maxWidth: parseInt(_PageSt.stVars.mainContainerMaxWidth, 10),
scrollProps: {}
};
var FixedContent = props => props.children;
FixedContent.displayName = 'Page.FixedContent';
FixedContent.propTypes = {
children: _propTypes.default.element.isRequired
};
Page.displayName = 'Page';
Page.Header = _PageHeader.default;
Page.Section = _PageSection.default;
Page.Content = _Content.default;
Page.FixedContent = FixedContent; // TODO: deprecate, use Page.Sticky instead
Page.Tail = _Tail.default;
Page.FixedFooter = _FixedFooter.default;
Page.Sticky = _PageSticky.PageSticky;
Page.Footer = _PageFooter.default;
var allowedChildren = [Page.Header, Page.Section, Page.Content, Page.FixedContent, Page.Tail, Page.FixedFooter];
Page.propTypes = {
/** Applies a data-hook HTML attribute that can be used in the tests */
dataHook: _propTypes.default.string,
/** Provides a link to the background image source (URL). Image will be displayed at the top of a page, underneath the \<Page.Header/>. */
backgroundImageUrl: _propTypes.default.string,
/** Sets the maximum width of the page (paddings excluded) */
maxWidth: _propTypes.default.number,
/** Sets the minimum width of the page (paddings excluded) */
minWidth: _propTypes.default.number,
/** Enables page content to scroll horizontally when its width exceed maximum allowed width */
horizontalScroll: _propTypes.default.bool,
/** Sets the height of the page in pixels (px), viewport height (vh), etc. */
height: _propTypes.default.string,
/** Sets the side paddings of a page */
sidePadding: _propTypes.default.number,
/** Specifies a CSS class name to be appended to the component’s root element */
className: _propTypes.default.string,
/** Specifies a CSS class name that defines a gradient background for \<Page.Header/> */
gradientClassName: _propTypes.default.string,
/** Defines a reference called together with page scrollable content ref after page mount.
* <br/>
* **Note** - if you need this ref only for listening to scroll events on the scrollable content then use this prop instead:
* `scrollProps = {onScrollChanged/onScrollAreaChanged}` */
scrollableContentRef: _propTypes.default.func,
/** Pass properties related to the scrollable content of the page.
* <br/>
* **onScrollAreaChanged** - defines a handler function for scroll area changes.
* Function is triggered when the user scrolls to a different area of the scrollable content. See signature for possible areas:
* `function({area: {y: AreaY, x: AreaX}, target: HTMLElement}) => void`
* `AreaY`: top | middle | bottom | none
* `AreaX`: start | middle | end | none (not implemented yet)
* <br/>
* **onScrollAreaChanged** - defines a general handler for scroll changes with throttling (100ms):
* `function({target: HTMLElement}) => void`
* */
scrollProps: _propTypes.default.shape(_ScrollableContainerCommon.ScrollableContainerCommonProps),
/** Accepts compound components as child items:
* - `<Page.Header/>`
* - `<Page.Content/>`
* - `<Page.Tail/>`
* - `<Page.Section/>`
* - `<Page.Footer/>`
* */
children: _propTypes.default.arrayOf((children, key) => {
var child = children[key];
if (!child) {
return;
}
var allowedDisplayNames = allowedChildren.map(c => c.displayName);
var childDisplayName = child.type.displayName;
if (!allowedDisplayNames.includes(childDisplayName)) {
return new Error("Page: Invalid Prop children, unknown child ".concat(child.type));
}
}).isRequired,
/** Specifies the stack order (z-index) of a page */
zIndex: _propTypes.default.number
};
function getChildrenObject(children) {
return _react.default.Children.toArray(children).reduce((acc, child) => {
switch (child.type.displayName) {
case 'Page.Header':
{
acc.PageHeader = child;
break;
}
case 'Page.Section':
{
acc.Section = child;
break;
}
case 'Page.Content':
{
acc.PageContent = child;
break;
}
case 'Page.FixedContent':
{
acc.PageFixedContent = child;
break;
}
case 'Page.Tail':
{
acc.PageTail = child;
break;
}
case 'Page.FixedFooter':
{
acc.FixedFooter = child;
break;
}
default:
{
break;
}
}
return acc;
}, {});
}
var _default = exports.default = Page;
//# sourceMappingURL=Page.js.map