UNPKG

@wix/design-system

Version:

@wix/design-system

643 lines (635 loc) 23.9 kB
"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 = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _cssElementQueries = require("css-element-queries"); var _PageSt = require("./Page.st.css.js"); var _PageContext = require("./PageContext"); var _PageScrollContext = require("./PageScrollContext"); var _Header = _interopRequireDefault(require("./components/Header")); var _Section = _interopRequireDefault(require("./components/Section")); var _Footer = _interopRequireDefault(require("./components/Footer")); 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/57e038ea7326c1ec/packages/wix-design-system/dist/cjs/Page/Page.tsx"; function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); } 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"] */ var FixedContent = props => props.children; FixedContent.displayName = 'Page.FixedContent'; FixedContent.propTypes = { children: _propTypes.default.element.isRequired }; class Page extends _react.PureComponent { constructor(props) { super(props); this.scrollableContainerRef = void 0; this.headerWrapperRef = void 0; this.headerContainerRef = void 0; this.pageHeaderTailRef = void 0; this.pageRef = void 0; this.footerWrapperRef = void 0; this.pageScrollContextValue = void 0; this.contentResizeListener = void 0; this.timerId = void 0; this._renderFixedFooter = () => { var { children } = this.props; var childrenObject = getChildrenObject(children); var { FixedFooter: FixedFooterChild, PageContent } = childrenObject; var contentFullScreen = PageContent && PageContent.props.fullScreen; var pageDimensionsStyle = contentFullScreen ? undefined : 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: 587, columnNumber: 9 } }, /*#__PURE__*/_react.default.cloneElement(FixedFooterChild, {})); } return null; }; this.scrollableContainerRef = /*#__PURE__*/_react.default.createRef(); this.headerWrapperRef = null; this.headerContainerRef = null; this.pageHeaderTailRef = null; this.pageRef = null; this.footerWrapperRef = null; this.pageScrollContextValue = { scrollableContentRef: this.scrollableContainerRef }; 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() { var _this$_getScrollConta; this._calculateComponentsHeights(); var resizeElement = (_this$_getScrollConta = this._getScrollContainer()) == null ? void 0 : _this$_getScrollConta.childNodes[0]; this.contentResizeListener = new _cssElementQueries.ResizeSensor(resizeElement, 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() { this._calculateComponentsHeights(); } componentWillUnmount() { var _this$contentResizeLi; window.removeEventListener('resize', this._handleWindowResize); (_this$contentResizeLi = this.contentResizeListener) == null || _this$contentResizeLi.detach(this._handleWidthResize); 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 ? 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 _this$_getScrollConta2, _this$_getScrollConta3, _this$props$scrollPro; var containerScrollTop = (_this$_getScrollConta2 = (_this$_getScrollConta3 = this._getScrollContainer()) == null ? void 0 : _this$_getScrollConta3.scrollTop) !== null && _this$_getScrollConta2 !== void 0 ? _this$_getScrollConta2 : 0; var { minimized } = this.state; var minimizationDiff = this._getMinimizationDiff(); var nextDisplayMiniHeader = !!(minimizationDiff && containerScrollTop >= minimizationDiff); if (minimized !== nextDisplayMiniHeader) { this.setState({ minimized: nextDisplayMiniHeader }); } var onScrollChanged = (_this$props$scrollPro = this.props.scrollProps) == null ? void 0 : _this$props$scrollPro.onScrollChanged; 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 undefined; } 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: 365, 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: 389, 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: 411, 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: 426, columnNumber: 7 } }, this._renderContentHorizontalLayout({ children: [placeholder, this._renderHeader(), this._renderTail()] })); } _renderScrollableContainer() { var _this$props$scrollPro2; var onScrollAreaChanged = (_this$props$scrollPro2 = this.props.scrollProps) == null ? void 0 : _this$props$scrollPro2.onScrollAreaChanged; 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: 447, columnNumber: 7 } }, /*#__PURE__*/_react.default.createElement("div", { "data-hook": "safari-12-13-sticky-fix", __self: this, __source: { fileName: _jsxFileName, lineNumber: 457, 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: 487, columnNumber: 9 } }, /*#__PURE__*/_react.default.createElement("div", { className: _PageSt.classes.imageBackground, style: { backgroundImage: "url(".concat(this.props.backgroundImageUrl, ")") }, __self: this, __source: { fileName: _jsxFileName, lineNumber: 492, 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: 502, columnNumber: 9 } }); } return null; } _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: 523, 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") }, scrollableContentRef: this.scrollableContainerRef }, __self: this, __source: { fileName: _jsxFileName, lineNumber: 542, columnNumber: 7 } }, /*#__PURE__*/_react.default.createElement(_PageScrollContext.PageScrollContext.Provider, { value: this.pageScrollContextValue, __self: this, __source: { fileName: _jsxFileName, lineNumber: 552, columnNumber: 9 } }, 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: 560, columnNumber: 15 } }, PageFixedContent && /*#__PURE__*/_react.default.createElement(_PageSticky.PageSticky, { "data-hook": "page-fixed-content", __self: this, __source: { fileName: _jsxFileName, lineNumber: 562, columnNumber: 19 } }, /*#__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: 606, columnNumber: 7 } }, /*#__PURE__*/_react.default.createElement("div", { "data-hook": "page", className: _PageSt.classes.page, style: { minWidth: "calc(".concat(minWidth, "px + 2 * ").concat(_PageSt.stVars.pageSidePadding, ")") }, ref: _ref4 => this.pageRef = _ref4, __self: this, __source: { fileName: _jsxFileName, lineNumber: 611, 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 == null || scrollContainer.scrollTo(scrollTo); } } Page.displayName = 'Page'; Page.defaultProps = { minWidth: parseInt(_PageSt.stVars.mainContainerMinWidth, 10), maxWidth: parseInt(_PageSt.stVars.mainContainerMaxWidth, 10), scrollProps: {} }; Page.propTypes = { dataHook: _propTypes.default.string, backgroundImageUrl: _propTypes.default.string, maxWidth: _propTypes.default.number, minWidth: _propTypes.default.number, horizontalScroll: _propTypes.default.bool, height: _propTypes.default.string, sidePadding: _propTypes.default.number, className: _propTypes.default.string, gradientClassName: _propTypes.default.string, scrollableContentRef: _propTypes.default.func, scrollProps: _propTypes.default.shape(_ScrollableContainerCommon.ScrollableContainerCommonProps), children: _propTypes.default.node, zIndex: _propTypes.default.number }; Page.Header = _Header.default; Page.Section = _Section.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 = _Footer.default; function getChildrenObject(children) { return _react.default.Children.toArray(children).reduce((acc, child) => { if (! /*#__PURE__*/_react.default.isValidElement(child)) { return acc; } var displayName = typeof child.type === 'string' || typeof child.type === 'symbol' ? undefined : child.type.displayName; switch (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