From 2ae803212f64e18a7b35441864642f7bec151b9a Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Thu, 5 Apr 2018 14:33:04 -0700 Subject: [PATCH 01/43] Fix sticky top behavior. Make inner div of ScrollablePane scrollable instead of root. Need to fix sticky bottom behavior still. --- .../ScrollablePane/ScrollablePane.base.tsx | 156 ++++++++-------- .../ScrollablePane/ScrollablePane.styles.ts | 22 ++- .../ScrollablePane/ScrollablePane.types.ts | 4 + .../ScrollablePane/ScrollablePanePage.tsx | 4 +- .../examples/ScrollablePane.Example.scss | 4 +- .../src/components/Sticky/Sticky.tsx | 169 +++++++++++------- 6 files changed, 216 insertions(+), 143 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index 8ac7bcd7eb5780..e5430688497a32 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -23,10 +23,15 @@ export interface IScrollablePaneContext { scrollablePane: PropTypes.Requireable; } +export interface IScrollablePaneState { + stickyTopHeight: number; + stickyBottomHeight: number; +} + const getClassNames = classNamesFunction(); @customizable('ScrollablePane', ['theme']) -export class ScrollablePaneBase extends BaseComponent implements IScrollablePane { +export class ScrollablePaneBase extends BaseComponent implements IScrollablePane { public static childContextTypes: React.ValidationMap = { scrollablePane: PropTypes.object }; @@ -34,7 +39,9 @@ export class ScrollablePaneBase extends BaseComponent private _root = createRef(); private _stickyAboveRef = createRef(); private _stickyBelowRef = createRef(); + private _contentContainer = createRef(); private _subscribers: Set; + private _stickies: Set; private _stickyAbove: Set; private _stickyBelow: Set; @@ -43,6 +50,12 @@ export class ScrollablePaneBase extends BaseComponent this._subscribers = new Set(); this._stickyAbove = new Set(); this._stickyBelow = new Set(); + this._stickies = new Set(); + + this.state = { + stickyTopHeight: 0, + stickyBottomHeight: 0 + }; } public get root(): HTMLDivElement | null { @@ -60,19 +73,17 @@ export class ScrollablePaneBase extends BaseComponent public getChildContext() { return { scrollablePane: { - subscribe: this.subscribe, + subscribe: this.subscribe2, unsubscribe: this.unsubscribe, - addStickyHeader: this.addStickyHeader, - removeStickyHeader: this.removeStickyHeader, - addStickyFooter: this.addStickyFooter, - removeStickyFooter: this.removeStickyFooter, + addSticky: this.addSticky, + updateStickyAboveHeight: this.updateStickyAboveHeight, notifySubscribers: this.notifySubscribers } }; } public componentDidMount() { - this._events.on(this._root.value, 'scroll', this.notifySubscribers); + this._events.on(this._contentContainer.value, 'scroll', this.notifySubscribers); this._events.on(window, 'resize', this._onWindowResize); } @@ -97,15 +108,37 @@ export class ScrollablePaneBase extends BaseComponent } ); + let stickyTopStyle = {}; + stickyTopStyle = { + height: this.state.stickyTopHeight + 'px' + }; + + + + let stickyBottomStyle = {}; + stickyBottomStyle = { + height: this.state.stickyBottomHeight + 'px' + }; + + + return (
-
-
-
+
+
+
{ this.props.children }
@@ -116,7 +149,11 @@ export class ScrollablePaneBase extends BaseComponent this._onWindowResize(); } - public subscribe = (handler: (headerBound: ClientRect, footerBound: ClientRect) => void): void => { + // public subscribe = (handler: (headerBound: ClientRect, footerBound: ClientRect) => void): void => { + // this._subscribers.add(handler); + // } + + public subscribe2 = (handler: (container: HTMLElement) => void): void => { this._subscribers.add(handler); } @@ -124,34 +161,45 @@ export class ScrollablePaneBase extends BaseComponent this._subscribers.delete(handler); } - public addStickyHeader = (sticky: Sticky): void => { - this._addSticky(sticky, this._stickyAbove, () => { - if (this._stickyAboveRef.value) { - this._stickyAboveRef.value.appendChild(sticky.content); - } - }); + public addSticky = (sticky: Sticky): void => { + console.log(sticky); + if (this.stickyAbove && sticky.stickyContentTop.value) { + this.stickyAbove.appendChild(sticky.stickyContentTop.value); + } + if (this.stickyBelow && sticky.stickyContentBottom.value) { + this.stickyBelow.appendChild(sticky.stickyContentBottom.value); + } + this._stickies.add(sticky); } - public addStickyFooter = (sticky: Sticky): void => { - this._addSticky(sticky, this._stickyBelow, () => { - if (this._stickyBelowRef.value) { - this._stickyBelowRef.value.insertBefore(sticky.content, this._stickyBelowRef.value.firstChild); + public updateStickyAboveHeight = (): void => { + const stickyItems = this._stickies; + + let stickyTopHeight: number = 0; + let stickyBottomHeight: number = 0; + + stickyItems.forEach((sticky: Sticky) => { + if (sticky.state.isStickyTop && sticky.stickyContentTop && sticky.stickyContentTop.value) { + stickyTopHeight += sticky.stickyContentTop.value.clientHeight; + } + if (sticky.state.isStickyBottom && sticky.stickyContentBottom && sticky.stickyContentBottom.value) { + stickyTopHeight += sticky.stickyContentBottom.value.clientHeight; } }); - } - public removeStickyHeader = (sticky: Sticky): void => { - this._removeSticky(sticky, this._stickyAbove, this._stickyAboveRef.value); - } - public removeStickyFooter = (sticky: Sticky): void => { - this._removeSticky(sticky, this._stickyBelow, this._stickyBelowRef.value); + this.setState({ + stickyTopHeight: stickyTopHeight, + stickyBottomHeight: stickyBottomHeight + }); } public notifySubscribers = (sort?: boolean): void => { this._subscribers.forEach((handle) => { - if (this._stickyAboveRef.value && this._stickyBelowRef.value) { - handle(this._stickyAboveRef.value.getBoundingClientRect(), this._stickyBelowRef.value.getBoundingClientRect()); + // if (this._stickyAboveRef.value && this._stickyBelowRef.value) { + if (this._contentContainer) { + // handle(this._stickyAboveRef.value.getBoundingClientRect(), this._stickyBelowRef.value.getBoundingClientRect()); + handle(this._contentContainer.value); } }); if (this._stickyAbove.size > 1) { @@ -170,47 +218,13 @@ export class ScrollablePaneBase extends BaseComponent return 0; } - private _addSticky(sticky: Sticky, stickyList: Set, addStickyToContainer: () => void) { - if (!stickyList.has(sticky)) { - stickyList.add(sticky); - addStickyToContainer(); - sticky.content.addEventListener('transitionend', - this._setPlaceholderHeights.bind(null, stickyList), - false); - if (sticky.props.stickyClassName) { - this._async.setTimeout(() => { - if (sticky.props.stickyClassName) { - sticky.content.children[0].classList.add(sticky.props.stickyClassName); - } - }, 1); - } - this._setPlaceholderHeights(stickyList); - } - } - - private _removeSticky(sticky: Sticky, stickyList: Set, container: HTMLElement | null) { - if (container && stickyList.has(sticky)) { - sticky.content.removeEventListener('transitionend', - this._setPlaceholderHeights.bind(null, stickyList, container)); - stickyList.delete(sticky); - } - } - - private _onWindowResize() { + private _onWindowResize = (): void => { this._async.setTimeout(() => { this.notifySubscribers(); - this._setPlaceholderHeights(this._stickyAbove); - this._setPlaceholderHeights(this._stickyBelow); }, 5); } - private _setPlaceholderHeights = (stickies: Set): void => { - stickies.forEach((sticky, idx) => { - sticky.setPlaceholderHeight(sticky.content.clientHeight); - }); - } - - private _sortStickies(stickyList: Set, container: HTMLElement | null): void { + private _sortStickies = (stickyList: Set, container: HTMLElement | null): void => { // No sorting needed if there is no container if (!container) { return; @@ -225,11 +239,11 @@ export class ScrollablePaneBase extends BaseComponent // Get number of elements that is already in order. let elementsInOrder = 0; while (elementsInOrder < container.children.length && elementsInOrder < stickyArr.length) { - if (container.children[elementsInOrder] === stickyArr[elementsInOrder].content) { - ++elementsInOrder; - } else { - break; - } + // if (container.children[elementsInOrder] === stickyArr[elementsInOrder].content) { + // ++elementsInOrder; + // } else { + // break; + // } } // Remove elements that is not in order if exist. for (let i = container.children.length - 1; i >= elementsInOrder; --i) { @@ -237,7 +251,7 @@ export class ScrollablePaneBase extends BaseComponent } // Append further elements if needed. for (let i = elementsInOrder; i < stickyArr.length; ++i) { - container.appendChild(stickyArr[i].content); + // container.appendChild(stickyArr[i].content); } } diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts index b89f518d1728c5..2ccba0c949dca1 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts @@ -13,19 +13,33 @@ export const getStyles = ( position: 'absolute', pointerEvents: 'auto', width: '100%', - zIndex: 1 + zIndex: 1, + background: '#ffffff' }; + const maxHeightStyles: IStyle = { + height: 'inherit', + maxHeight: 'inherit' + } + return ({ root: [ 'ms-ScrollablePane', + { + WebkitOverflowScrolling: 'touch', + position: 'relative' + }, + maxHeightStyles, + className + ], + contentContainer: [ + 'ms-ScrollablePane--contentContainer', { overflowY: 'auto', - maxHeight: 'inherit', - height: 'inherit', + position: 'relative', WebkitOverflowScrolling: 'touch' }, - className + maxHeightStyles ], stickyAbove: [ { diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.types.ts b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.types.ts index 41d1eb7a20d76f..716e3a96ef995c 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.types.ts +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.types.ts @@ -68,4 +68,8 @@ export interface IScrollablePaneStyles { * Style set for the stickyAbove element. */ stickyBelow: IStyle; + /** + * Style set for the contentContainer element. + */ + contentContainer: IStyle; } diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx index 86abb63498a324..b8504b1e069c1d 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx @@ -25,9 +25,9 @@ export class ScrollablePanePage extends React.Component - + {/* - + */}
} allowNativeProps={ true } diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Example.scss b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Example.scss index 5a9603237c42a4..267314f2e308cd 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Example.scss +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Example.scss @@ -3,7 +3,6 @@ :global { .scrollablePaneDefaultExample { max-width: 400px; - max-height: inherit; border: 1px solid $ms-color-neutralLight; } @@ -21,7 +20,8 @@ -o-transform: translateZ(0); transform: translateZ(0); will-change: font-size; - box-shadow: 0 0 5px -1px $ms-color-neutralDark; + border-top: 1px solid black; + border-bottom: 1px solid black; } .largeFont { diff --git a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx index 6b08abea6d4ea6..3df91a9b0560fa 100644 --- a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx +++ b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx @@ -30,16 +30,16 @@ export class Sticky extends BaseComponent { scrollablePane: { subscribe: (handler: Function) => void; unsubscribe: (handler: Function) => void; - addStickyHeader: (sticky: Sticky) => void; - removeStickyHeader: (sticky: Sticky) => void; - addStickyFooter: (sticky: Sticky) => void; - removeStickyFooter: (sticky: Sticky) => void; + addSticky: (sticky: Sticky) => void; + updateStickyAboveHeight: () => void; notifySubscribers: (sort?: boolean) => void; } }; - public content: HTMLElement; public root = createRef(); + public stickyContentTop = createRef(); + public stickyContentBottom = createRef(); + public nonStickyContent = createRef(); constructor(props: IStickyProps) { super(props); @@ -54,29 +54,25 @@ export class Sticky extends BaseComponent { throw new TypeError('Expected Sticky to be mounted within ScrollablePane'); } const { scrollablePane } = this.context; - scrollablePane.subscribe(this._onScrollEvent); - this.content = document.createElement('div'); - this.content.style.background = this.props.stickyBackgroundColor || this._getBackground(); - ReactDOM.render(
{ this.props.children }
, this.content); + scrollablePane.subscribe(this._onScrollEvent2); + scrollablePane.addSticky(this); + console.log('distance from top', this._getStickyDistanceFromTop()); + // console.log(this, this.root.value); if (this.root.value) { - this.root.value.appendChild(this.content); + // console.log(' this root value', this.root.value, this.root.value.offsetParent, this.root.value.offsetTop); } + // this.content = document.createElement('div'); + // this.content.style.background = this.props.stickyBackgroundColor || this._getBackground(); + // ReactDOM.render(
{ this.props.children }
, this.content); + // if (this.root.value) { + // this.root.value.appendChild(this.content); + // } this.context.scrollablePane.notifySubscribers(true); } public componentWillUnmount(): void { const { isStickyTop, isStickyBottom } = this.state; const { scrollablePane } = this.context; - if (isStickyTop) { - this._resetSticky(() => { - scrollablePane.removeStickyHeader(this); - }); - } - if (isStickyBottom) { - this._resetSticky(() => { - scrollablePane.removeStickyFooter(this); - }); - } scrollablePane.unsubscribe(this._onScrollEvent); } @@ -84,29 +80,6 @@ export class Sticky extends BaseComponent { const { isStickyTop, isStickyBottom } = this.state; const { scrollablePane } = this.context; - if (this.props.children !== prevProps.children) { - ReactDOM.render(
{ this.props.children }
, this.content); - } - - if (isStickyTop && !prevState.isStickyTop) { - this._setSticky(() => { - scrollablePane.addStickyHeader(this); - }); - } else if (!isStickyTop && prevState.isStickyTop) { - this._resetSticky(() => { - scrollablePane.removeStickyHeader(this); - }); - } - - if (isStickyBottom && !prevState.isStickyBottom) { - this._setSticky(() => { - scrollablePane.addStickyFooter(this); - }); - } else if (!isStickyBottom && prevState.isStickyBottom) { - this._resetSticky(() => { - scrollablePane.removeStickyFooter(this); - }); - } } public shouldComponentUpdate(nextProps: IStickyProps, nextState: IStickyState): boolean { @@ -127,13 +100,101 @@ export class Sticky extends BaseComponent { const { isStickyTop, isStickyBottom, placeholderHeight } = this.state; const isSticky = isStickyTop || isStickyBottom; + let isStickyStyleTop = {}; + if (isStickyTop) { + isStickyStyleTop = { + opacity: '1' + }; + } else { + isStickyStyleTop = { + opacity: '0' + }; + } + + let isStickyStyleBottom = {}; + if (isStickyBottom) { + isStickyStyleBottom = { + opacity: '1' + }; + } else { + isStickyStyleBottom = { + opacity: '0' + }; + } + return (
-
+ {/*
*/ } +
+ { this.props.children } +
+
+ { this.props.children } +
+
+ { this.props.children } +
); } + private _onScrollEvent2 = (container: HTMLElement): void => { + const { scrollablePane } = this.context; + + if (container && this.root.value) { + let distanceFromTop = this._getNonStickyDistanceFromTop(container); + let stickyDistanceFromTop = this._getStickyDistanceFromTop(); + let distanceToStick = distanceFromTop - stickyDistanceFromTop; + if (container.scrollTop <= distanceToStick) { + this.setState({ + isStickyTop: false + }); + console.log('distance from top', this.root.value, distanceFromTop, stickyDistanceFromTop, container.scrollTop); + } else { + this.setState({ + isStickyTop: true + }); + console.log('element is sticky', this.root.value); + } + + scrollablePane.updateStickyAboveHeight(); + } + } + + private _getStickyDistanceFromTop = (): number => { + let distance: number = 0; + if (this.stickyContentTop.value) { + distance = this.stickyContentTop.value.offsetTop; + } + + return distance; + } + + private _getNonStickyDistanceFromTop = (container: HTMLElement): number => { + let distance: number = 0; + let currElem = this.root.value; + + if (currElem) { + if (currElem.offsetParent === container) { + return currElem.offsetTop; + } + + if (currElem.offsetParent) { + do { + distance += currElem.offsetTop; + if (currElem) { + currElem = currElem.offsetParent as HTMLDivElement; + } + } while (currElem && currElem.offsetParent !== container) + } + } + return distance; + } + private _onScrollEvent = (headerBound: ClientRect, footerBound: ClientRect): void => { if (!this.root.value) { return; @@ -151,26 +212,6 @@ export class Sticky extends BaseComponent { }); } - private _setSticky(callback: () => void): void { - if (this.content.parentElement) { - this.content.parentElement.removeChild(this.content); - } - callback(); - } - - private _resetSticky(callback: () => void): void { - if (this.root.value) { - this.root.value.appendChild(this.content); - } - - setTimeout(() => { - if (this.props.stickyClassName) { - this.content.children[0].classList.remove(this.props.stickyClassName); - } - }, 1); - callback(); - } - // Gets background of nearest parent element that has a declared background-color attribute private _getBackground(): string | null { if (!this.root.value) { From 25349024c889140e6ad90e76497d29226cde986f Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Thu, 5 Apr 2018 18:08:45 -0700 Subject: [PATCH 02/43] Fix sticky footer behavior --- .../ScrollablePane/ScrollablePane.base.tsx | 102 +++++------------- .../ScrollablePane/ScrollablePane.styles.ts | 9 +- .../ScrollablePane/ScrollablePane.types.ts | 4 + .../ScrollablePane/ScrollablePanePage.tsx | 1 + .../ScrollablePane.Default.Example.tsx | 2 +- .../src/components/Sticky/Sticky.tsx | 74 ++++++------- 6 files changed, 76 insertions(+), 116 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index e5430688497a32..a333596154ebf0 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -38,6 +38,7 @@ export class ScrollablePaneBase extends BaseComponent(); private _stickyAboveRef = createRef(); + private _stickyBelowContainerRef = createRef(); private _stickyBelowRef = createRef(); private _contentContainer = createRef(); private _subscribers: Set; @@ -66,6 +67,10 @@ export class ScrollablePaneBase extends BaseComponent -
-
-
+
+
+
{ this.props.children } @@ -149,30 +159,25 @@ export class ScrollablePaneBase extends BaseComponent void): void => { - // this._subscribers.add(handler); - // } - - public subscribe2 = (handler: (container: HTMLElement) => void): void => { + public subscribe = (handler: Function): void => { this._subscribers.add(handler); } - public unsubscribe = (handler: (headerBound: ClientRect, footerBound: ClientRect) => void): void => { + public unsubscribe = (handler: Function): void => { this._subscribers.delete(handler); } public addSticky = (sticky: Sticky): void => { - console.log(sticky); + this._stickies.add(sticky); if (this.stickyAbove && sticky.stickyContentTop.value) { this.stickyAbove.appendChild(sticky.stickyContentTop.value); } if (this.stickyBelow && sticky.stickyContentBottom.value) { this.stickyBelow.appendChild(sticky.stickyContentBottom.value); } - this._stickies.add(sticky); } - public updateStickyAboveHeight = (): void => { + public updateStickyRefHeights = (): void => { const stickyItems = this._stickies; let stickyTopHeight: number = 0; @@ -183,11 +188,10 @@ export class ScrollablePaneBase extends BaseComponent { this._subscribers.forEach((handle) => { - // if (this._stickyAboveRef.value && this._stickyBelowRef.value) { - if (this._contentContainer) { - // handle(this._stickyAboveRef.value.getBoundingClientRect(), this._stickyBelowRef.value.getBoundingClientRect()); - handle(this._contentContainer.value); + if (this._contentContainer && this.stickyBelowContainer) { + handle(this._contentContainer.value, this.stickyBelowContainer, this.stickyBelow); } }); - if (this._stickyAbove.size > 1) { - this._sortStickies(this._stickyAbove, this._stickyAboveRef.value); - } - if (this._stickyBelow.size > 1) { - this._sortStickies(this._stickyBelow, this._stickyBelowRef.value); - } } public getScrollPosition = (): number => { @@ -223,46 +219,4 @@ export class ScrollablePaneBase extends BaseComponent, container: HTMLElement | null): void => { - // No sorting needed if there is no container - if (!container) { - return; - } - - let stickyArr = Array.from(stickyList); - stickyArr = stickyArr.sort((a, b) => { - const aOffset = this._calculateOffsetParent(a.root.value); - const bOffset = this._calculateOffsetParent(b.root.value); - return aOffset - bOffset; - }); - // Get number of elements that is already in order. - let elementsInOrder = 0; - while (elementsInOrder < container.children.length && elementsInOrder < stickyArr.length) { - // if (container.children[elementsInOrder] === stickyArr[elementsInOrder].content) { - // ++elementsInOrder; - // } else { - // break; - // } - } - // Remove elements that is not in order if exist. - for (let i = container.children.length - 1; i >= elementsInOrder; --i) { - container.removeChild(container.children[i]); - } - // Append further elements if needed. - for (let i = elementsInOrder; i < stickyArr.length; ++i) { - // container.appendChild(stickyArr[i].content); - } - } - - private _calculateOffsetParent(ele: HTMLElement | null): number { - let offset = 0; - while (ele && this._root.value && ele.offsetParent !== this._root.value.offsetParent) { - offset += ele.offsetTop; - if (ele.parentElement) { - ele = ele.parentElement; - } - } - return offset; - } -} +} \ No newline at end of file diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts index 2ccba0c949dca1..2d091323b6e4a1 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts @@ -14,7 +14,8 @@ export const getStyles = ( pointerEvents: 'auto', width: '100%', zIndex: 1, - background: '#ffffff' + background: '#ffffff', + overflow: 'hidden' }; const maxHeightStyles: IStyle = { @@ -62,6 +63,12 @@ export const getStyles = ( } }, AboveAndBelowStyles + ], + stickyBelowItems: [ + { + bottom: 0 + }, + AboveAndBelowStyles ] }); }; diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.types.ts b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.types.ts index 716e3a96ef995c..46cc05f00b502e 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.types.ts +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.types.ts @@ -68,6 +68,10 @@ export interface IScrollablePaneStyles { * Style set for the stickyAbove element. */ stickyBelow: IStyle; + /** + * Style set for the stickyBelowItems element. + */ + stickyBelowItems: IStyle; /** * Style set for the contentContainer element. */ diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx index b8504b1e069c1d..042b682c779894 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx @@ -58,6 +58,7 @@ export class ScrollablePanePage extends React.ComponentEnsure that a parent component has a CSS height, or max-height attribute set (and any intermediary containers have an inherit, or explicit height/max-height set).
  • Use Sticky component on block level elements
  • Sticky component are ideally section headers and/or footers
  • +
  • Ensure that the total height of Sticky components do not exceed the height of the ScrollablePane
  • } diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx index f2ca794437da9a..05030729cf0e1e 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx @@ -8,7 +8,7 @@ export class ScrollablePaneDefaultExample extends React.Component { public render() { const contentAreas: JSX.Element[] = []; - for (let i = 0; i < 4; i++) { + for (let i = 0; i < 5; i++) { contentAreas.push(this._createContentArea(i)); } diff --git a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx index 3df91a9b0560fa..46d2d1d1d6fbfd 100644 --- a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx +++ b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx @@ -31,7 +31,7 @@ export class Sticky extends BaseComponent { subscribe: (handler: Function) => void; unsubscribe: (handler: Function) => void; addSticky: (sticky: Sticky) => void; - updateStickyAboveHeight: () => void; + updateStickyRefHeights: () => void; notifySubscribers: (sort?: boolean) => void; } }; @@ -56,24 +56,15 @@ export class Sticky extends BaseComponent { const { scrollablePane } = this.context; scrollablePane.subscribe(this._onScrollEvent2); scrollablePane.addSticky(this); - console.log('distance from top', this._getStickyDistanceFromTop()); - // console.log(this, this.root.value); - if (this.root.value) { - // console.log(' this root value', this.root.value, this.root.value.offsetParent, this.root.value.offsetTop); - } - // this.content = document.createElement('div'); - // this.content.style.background = this.props.stickyBackgroundColor || this._getBackground(); - // ReactDOM.render(
    { this.props.children }
    , this.content); - // if (this.root.value) { - // this.root.value.appendChild(this.content); - // } + + this.context.scrollablePane.notifySubscribers(true); } public componentWillUnmount(): void { const { isStickyTop, isStickyBottom } = this.state; const { scrollablePane } = this.context; - scrollablePane.unsubscribe(this._onScrollEvent); + scrollablePane.unsubscribe(this._onScrollEvent2); } public componentDidUpdate(prevProps: IStickyProps, prevState: IStickyState): void { @@ -124,7 +115,6 @@ export class Sticky extends BaseComponent { return (
    - {/*
    */ }
    @@ -142,26 +132,38 @@ export class Sticky extends BaseComponent { ); } - private _onScrollEvent2 = (container: HTMLElement): void => { + private _onScrollEvent2 = (container: HTMLElement, bottomStickyContainer: HTMLElement, footerStickyVisible: HTMLElement): void => { const { scrollablePane } = this.context; - if (container && this.root.value) { - let distanceFromTop = this._getNonStickyDistanceFromTop(container); - let stickyDistanceFromTop = this._getStickyDistanceFromTop(); - let distanceToStick = distanceFromTop - stickyDistanceFromTop; - if (container.scrollTop <= distanceToStick) { + if (container && this.root.value && this.nonStickyContent.value && this.stickyContentBottom.value) { + const distanceFromTop = this._getNonStickyDistanceFromTop(container); + + const stickyDistanceFromTop = this._getStickyDistanceFromTop(); + let distanceToStickTop = distanceFromTop - stickyDistanceFromTop; + if (container.scrollTop <= distanceToStickTop) { this.setState({ isStickyTop: false }); - console.log('distance from top', this.root.value, distanceFromTop, stickyDistanceFromTop, container.scrollTop); } else { this.setState({ isStickyTop: true }); - console.log('element is sticky', this.root.value); } - scrollablePane.updateStickyAboveHeight(); + // Can sticky bottom if the scrollablePane height is smaller than the sticky's distance from the top of the pane + if (container.clientHeight <= distanceFromTop) { + if (distanceFromTop - container.scrollTop > this._getStickyDistanceFromTopForFooter(container, footerStickyVisible)) { + this.setState({ + isStickyBottom: true + }); + } else { + this.setState({ + isStickyBottom: false + }); + } + } + + scrollablePane.updateStickyRefHeights(); } } @@ -174,6 +176,15 @@ export class Sticky extends BaseComponent { return distance; } + private _getStickyDistanceFromTopForFooter = (container: HTMLElement, footerStickyVisibleContainer: HTMLElement): number => { + let distance: number = 0; + if (this.stickyContentBottom.value) { + distance = container.clientHeight - footerStickyVisibleContainer.offsetHeight + this.stickyContentBottom.value.offsetTop; + } + + return distance; + } + private _getNonStickyDistanceFromTop = (container: HTMLElement): number => { let distance: number = 0; let currElem = this.root.value; @@ -195,23 +206,6 @@ export class Sticky extends BaseComponent { return distance; } - private _onScrollEvent = (headerBound: ClientRect, footerBound: ClientRect): void => { - if (!this.root.value) { - return; - } - - const { top, bottom } = this.root.value.getBoundingClientRect(); - const { isStickyTop, isStickyBottom } = this.state; - const { stickyPosition } = this.props; - const canStickyHeader = stickyPosition === StickyPositionType.Both || stickyPosition === StickyPositionType.Header; - const canStickyFooter = stickyPosition === StickyPositionType.Both || stickyPosition === StickyPositionType.Footer; - - this.setState({ - isStickyTop: canStickyHeader && ((top <= headerBound.bottom) || (isStickyTop && bottom < headerBound.bottom)), - isStickyBottom: canStickyFooter && ((bottom >= footerBound.top) || (isStickyBottom && top > footerBound.top)) - }); - } - // Gets background of nearest parent element that has a declared background-color attribute private _getBackground(): string | null { if (!this.root.value) { From 351b5094152826f81fb006f883a0e627a3b13f9d Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Thu, 5 Apr 2018 19:19:42 -0700 Subject: [PATCH 03/43] Remove unused state placeholderHeight. clean up onScrollEvent to only setState once. Need to fix DetailsList behavior --- .../ScrollablePane/ScrollablePanePage.tsx | 4 +- .../ScrollablePane.Default.Example.tsx | 1 + .../ScrollablePane.DetailsList.Example.tsx | 1 + .../src/components/Sticky/Sticky.tsx | 73 ++++++++----------- 4 files changed, 35 insertions(+), 44 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx index 042b682c779894..e62ce3f1b8e6b0 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx @@ -25,9 +25,9 @@ export class ScrollablePanePage extends React.Component - {/* + - */} +
    } allowNativeProps={ true } diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx index 05030729cf0e1e..c86fe69645ffa0 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx @@ -14,6 +14,7 @@ export class ScrollablePaneDefaultExample extends React.Component { return ( + testing testing
    { contentAreas.map((ele) => { return ele; }) } diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx index d03049bf316b0d..a4cb76034348b3 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx @@ -86,6 +86,7 @@ export class ScrollablePaneDetailsListExample extends React.Component<{}, { return ( + hello world
    { selectionDetails } { throw new TypeError('Expected Sticky to be mounted within ScrollablePane'); } const { scrollablePane } = this.context; - scrollablePane.subscribe(this._onScrollEvent2); + scrollablePane.subscribe(this._onScrollEvent); scrollablePane.addSticky(this); @@ -64,104 +63,94 @@ export class Sticky extends BaseComponent { public componentWillUnmount(): void { const { isStickyTop, isStickyBottom } = this.state; const { scrollablePane } = this.context; - scrollablePane.unsubscribe(this._onScrollEvent2); + scrollablePane.unsubscribe(this._onScrollEvent); } public componentDidUpdate(prevProps: IStickyProps, prevState: IStickyState): void { const { isStickyTop, isStickyBottom } = this.state; const { scrollablePane } = this.context; - } public shouldComponentUpdate(nextProps: IStickyProps, nextState: IStickyState): boolean { - const { isStickyTop, isStickyBottom, placeholderHeight } = this.state; + const { isStickyTop, isStickyBottom } = this.state; return isStickyTop !== nextState.isStickyTop || isStickyBottom !== nextState.isStickyBottom || - placeholderHeight !== nextState.placeholderHeight || this.props.children !== nextProps.children; } - public setPlaceholderHeight(height: number): void { - this.setState({ - placeholderHeight: height - }); - } - public render(): JSX.Element { - const { isStickyTop, isStickyBottom, placeholderHeight } = this.state; - const isSticky = isStickyTop || isStickyBottom; + const { isStickyTop, isStickyBottom } = this.state; let isStickyStyleTop = {}; if (isStickyTop) { isStickyStyleTop = { - opacity: '1' + opacity: '1', + backgroundColor: this.props.stickyBackgroundColor }; } else { isStickyStyleTop = { - opacity: '0' + opacity: '0', + backgroundColor: this.props.stickyBackgroundColor }; } let isStickyStyleBottom = {}; if (isStickyBottom) { isStickyStyleBottom = { - opacity: '1' + opacity: '1', + backgroundColor: this.props.stickyBackgroundColor }; } else { isStickyStyleBottom = { - opacity: '0' + opacity: '0', + backgroundColor: this.props.stickyBackgroundColor }; } return (
    -
    { this.props.children }
    -
    { this.props.children }
    -
    +
    { this.props.children }
    ); } - private _onScrollEvent2 = (container: HTMLElement, bottomStickyContainer: HTMLElement, footerStickyVisible: HTMLElement): void => { + private _onScrollEvent = (container: HTMLElement, bottomStickyContainer: HTMLElement, footerStickyVisible: HTMLElement): void => { const { scrollablePane } = this.context; if (container && this.root.value && this.nonStickyContent.value && this.stickyContentBottom.value) { const distanceFromTop = this._getNonStickyDistanceFromTop(container); - const stickyDistanceFromTop = this._getStickyDistanceFromTop(); - let distanceToStickTop = distanceFromTop - stickyDistanceFromTop; - if (container.scrollTop <= distanceToStickTop) { - this.setState({ - isStickyTop: false - }); - } else { - this.setState({ - isStickyTop: true - }); - } + const distanceToStickTop = distanceFromTop - stickyDistanceFromTop; + + const isStickyTop = distanceToStickTop <= container.scrollTop; + let isStickyBottom: boolean = false; // Can sticky bottom if the scrollablePane height is smaller than the sticky's distance from the top of the pane if (container.clientHeight <= distanceFromTop) { - if (distanceFromTop - container.scrollTop > this._getStickyDistanceFromTopForFooter(container, footerStickyVisible)) { - this.setState({ - isStickyBottom: true - }); - } else { - this.setState({ - isStickyBottom: false - }); - } + isStickyBottom = distanceFromTop - container.scrollTop > this._getStickyDistanceFromTopForFooter(container, footerStickyVisible); } + this.setState({ + isStickyTop: isStickyTop, + isStickyBottom: isStickyBottom + }); scrollablePane.updateStickyRefHeights(); } From d7befcebb4dd42737e7b4a418d5684c0df4e5dce Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Thu, 5 Apr 2018 19:42:26 -0700 Subject: [PATCH 04/43] Add stickyPosition prop back --- .../components/ScrollablePane/ScrollablePane.base.tsx | 4 ++-- .../examples/ScrollablePane.DetailsList.Example.tsx | 9 +++++---- .../src/components/Sticky/Sticky.tsx | 7 +++++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index a333596154ebf0..e46ba63d6f619c 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -185,10 +185,10 @@ export class ScrollablePaneBase extends BaseComponent { if (sticky.state.isStickyTop && sticky.stickyContentTop && sticky.stickyContentTop.value) { - stickyTopHeight += sticky.stickyContentTop.value.clientHeight; + stickyTopHeight += sticky.stickyContentTop.value.offsetHeight; } if (sticky.state.isStickyBottom && sticky.stickyContentBottom && sticky.stickyContentBottom.value) { - stickyBottomHeight += sticky.stickyContentBottom.value.clientHeight; + stickyBottomHeight += sticky.stickyContentBottom.value.offsetHeight; } }); diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx index a4cb76034348b3..086760a4f030e4 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx @@ -20,7 +20,8 @@ import { ScrollablePane } from 'office-ui-fabric-react/lib/ScrollablePane'; import { - Sticky + Sticky, + StickyPositionType } from 'office-ui-fabric-react/lib/Sticky'; import { MarqueeSelection } from 'office-ui-fabric-react/lib/MarqueeSelection'; @@ -87,13 +88,13 @@ export class ScrollablePaneDetailsListExample extends React.Component<{}, { return ( hello world
    - { selectionDetails } + { selectionDetails } this.setState({ items: text ? _items.filter(i => i.name.toLowerCase().indexOf(text) > -1) : _items }) } /> - +

    Item List

    @@ -105,7 +106,7 @@ export class ScrollablePaneDetailsListExample extends React.Component<{}, { onRenderDetailsHeader={ // tslint:disable-next-line:jsx-no-lambda (detailsHeaderProps: IDetailsHeaderProps, defaultRender: IRenderFunction) => ( - + { defaultRender({ ...detailsHeaderProps, onRenderColumnHeaderTooltip: (tooltipHostProps: ITooltipHostProps) => diff --git a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx index 89a993c4f4a62d..8f80ff05046970 100644 --- a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx +++ b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx @@ -134,11 +134,14 @@ export class Sticky extends BaseComponent { private _onScrollEvent = (container: HTMLElement, bottomStickyContainer: HTMLElement, footerStickyVisible: HTMLElement): void => { const { scrollablePane } = this.context; + const { stickyPosition } = this.props; if (container && this.root.value && this.nonStickyContent.value && this.stickyContentBottom.value) { const distanceFromTop = this._getNonStickyDistanceFromTop(container); const stickyDistanceFromTop = this._getStickyDistanceFromTop(); const distanceToStickTop = distanceFromTop - stickyDistanceFromTop; + const canStickyTop = stickyPosition === StickyPositionType.Both || stickyPosition === StickyPositionType.Header; + const canStickyBottom = stickyPosition === StickyPositionType.Both || stickyPosition === StickyPositionType.Footer; const isStickyTop = distanceToStickTop <= container.scrollTop; let isStickyBottom: boolean = false; @@ -148,8 +151,8 @@ export class Sticky extends BaseComponent { isStickyBottom = distanceFromTop - container.scrollTop > this._getStickyDistanceFromTopForFooter(container, footerStickyVisible); } this.setState({ - isStickyTop: isStickyTop, - isStickyBottom: isStickyBottom + isStickyTop: canStickyTop && isStickyTop, + isStickyBottom: canStickyBottom && isStickyBottom }); scrollablePane.updateStickyRefHeights(); From 2e6f1eb82f00a61c16fe412ecadcaa7cd6671df3 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Thu, 5 Apr 2018 20:00:00 -0700 Subject: [PATCH 05/43] Remove stickyBelowContainer from handle. --- .../components/ScrollablePane/ScrollablePane.base.tsx | 2 +- .../examples/ScrollablePane.DetailsList.Example.tsx | 3 +++ .../src/components/Sticky/Sticky.tsx | 10 +++++----- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index e46ba63d6f619c..a40fafa1dcaf97 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -201,7 +201,7 @@ export class ScrollablePaneBase extends BaseComponent { this._subscribers.forEach((handle) => { if (this._contentContainer && this.stickyBelowContainer) { - handle(this._contentContainer.value, this.stickyBelowContainer, this.stickyBelow); + handle(this._contentContainer.value, this.stickyBelow); } }); } diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx index 086760a4f030e4..fc35e95488f671 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx @@ -89,14 +89,17 @@ export class ScrollablePaneDetailsListExample extends React.Component<{}, { hello world
    { selectionDetails } +
    this.setState({ items: text ? _items.filter(i => i.name.toLowerCase().indexOf(text) > -1) : _items }) } /> +

    Item List

    +
    { if (isStickyTop) { isStickyStyleTop = { opacity: '1', - backgroundColor: this.props.stickyBackgroundColor + backgroundColor: this.props.stickyBackgroundColor || this._getBackground() }; } else { isStickyStyleTop = { opacity: '0', - backgroundColor: this.props.stickyBackgroundColor + backgroundColor: this.props.stickyBackgroundColor || this._getBackground() }; } @@ -98,12 +98,12 @@ export class Sticky extends BaseComponent { if (isStickyBottom) { isStickyStyleBottom = { opacity: '1', - backgroundColor: this.props.stickyBackgroundColor + backgroundColor: this.props.stickyBackgroundColor || this._getBackground() }; } else { isStickyStyleBottom = { opacity: '0', - backgroundColor: this.props.stickyBackgroundColor + backgroundColor: this.props.stickyBackgroundColor || this._getBackground() }; } @@ -132,7 +132,7 @@ export class Sticky extends BaseComponent { ); } - private _onScrollEvent = (container: HTMLElement, bottomStickyContainer: HTMLElement, footerStickyVisible: HTMLElement): void => { + private _onScrollEvent = (container: HTMLElement, footerStickyVisible: HTMLElement): void => { const { scrollablePane } = this.context; const { stickyPosition } = this.props; From 4cc596080bfaf50d37f9630394f2186195dd4006 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Fri, 6 Apr 2018 10:32:29 -0700 Subject: [PATCH 06/43] Revert details list example. Fix distanceFromTop calculation --- .../ScrollablePane.DetailsList.Example.tsx | 4 ---- .../src/components/Sticky/Sticky.tsx | 16 +++++----------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx index fc35e95488f671..569ae58218134b 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx @@ -87,19 +87,15 @@ export class ScrollablePaneDetailsListExample extends React.Component<{}, { return ( - hello world
    { selectionDetails } -
    this.setState({ items: text ? _items.filter(i => i.name.toLowerCase().indexOf(text) > -1) : _items }) } /> -

    Item List

    -
    { scrollablePane.subscribe(this._onScrollEvent); scrollablePane.addSticky(this); - this.context.scrollablePane.notifySubscribers(true); } public componentWillUnmount(): void { - const { isStickyTop, isStickyBottom } = this.state; const { scrollablePane } = this.context; scrollablePane.unsubscribe(this._onScrollEvent); } @@ -182,17 +180,13 @@ export class Sticky extends BaseComponent { let currElem = this.root.value; if (currElem) { - if (currElem.offsetParent === container) { - return currElem.offsetTop; + while (currElem.offsetParent !== container) { + distance += currElem.offsetTop; + currElem = currElem.offsetParent as HTMLDivElement; } - if (currElem.offsetParent) { - do { - distance += currElem.offsetTop; - if (currElem) { - currElem = currElem.offsetParent as HTMLDivElement; - } - } while (currElem && currElem.offsetParent !== container) + if (currElem.offsetParent === container) { + distance += currElem.offsetTop; } } return distance; From 30b8c798b5c93496999aeebc255ef89d3a769b1b Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Fri, 6 Apr 2018 12:41:23 -0700 Subject: [PATCH 07/43] Fix unmounting sticky. Fix ScrollablePane not setting correct heights on StickyTop and StickyBottom after mounting/unmounting sticky. --- .../ScrollablePane/ScrollablePane.base.tsx | 17 +++++++++++++++-- .../ScrollablePane/ScrollablePanePage.tsx | 4 ++-- .../src/components/Sticky/Sticky.tsx | 17 +++++++++-------- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index a40fafa1dcaf97..2e31c21190d580 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -81,6 +81,7 @@ export class ScrollablePaneBase extends BaseComponent { + this._stickies.delete(sticky); + if (this.stickyAbove && sticky.stickyContentTop.value) { + this.stickyAbove.removeChild(sticky.stickyContentTop.value); + } + if (this.stickyBelow && sticky.stickyContentBottom.value) { + this.stickyBelow.removeChild(sticky.stickyContentBottom.value); + } + this.notifySubscribers(); } public updateStickyRefHeights = (): void => { @@ -198,7 +211,7 @@ export class ScrollablePaneBase extends BaseComponent { + public notifySubscribers = (): void => { this._subscribers.forEach((handle) => { if (this._contentContainer && this.stickyBelowContainer) { handle(this._contentContainer.value, this.stickyBelow); diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx index e62ce3f1b8e6b0..042b682c779894 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx @@ -25,9 +25,9 @@ export class ScrollablePanePage extends React.Component - + {/* - + */}
    } allowNativeProps={ true } diff --git a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx index c37bbb5a626ad9..02b93de267f127 100644 --- a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx +++ b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx @@ -30,6 +30,7 @@ export class Sticky extends BaseComponent { subscribe: (handler: Function) => void; unsubscribe: (handler: Function) => void; addSticky: (sticky: Sticky) => void; + removeSticky: (sticky: Sticky) => void; updateStickyRefHeights: () => void; notifySubscribers: (sort?: boolean) => void; } @@ -55,12 +56,12 @@ export class Sticky extends BaseComponent { const { scrollablePane } = this.context; scrollablePane.subscribe(this._onScrollEvent); scrollablePane.addSticky(this); - - this.context.scrollablePane.notifySubscribers(true); } public componentWillUnmount(): void { const { scrollablePane } = this.context; + + scrollablePane.removeSticky(this); scrollablePane.unsubscribe(this._onScrollEvent); } @@ -130,7 +131,7 @@ export class Sticky extends BaseComponent { ); } - private _onScrollEvent = (container: HTMLElement, footerStickyVisible: HTMLElement): void => { + private _onScrollEvent = (container: HTMLElement, footerStickyContainer: HTMLElement): void => { const { scrollablePane } = this.context; const { stickyPosition } = this.props; @@ -144,16 +145,16 @@ export class Sticky extends BaseComponent { const isStickyTop = distanceToStickTop <= container.scrollTop; let isStickyBottom: boolean = false; - // Can sticky bottom if the scrollablePane height is smaller than the sticky's distance from the top of the pane - if (container.clientHeight <= distanceFromTop) { - isStickyBottom = distanceFromTop - container.scrollTop > this._getStickyDistanceFromTopForFooter(container, footerStickyVisible); + // Can sticky bottom if the scrollablePane - total sticky footer height is smaller than the sticky's distance from the top of the pane + if (container.clientHeight - footerStickyContainer.offsetHeight <= distanceFromTop) { + isStickyBottom = distanceFromTop - container.scrollTop > this._getStickyDistanceFromTopForFooter(container, footerStickyContainer); } this.setState({ isStickyTop: canStickyTop && isStickyTop, isStickyBottom: canStickyBottom && isStickyBottom + }, () => { + scrollablePane.updateStickyRefHeights(); }); - - scrollablePane.updateStickyRefHeights(); } } From de0424beb2510620c923fc9a7fe7f03246a3173d Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Fri, 6 Apr 2018 14:50:21 -0700 Subject: [PATCH 08/43] Update subscribers when DOM changes in scrollablePane. Add back DetailsList example. Remove unused componentDidUpdate in Sticky. --- .../ScrollablePane/ScrollablePane.base.tsx | 5 +++++ .../components/ScrollablePane/ScrollablePanePage.tsx | 4 ++-- .../src/components/Sticky/Sticky.tsx | 12 +++--------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index 2e31c21190d580..8cfac9c0352eb5 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -104,6 +104,11 @@ export class ScrollablePaneBase extends BaseComponent - {/* + - */} +
    } allowNativeProps={ true } diff --git a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx index 02b93de267f127..872d8762e76dc5 100644 --- a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx +++ b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx @@ -60,14 +60,8 @@ export class Sticky extends BaseComponent { public componentWillUnmount(): void { const { scrollablePane } = this.context; - - scrollablePane.removeSticky(this); scrollablePane.unsubscribe(this._onScrollEvent); - } - - public componentDidUpdate(prevProps: IStickyProps, prevState: IStickyState): void { - const { isStickyTop, isStickyBottom } = this.state; - const { scrollablePane } = this.context; + scrollablePane.removeSticky(this); } public shouldComponentUpdate(nextProps: IStickyProps, nextState: IStickyState): boolean { @@ -137,8 +131,7 @@ export class Sticky extends BaseComponent { if (container && this.root.value && this.nonStickyContent.value && this.stickyContentBottom.value) { const distanceFromTop = this._getNonStickyDistanceFromTop(container); - const stickyDistanceFromTop = this._getStickyDistanceFromTop(); - const distanceToStickTop = distanceFromTop - stickyDistanceFromTop; + const distanceToStickTop = distanceFromTop - this._getStickyDistanceFromTop(); const canStickyTop = stickyPosition === StickyPositionType.Both || stickyPosition === StickyPositionType.Header; const canStickyBottom = stickyPosition === StickyPositionType.Both || stickyPosition === StickyPositionType.Footer; @@ -153,6 +146,7 @@ export class Sticky extends BaseComponent { isStickyTop: canStickyTop && isStickyTop, isStickyBottom: canStickyBottom && isStickyBottom }, () => { + // Update ScrollablePane's Sticky bop and Sticky bottom heights scrollablePane.updateStickyRefHeights(); }); } From 0fe99c93e32f2c0b42baa82210c15757aa5d26d6 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Fri, 6 Apr 2018 15:23:52 -0700 Subject: [PATCH 09/43] Clean up inline sticky styles --- .../src/components/Sticky/Sticky.tsx | 37 +++++-------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx index 872d8762e76dc5..eeb79eaafab4c9 100644 --- a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx +++ b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx @@ -71,46 +71,27 @@ export class Sticky extends BaseComponent { this.props.children !== nextProps.children; } + private _getStickyStyles(isSticky: boolean): React.CSSProperties { + return { + visibility: isSticky ? 'visible' : 'hidden', + backgroundColor: this.props.stickyBackgroundColor || this._getBackground() + }; + } + public render(): JSX.Element { const { isStickyTop, isStickyBottom } = this.state; - let isStickyStyleTop = {}; - if (isStickyTop) { - isStickyStyleTop = { - opacity: '1', - backgroundColor: this.props.stickyBackgroundColor || this._getBackground() - }; - } else { - isStickyStyleTop = { - opacity: '0', - backgroundColor: this.props.stickyBackgroundColor || this._getBackground() - }; - } - - let isStickyStyleBottom = {}; - if (isStickyBottom) { - isStickyStyleBottom = { - opacity: '1', - backgroundColor: this.props.stickyBackgroundColor || this._getBackground() - }; - } else { - isStickyStyleBottom = { - opacity: '0', - backgroundColor: this.props.stickyBackgroundColor || this._getBackground() - }; - } - return (
    { this.props.children }
    { this.props.children }
    From 92d4db550d4824f188f73e1fb1d0447403c4adb2 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Fri, 6 Apr 2018 15:24:50 -0700 Subject: [PATCH 10/43] Remove "testing testing" from default example --- .../ScrollablePane/examples/ScrollablePane.Default.Example.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx index c86fe69645ffa0..05030729cf0e1e 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx @@ -14,7 +14,6 @@ export class ScrollablePaneDefaultExample extends React.Component { return ( - testing testing
    { contentAreas.map((ele) => { return ele; }) } From de3070c3f884b562468ab619cedd7c963f7c6376 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Fri, 6 Apr 2018 15:50:58 -0700 Subject: [PATCH 11/43] Set stickyClassName on nonStickyContent if Sticky component is stickyTop or stickyBottom --- .../ScrollablePane.Default.Example.tsx | 1 - .../src/components/Sticky/Sticky.tsx | 19 +++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx index 05030729cf0e1e..1b3d8c843962fc 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx @@ -37,7 +37,6 @@ export class ScrollablePaneDefaultExample extends React.Component {
    diff --git a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx index eeb79eaafab4c9..d82e4d8440d546 100644 --- a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx +++ b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx @@ -71,25 +71,20 @@ export class Sticky extends BaseComponent { this.props.children !== nextProps.children; } - private _getStickyStyles(isSticky: boolean): React.CSSProperties { - return { - visibility: isSticky ? 'visible' : 'hidden', - backgroundColor: this.props.stickyBackgroundColor || this._getBackground() - }; - } - public render(): JSX.Element { const { isStickyTop, isStickyBottom } = this.state; return (
    { this.props.children }
    @@ -97,6 +92,7 @@ export class Sticky extends BaseComponent {
    @@ -106,6 +102,13 @@ export class Sticky extends BaseComponent { ); } + private _getStickyStyles = (isSticky: boolean): React.CSSProperties => { + return { + visibility: isSticky ? 'visible' : 'hidden', + backgroundColor: this.props.stickyBackgroundColor || this._getBackground() + }; + } + private _onScrollEvent = (container: HTMLElement, footerStickyContainer: HTMLElement): void => { const { scrollablePane } = this.context; const { stickyPosition } = this.props; @@ -127,7 +130,7 @@ export class Sticky extends BaseComponent { isStickyTop: canStickyTop && isStickyTop, isStickyBottom: canStickyBottom && isStickyBottom }, () => { - // Update ScrollablePane's Sticky bop and Sticky bottom heights + // Update ScrollablePane's Sticky top and Sticky bottom heights scrollablePane.updateStickyRefHeights(); }); } From b72e391719ff25117b22d972ea8e46d43983dca3 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Fri, 6 Apr 2018 16:05:36 -0700 Subject: [PATCH 12/43] Remove unused _stickyBelow/_stickyAbove from ScrollablePane. Clean up stickyTopStyle and stickyBottomStyle --- .../ScrollablePane/ScrollablePane.base.tsx | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index 8cfac9c0352eb5..695e3368a655ea 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -43,14 +43,10 @@ export class ScrollablePaneBase extends BaseComponent(); private _subscribers: Set; private _stickies: Set; - private _stickyAbove: Set; - private _stickyBelow: Set; constructor(props: IScrollablePaneProps) { super(props); this._subscribers = new Set(); - this._stickyAbove = new Set(); - this._stickyBelow = new Set(); this._stickies = new Set(); this.state = { @@ -113,6 +109,7 @@ export class ScrollablePaneBase extends BaseComponent
    { + return { + height: height + } + } } \ No newline at end of file From e4ab4810b96d9738d5881de1a1bf99fbc7335176 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Fri, 6 Apr 2018 16:18:59 -0700 Subject: [PATCH 13/43] black to $ms-color-black. Set overflow-x to auto and overflow-y to hidden for Top/Bottom sticky --- .../src/components/ScrollablePane/ScrollablePane.styles.ts | 3 ++- .../ScrollablePane/examples/ScrollablePane.Example.scss | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts index 2d091323b6e4a1..c7b007205fe476 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts @@ -15,7 +15,8 @@ export const getStyles = ( width: '100%', zIndex: 1, background: '#ffffff', - overflow: 'hidden' + overflowY: 'hidden', + overflowX: 'auto' }; const maxHeightStyles: IStyle = { diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Example.scss b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Example.scss index 267314f2e308cd..4e830872be9174 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Example.scss +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Example.scss @@ -20,8 +20,8 @@ -o-transform: translateZ(0); transform: translateZ(0); will-change: font-size; - border-top: 1px solid black; - border-bottom: 1px solid black; + border-top: 1px solid $ms-color-black; + border-bottom: 1px solid $ms-color-black; } .largeFont { From 7fe6b8cee200bdf3107e29180d387eb6c53c464e Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Fri, 6 Apr 2018 20:50:29 -0700 Subject: [PATCH 14/43] Remove unused ref _stickyBelowContainerRef --- .../src/components/ScrollablePane/ScrollablePane.base.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index 695e3368a655ea..366b49260a236d 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -38,7 +38,6 @@ export class ScrollablePaneBase extends BaseComponent(); private _stickyAboveRef = createRef(); - private _stickyBelowContainerRef = createRef(); private _stickyBelowRef = createRef(); private _contentContainer = createRef(); private _subscribers: Set; @@ -63,10 +62,6 @@ export class ScrollablePaneBase extends BaseComponent
    @@ -205,7 +199,7 @@ export class ScrollablePaneBase extends BaseComponent { this._subscribers.forEach((handle) => { - if (this._contentContainer && this.stickyBelowContainer) { + if (this._contentContainer) { handle(this._contentContainer.value, this.stickyBelow); } }); From 79923592b8407d95ae121278668d22ffee473aee Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Fri, 6 Apr 2018 20:55:23 -0700 Subject: [PATCH 15/43] Add getter for contentContainer --- .../ScrollablePane/ScrollablePane.base.tsx | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index 366b49260a236d..669654201375b6 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -66,6 +66,10 @@ export class ScrollablePaneBase extends BaseComponent { this._subscribers.forEach((handle) => { - if (this._contentContainer) { - handle(this._contentContainer.value, this.stickyBelow); + if (this.contentContainer) { + handle(this.contentContainer, this.stickyBelow); } }); } public getScrollPosition = (): number => { - if (this._root.value) { - return this._root.value.scrollTop; + if (this.root) { + return this.root.scrollTop; } return 0; From 0397c023e262002106607575c9fd7b4642daf2c1 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Sun, 8 Apr 2018 16:44:38 -0700 Subject: [PATCH 16/43] Fix initial scroll position prop not working properly. Only set state if props/state changes (preventing excessive setState with updateStickyRefHeights). Change this.root to this.contentContainer for check for initialScrollPosition prop. Move logic for appending child to this.stickyAbove/Below into sortSticky. --- .../ScrollablePane/ScrollablePane.base.tsx | 117 ++++++++++++++---- .../ScrollablePane/ScrollablePanePage.tsx | 4 +- .../src/components/Sticky/Sticky.tsx | 75 +++++++---- 3 files changed, 149 insertions(+), 47 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index 669654201375b6..560409ec3d76ed 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -78,14 +78,20 @@ export class ScrollablePaneBase extends BaseComponent { this._stickies.add(sticky); - if (this.stickyAbove && sticky.stickyContentTop.value) { - this.stickyAbove.appendChild(sticky.stickyContentTop.value); - } - if (this.stickyBelow && sticky.stickyContentBottom.value) { - this.stickyBelow.appendChild(sticky.stickyContentBottom.value); - } this.notifySubscribers(); } public removeSticky = (sticky: Sticky): void => { this._stickies.delete(sticky); - if (this.stickyAbove && sticky.stickyContentTop.value) { - this.stickyAbove.removeChild(sticky.stickyContentTop.value); - } - if (this.stickyBelow && sticky.stickyContentBottom.value) { - this.stickyBelow.removeChild(sticky.stickyContentBottom.value); - } + this._removeStickyFromContainers(sticky); this.notifySubscribers(); } + public sortSticky = (sticky: Sticky): void => { + if (this.stickyAbove && this.stickyBelow) { + if (sticky.canStickyTop && sticky.stickyContentTop.value) { + if (!this.stickyAbove.children.length) { + this.stickyAbove.appendChild(sticky.stickyContentTop.value); + } else if (!this.stickyAbove.contains(sticky.stickyContentTop.value)) { + this._addToStickyContainer(sticky, this.stickyAbove); + } + } + + if (sticky.canStickyBottom && sticky.stickyContentBottom.value) { + if (!this.stickyBelow.children.length) { + this.stickyBelow.appendChild(sticky.stickyContentBottom.value); + } else if (!this.stickyBelow.contains(sticky.stickyContentBottom.value)) { + this._addToStickyContainer(sticky, this.stickyBelow); + } + } + } + } + public updateStickyRefHeights = (): void => { const stickyItems = this._stickies; @@ -187,10 +211,10 @@ export class ScrollablePaneBase extends BaseComponent { - if (sticky.state.isStickyTop && sticky.stickyContentTop && sticky.stickyContentTop.value) { + if (sticky.state.isStickyTop && sticky.canStickyTop && sticky.stickyContentTop.value) { stickyTopHeight += sticky.stickyContentTop.value.offsetHeight; } - if (sticky.state.isStickyBottom && sticky.stickyContentBottom && sticky.stickyContentBottom.value) { + if (sticky.state.isStickyBottom && sticky.canStickyBottom && sticky.stickyContentBottom.value) { stickyBottomHeight += sticky.stickyContentBottom.value.offsetHeight; } }); @@ -202,11 +226,11 @@ export class ScrollablePaneBase extends BaseComponent { - this._subscribers.forEach((handle) => { - if (this.contentContainer) { + if (this.contentContainer) { + this._subscribers.forEach((handle) => { handle(this.contentContainer, this.stickyBelow); - } - }); + }); + } } public getScrollPosition = (): number => { @@ -217,6 +241,57 @@ export class ScrollablePaneBase extends BaseComponent { + if (stickyContainer) { + const stickyChildrenElements = Array.from(stickyContainer.children) as HTMLElement[]; + const stickyListSorted = Array.from(this._stickies).sort((a, b) => { + return a.distanceFromTop - b.distanceFromTop; + }).filter((item) => { + const stickyContent = (stickyContainer === this.stickyAbove) ? item.stickyContentTop.value : item.stickyContentBottom.value; + if (stickyContent) { + return stickyChildrenElements.indexOf(stickyContent) > -1; + } + }).filter((item) => { + if (stickyContainer === this.stickyAbove) { + return item.canStickyTop; + } else { + return item.canStickyBottom; + } + }); + + const first = stickyListSorted.filter((sticky, idx) => { + return sticky.distanceFromTop > sticky.distanceFromTop + })[0]; + let targetContainer: HTMLDivElement | null = null; + if (first) { + if (stickyContainer === this.stickyAbove) { + targetContainer = first.stickyContentTop.value; + } else { + targetContainer = first.stickyContentBottom.value; + } + } + + let stickyContent: HTMLDivElement | undefined = undefined; + if (stickyContainer === this.stickyAbove && sticky.stickyContentTop.value) { + stickyContent = sticky.stickyContentTop.value; + } + if (stickyContainer === this.stickyBelow && sticky.stickyContentBottom.value) { + stickyContent = sticky.stickyContentBottom.value; + } + + if (stickyContent) { + stickyContainer.insertBefore(stickyContent, targetContainer); + } + } + } + + private _removeStickyFromContainers = (sticky: Sticky): void => { + if (this.stickyAbove && this.stickyBelow && sticky.stickyContentTop.value && sticky.stickyContentBottom.value) { + this.stickyAbove.removeChild(sticky.stickyContentTop.value); + this.stickyBelow.removeChild(sticky.stickyContentBottom.value); + } + } + private _onWindowResize = (): void => { this._async.setTimeout(() => { this.notifySubscribers(); diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx index e62ce3f1b8e6b0..042b682c779894 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx @@ -25,9 +25,9 @@ export class ScrollablePanePage extends React.Component - + {/* - + */}
    } allowNativeProps={ true } diff --git a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx index d82e4d8440d546..27dfa3e0a754a5 100644 --- a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx +++ b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx @@ -32,6 +32,7 @@ export class Sticky extends BaseComponent { addSticky: (sticky: Sticky) => void; removeSticky: (sticky: Sticky) => void; updateStickyRefHeights: () => void; + sortSticky: (sticky: Sticky) => void; notifySubscribers: (sort?: boolean) => void; } }; @@ -40,6 +41,7 @@ export class Sticky extends BaseComponent { public stickyContentTop = createRef(); public stickyContentBottom = createRef(); public nonStickyContent = createRef(); + public distanceFromTop: number; constructor(props: IStickyProps) { super(props); @@ -47,6 +49,15 @@ export class Sticky extends BaseComponent { isStickyTop: false, isStickyBottom: false }; + this.distanceFromTop = 0; + } + + public get canStickyTop(): boolean { + return this.props.stickyPosition === StickyPositionType.Both || this.props.stickyPosition === StickyPositionType.Header; + } + + public get canStickyBottom(): boolean { + return this.props.stickyPosition === StickyPositionType.Both || this.props.stickyPosition === StickyPositionType.Footer; } public componentDidMount(): void { @@ -68,6 +79,7 @@ export class Sticky extends BaseComponent { const { isStickyTop, isStickyBottom } = this.state; return isStickyTop !== nextState.isStickyTop || isStickyBottom !== nextState.isStickyBottom || + this.props.stickyPosition !== nextProps.stickyPosition || this.props.children !== nextProps.children; } @@ -76,20 +88,28 @@ export class Sticky extends BaseComponent { return (
    -
    - { this.props.children } -
    -
    - { this.props.children } -
    + { + this.canStickyTop && +
    + { this.props.children } +
    + } + { + this.canStickyBottom && +
    + { this.props.children } +
    + }
    { const { scrollablePane } = this.context; const { stickyPosition } = this.props; - if (container && this.root.value && this.nonStickyContent.value && this.stickyContentBottom.value) { - const distanceFromTop = this._getNonStickyDistanceFromTop(container); - const distanceToStickTop = distanceFromTop - this._getStickyDistanceFromTop(); - const canStickyTop = stickyPosition === StickyPositionType.Both || stickyPosition === StickyPositionType.Header; - const canStickyBottom = stickyPosition === StickyPositionType.Both || stickyPosition === StickyPositionType.Footer; + if (this.root.value && this.nonStickyContent.value) { + this.distanceFromTop = this._getNonStickyDistanceFromTop(container); + + // Add stickyContentTop/stickyContentBottom to ScrollablePane in proper position + scrollablePane.sortSticky(this); + let isStickyTop: boolean = false; + + if (this.canStickyTop) { + const distanceToStickTop = this.distanceFromTop - this._getStickyDistanceFromTop(); + isStickyTop = distanceToStickTop <= container.scrollTop; + } - const isStickyTop = distanceToStickTop <= container.scrollTop; let isStickyBottom: boolean = false; // Can sticky bottom if the scrollablePane - total sticky footer height is smaller than the sticky's distance from the top of the pane - if (container.clientHeight - footerStickyContainer.offsetHeight <= distanceFromTop) { - isStickyBottom = distanceFromTop - container.scrollTop > this._getStickyDistanceFromTopForFooter(container, footerStickyContainer); + if (this.canStickyBottom && container.clientHeight - footerStickyContainer.offsetHeight <= this.distanceFromTop) { + isStickyBottom = this.distanceFromTop - container.scrollTop > this._getStickyDistanceFromTopForFooter(container, footerStickyContainer); } + this.setState({ - isStickyTop: canStickyTop && isStickyTop, - isStickyBottom: canStickyBottom && isStickyBottom + isStickyTop: this.canStickyTop && isStickyTop, + isStickyBottom: isStickyBottom }, () => { // Update ScrollablePane's Sticky top and Sticky bottom heights scrollablePane.updateStickyRefHeights(); @@ -142,6 +168,7 @@ export class Sticky extends BaseComponent { distance = this.stickyContentTop.value.offsetTop; } + return distance; } From 0082fb414cf7dbae80a60a0731aad3cd92998bc0 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Sun, 8 Apr 2018 21:11:02 -0700 Subject: [PATCH 17/43] Simplify sortSticky function. Clean up _addtoStickyContainer function. Fix _removeStickyFromContainers not removing stickies properly. --- .../ScrollablePane/ScrollablePane.base.tsx | 93 +++++++++---------- 1 file changed, 45 insertions(+), 48 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index 560409ec3d76ed..cb8b5187b2f96c 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -187,19 +187,11 @@ export class ScrollablePaneBase extends BaseComponent { if (this.stickyAbove && this.stickyBelow) { if (sticky.canStickyTop && sticky.stickyContentTop.value) { - if (!this.stickyAbove.children.length) { - this.stickyAbove.appendChild(sticky.stickyContentTop.value); - } else if (!this.stickyAbove.contains(sticky.stickyContentTop.value)) { - this._addToStickyContainer(sticky, this.stickyAbove); - } + this._addToStickyContainer(sticky, this.stickyAbove, sticky.stickyContentTop.value); } if (sticky.canStickyBottom && sticky.stickyContentBottom.value) { - if (!this.stickyBelow.children.length) { - this.stickyBelow.appendChild(sticky.stickyContentBottom.value); - } else if (!this.stickyBelow.contains(sticky.stickyContentBottom.value)) { - this._addToStickyContainer(sticky, this.stickyBelow); - } + this._addToStickyContainer(sticky, this.stickyBelow, sticky.stickyContentBottom.value); } } } @@ -241,53 +233,58 @@ export class ScrollablePaneBase extends BaseComponent { - if (stickyContainer) { - const stickyChildrenElements = Array.from(stickyContainer.children) as HTMLElement[]; - const stickyListSorted = Array.from(this._stickies).sort((a, b) => { - return a.distanceFromTop - b.distanceFromTop; - }).filter((item) => { - const stickyContent = (stickyContainer === this.stickyAbove) ? item.stickyContentTop.value : item.stickyContentBottom.value; - if (stickyContent) { - return stickyChildrenElements.indexOf(stickyContent) > -1; - } - }).filter((item) => { - if (stickyContainer === this.stickyAbove) { - return item.canStickyTop; - } else { - return item.canStickyBottom; + private _addToStickyContainer = (sticky: Sticky, stickyContainer: HTMLDivElement, stickyContentToAdd: HTMLDivElement): void => { + // If there's no children, append child to list, otherwise, sort though array and append at correct position + if (!stickyContainer.children.length) { + stickyContainer.appendChild(stickyContentToAdd); + } else { + // If stickyContentToAdd isn't a child element of target container, then append + if (!stickyContainer.contains(stickyContentToAdd)) { + const stickyChildrenElements = Array.from(stickyContainer.children); + + // Get stickies. Filter by canStickyTop/Bottom, then sort by distance from top, and then + // filter by elements that are in the stickyContainer already. + const stickyListSorted = Array.from(this._stickies).filter((item) => { + if (stickyContainer === this.stickyAbove) { + return item.canStickyTop; + } else { + return item.canStickyBottom; + } + }).sort((a, b) => { + return a.distanceFromTop - b.distanceFromTop; + }).filter((item) => { + const stickyContent = (stickyContainer === this.stickyAbove) ? item.stickyContentTop.value : item.stickyContentBottom.value; + if (stickyContent) { + return stickyChildrenElements.indexOf(stickyContent) > -1; + } + }); + + // Get first element that has a distance from top that is further than our sticky that is being added + let targetStickyToAppendBefore: Sticky | undefined = undefined; + for (let i = 0; i < stickyListSorted.length; i++) { + if (stickyListSorted[i].distanceFromTop >= sticky.distanceFromTop) { + targetStickyToAppendBefore = stickyListSorted[i]; + break; + } } - }); - const first = stickyListSorted.filter((sticky, idx) => { - return sticky.distanceFromTop > sticky.distanceFromTop - })[0]; - let targetContainer: HTMLDivElement | null = null; - if (first) { - if (stickyContainer === this.stickyAbove) { - targetContainer = first.stickyContentTop.value; - } else { - targetContainer = first.stickyContentBottom.value; + // If target element to append before is known, then grab respective stickyContentTop/Bottom value and insert before + let targetContainer: HTMLDivElement | null = null; + if (targetStickyToAppendBefore) { + targetContainer = stickyContainer === this.stickyAbove ? + targetStickyToAppendBefore.stickyContentTop.value : + targetStickyToAppendBefore.stickyContentBottom.value; } - } - - let stickyContent: HTMLDivElement | undefined = undefined; - if (stickyContainer === this.stickyAbove && sticky.stickyContentTop.value) { - stickyContent = sticky.stickyContentTop.value; - } - if (stickyContainer === this.stickyBelow && sticky.stickyContentBottom.value) { - stickyContent = sticky.stickyContentBottom.value; - } - - if (stickyContent) { - stickyContainer.insertBefore(stickyContent, targetContainer); + stickyContainer.insertBefore(stickyContentToAdd, targetContainer); } } } private _removeStickyFromContainers = (sticky: Sticky): void => { - if (this.stickyAbove && this.stickyBelow && sticky.stickyContentTop.value && sticky.stickyContentBottom.value) { + if (this.stickyAbove && sticky.stickyContentTop.value) { this.stickyAbove.removeChild(sticky.stickyContentTop.value); + } + if (this.stickyBelow && sticky.stickyContentBottom.value) { this.stickyBelow.removeChild(sticky.stickyContentBottom.value); } } From a143c76f4f9a577228cde4ef709bfdadd1fb3034 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Sun, 8 Apr 2018 21:30:41 -0700 Subject: [PATCH 18/43] Add back in detailslist example --- .../src/components/ScrollablePane/ScrollablePanePage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx index 042b682c779894..e62ce3f1b8e6b0 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx @@ -25,9 +25,9 @@ export class ScrollablePanePage extends React.Component - {/* + - */} +
    } allowNativeProps={ true } From ca652517588cf5d0629c9db6c6c4fd81a66c246c Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Sun, 8 Apr 2018 22:48:44 -0700 Subject: [PATCH 19/43] Fix linting --- .../ScrollablePane/ScrollablePane.base.tsx | 9 +++++---- .../ScrollablePane/ScrollablePane.styles.ts | 2 +- .../src/components/Sticky/Sticky.tsx | 16 +++++++--------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index cb8b5187b2f96c..9df299d02ded4e 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -154,7 +154,8 @@ export class ScrollablePaneBase extends BaseComponent + data-is-scrollable={ true } + > { this.props.children }
    @@ -199,8 +200,8 @@ export class ScrollablePaneBase extends BaseComponent { const stickyItems = this._stickies; - let stickyTopHeight: number = 0; - let stickyBottomHeight: number = 0; + let stickyTopHeight = 0; + let stickyBottomHeight = 0; stickyItems.forEach((sticky: Sticky) => { if (sticky.state.isStickyTop && sticky.canStickyTop && sticky.stickyContentTop.value) { @@ -298,6 +299,6 @@ export class ScrollablePaneBase extends BaseComponent { return { height: height - } + }; } } \ No newline at end of file diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts index c7b007205fe476..5ef477a7af806e 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts @@ -22,7 +22,7 @@ export const getStyles = ( const maxHeightStyles: IStyle = { height: 'inherit', maxHeight: 'inherit' - } + }; return ({ root: [ diff --git a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx index 27dfa3e0a754a5..1b640aa67f3346 100644 --- a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx +++ b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx @@ -91,7 +91,6 @@ export class Sticky extends BaseComponent { { this.canStickyTop &&
    { { this.canStickyBottom &&
    { className={ isStickyTop || isStickyBottom ? this.props.stickyClassName : undefined } style={ { backgroundColor: this.props.stickyBackgroundColor - } }> + } } + > { this.props.children }
    @@ -138,14 +137,14 @@ export class Sticky extends BaseComponent { // Add stickyContentTop/stickyContentBottom to ScrollablePane in proper position scrollablePane.sortSticky(this); - let isStickyTop: boolean = false; + let isStickyTop = false; if (this.canStickyTop) { const distanceToStickTop = this.distanceFromTop - this._getStickyDistanceFromTop(); isStickyTop = distanceToStickTop <= container.scrollTop; } - let isStickyBottom: boolean = false; + let isStickyBottom = false; // Can sticky bottom if the scrollablePane - total sticky footer height is smaller than the sticky's distance from the top of the pane if (this.canStickyBottom && container.clientHeight - footerStickyContainer.offsetHeight <= this.distanceFromTop) { @@ -163,17 +162,16 @@ export class Sticky extends BaseComponent { } private _getStickyDistanceFromTop = (): number => { - let distance: number = 0; + let distance = 0; if (this.stickyContentTop.value) { distance = this.stickyContentTop.value.offsetTop; } - return distance; } private _getStickyDistanceFromTopForFooter = (container: HTMLElement, footerStickyVisibleContainer: HTMLElement): number => { - let distance: number = 0; + let distance = 0; if (this.stickyContentBottom.value) { distance = container.clientHeight - footerStickyVisibleContainer.offsetHeight + this.stickyContentBottom.value.offsetTop; } @@ -182,7 +180,7 @@ export class Sticky extends BaseComponent { } private _getNonStickyDistanceFromTop = (container: HTMLElement): number => { - let distance: number = 0; + let distance = 0; let currElem = this.root.value; if (currElem) { From b4a7820739af48ac707727bcecf1467dd20bdfaa Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Mon, 9 Apr 2018 11:16:53 -0700 Subject: [PATCH 20/43] Remove redundant check for canStickyTop/Bottom in updateStickyRefHeights. Change getScrollPosition to check for contentContainer.scrollTop --- .../src/components/ScrollablePane/ScrollablePane.base.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index 9df299d02ded4e..ae7e7410f921e1 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -204,10 +204,10 @@ export class ScrollablePaneBase extends BaseComponent { - if (sticky.state.isStickyTop && sticky.canStickyTop && sticky.stickyContentTop.value) { + if (sticky.state.isStickyTop && sticky.stickyContentTop.value) { stickyTopHeight += sticky.stickyContentTop.value.offsetHeight; } - if (sticky.state.isStickyBottom && sticky.canStickyBottom && sticky.stickyContentBottom.value) { + if (sticky.state.isStickyBottom && sticky.stickyContentBottom.value) { stickyBottomHeight += sticky.stickyContentBottom.value.offsetHeight; } }); @@ -227,8 +227,8 @@ export class ScrollablePaneBase extends BaseComponent { - if (this.root) { - return this.root.scrollTop; + if (this.contentContainer) { + return this.contentContainer.scrollTop; } return 0; From 697abf8f2794eef692cf90544fce7e65dd274656 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Tue, 10 Apr 2018 15:48:19 -0700 Subject: [PATCH 21/43] nit: cleaner code in _addToStickyContainer --- .../src/components/ScrollablePane/ScrollablePane.base.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index ae7e7410f921e1..9a09ca5cfcf68e 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -262,7 +262,7 @@ export class ScrollablePaneBase extends BaseComponent= sticky.distanceFromTop) { targetStickyToAppendBefore = stickyListSorted[i]; break; From 9e012ff9c984feb2521e097d6e736bc7b19dfd95 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Tue, 10 Apr 2018 22:07:37 -0700 Subject: [PATCH 22/43] Fix lint --- .../src/components/ScrollablePane/ScrollablePane.base.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index 9a09ca5cfcf68e..49d49543328859 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -262,7 +262,7 @@ export class ScrollablePaneBase extends BaseComponent= sticky.distanceFromTop) { targetStickyToAppendBefore = stickyListSorted[i]; break; From 5d894de665d3248197da6b8e5329c4c266d660ba Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Thu, 12 Apr 2018 17:10:44 -0700 Subject: [PATCH 23/43] Add aria-hidden to render for Sticky. Add comment in notifySubscribers. --- .../src/components/ScrollablePane/ScrollablePane.base.tsx | 1 + .../office-ui-fabric-react/src/components/Sticky/Sticky.tsx | 3 +++ 2 files changed, 4 insertions(+) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index 49d49543328859..e114306b0cd20b 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -221,6 +221,7 @@ export class ScrollablePaneBase extends BaseComponent { if (this.contentContainer) { this._subscribers.forEach((handle) => { + // this.stickyBelow is passed in for calculating distance to determine Sticky status handle(this.contentContainer, this.stickyBelow); }); } diff --git a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx index 1b640aa67f3346..e21500b8e08576 100644 --- a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx +++ b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx @@ -94,6 +94,7 @@ export class Sticky extends BaseComponent { className={ this.props.stickyClassName } ref={ this.stickyContentTop } style={ this._getStickyStyles(isStickyTop) } + aria-hidden={ !isStickyTop } > { this.props.children }
    @@ -104,6 +105,7 @@ export class Sticky extends BaseComponent { className={ this.props.stickyClassName } ref={ this.stickyContentBottom } style={ this._getStickyStyles(isStickyBottom) } + aria-hidden={ !isStickyBottom } > { this.props.children }
    @@ -111,6 +113,7 @@ export class Sticky extends BaseComponent {
    Date: Mon, 16 Apr 2018 16:42:26 -0700 Subject: [PATCH 24/43] move sortSticky to component mount only. Add setDistanceFromTop function and set distances once ScrollablePane has mounted --- .../ScrollablePane/ScrollablePane.base.tsx | 19 +++++++++++++++++++ .../src/components/Sticky/Sticky.tsx | 10 +++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index e114306b0cd20b..7707091c30eac6 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -92,6 +92,11 @@ export class ScrollablePaneBase extends BaseComponent { + this.sortSticky(sticky); + }); this.notifySubscribers(); } @@ -162,6 +167,14 @@ export class ScrollablePaneBase extends BaseComponent { + sticky.setDistanceFromTop(this.contentContainer as HTMLDivElement); + }); + } + } + public forceLayoutUpdate() { this._onWindowResize(); } @@ -176,6 +189,12 @@ export class ScrollablePaneBase extends BaseComponent { this._stickies.add(sticky); + + // If ScrollablePane is mounted, then sort sticky in correct place + if (this.contentContainer) { + sticky.setDistanceFromTop(this.contentContainer); + this.sortSticky(sticky); + } this.notifySubscribers(); } diff --git a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx index e21500b8e08576..fccadc49877ab3 100644 --- a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx +++ b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx @@ -124,6 +124,10 @@ export class Sticky extends BaseComponent { ); } + public setDistanceFromTop(container: HTMLDivElement): void { + this.distanceFromTop = this._getNonStickyDistanceFromTop(container); + } + private _getStickyStyles = (isSticky: boolean): React.CSSProperties => { return { visibility: isSticky ? 'visible' : 'hidden', @@ -137,18 +141,14 @@ export class Sticky extends BaseComponent { if (this.root.value && this.nonStickyContent.value) { this.distanceFromTop = this._getNonStickyDistanceFromTop(container); - - // Add stickyContentTop/stickyContentBottom to ScrollablePane in proper position - scrollablePane.sortSticky(this); let isStickyTop = false; + let isStickyBottom = false; if (this.canStickyTop) { const distanceToStickTop = this.distanceFromTop - this._getStickyDistanceFromTop(); isStickyTop = distanceToStickTop <= container.scrollTop; } - let isStickyBottom = false; - // Can sticky bottom if the scrollablePane - total sticky footer height is smaller than the sticky's distance from the top of the pane if (this.canStickyBottom && container.clientHeight - footerStickyContainer.offsetHeight <= this.distanceFromTop) { isStickyBottom = this.distanceFromTop - container.scrollTop > this._getStickyDistanceFromTopForFooter(container, footerStickyContainer); From 57faff068b1d59cac90598765a8405b48fbf7d72 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Tue, 17 Apr 2018 12:13:31 -0700 Subject: [PATCH 25/43] Return undefined instead of null in _getBackground --- .../office-ui-fabric-react/src/components/Sticky/Sticky.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx index fccadc49877ab3..09c34081ddb90c 100644 --- a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx +++ b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx @@ -200,9 +200,9 @@ export class Sticky extends BaseComponent { } // Gets background of nearest parent element that has a declared background-color attribute - private _getBackground(): string | null { + private _getBackground(): string | undefined { if (!this.root.value) { - return null; + return undefined; } let curr: HTMLElement = this.root.value; @@ -211,7 +211,7 @@ export class Sticky extends BaseComponent { window.getComputedStyle(curr).getPropertyValue('background-color') === 'transparent') { if (curr.tagName === 'HTML') { // Fallback color if no element has a declared background-color attribute - return null; + return undefined; } if (curr.parentElement) { curr = curr.parentElement; From 7d86387f18e6bbac4e383312757f5739cf7964a9 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Tue, 17 Apr 2018 13:08:01 -0700 Subject: [PATCH 26/43] Fix merge conflict --- .../components/ScrollablePane/ScrollablePanePage.tsx | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx index 5f6c64017fb9e2..170577ea911936 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePanePage.tsx @@ -53,20 +53,9 @@ export class ScrollablePanePage extends React.Component } dos={ -<<<<<<< HEAD -
    -
      -
    • Ensure that a parent component has a CSS height, or max-height attribute set (and any intermediary containers have an inherit, or explicit height/max-height set).
    • -
    • Use Sticky component on block level elements
    • -
    • Sticky component are ideally section headers and/or footers
    • -
    • Ensure that the total height of Sticky components do not exceed the height of the ScrollablePane
    • -
    -
    -======= { require('!raw-loader!office-ui-fabric-react/src/components/ScrollablePane/docs/ScrollablePaneDos.md') } ->>>>>>> 4efff92981d7301ac16bc8a2cbd7624585f9c42b } donts={ From 3799d8791288f17ed7c89cf0033488d9bace2f0f Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Thu, 19 Apr 2018 13:18:42 -0700 Subject: [PATCH 27/43] Remove unused StickyPosition --- packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx index a49a7f72336467..20ab81806fedf2 100644 --- a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx +++ b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx @@ -137,7 +137,6 @@ export class Sticky extends BaseComponent { private _onScrollEvent = (container: HTMLElement, footerStickyContainer: HTMLElement): void => { const { scrollablePane } = this.context; - const { stickyPosition } = this.props; if (this.root.current && this.nonStickyContent.current) { this.distanceFromTop = this._getNonStickyDistanceFromTop(container); From a7aeb07c71f0cf43d615bf9a6cec18151046f3cb Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Sun, 22 Apr 2018 11:01:18 -0700 Subject: [PATCH 28/43] Only updateStickyRefHeights in Sticky if state changes. Change from using duplicate props.children to placeholder divs --- .../src/components/Sticky/Sticky.tsx | 53 ++++++++++++++----- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx index 20ab81806fedf2..628e09d2f64428 100644 --- a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx +++ b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx @@ -75,6 +75,13 @@ export class Sticky extends BaseComponent { scrollablePane.removeSticky(this); } + public componentDidUpdate(prevProps: IStickyProps, prevState: IStickyState): void { + const { scrollablePane } = this.context; + if (prevState.isStickyTop !== this.state.isStickyTop || prevState.isStickyBottom !== this.state.isStickyBottom) { + scrollablePane.updateStickyRefHeights(); + } + } + public shouldComponentUpdate(nextProps: IStickyProps, nextState: IStickyState): boolean { const { isStickyTop, isStickyBottom } = this.state; return isStickyTop !== nextState.isStickyTop || @@ -93,10 +100,9 @@ export class Sticky extends BaseComponent {
    - { this.props.children } +
    } { @@ -104,19 +110,16 @@ export class Sticky extends BaseComponent {
    - { this.props.children } +
    } +
    { this.props.children }
    @@ -124,14 +127,39 @@ export class Sticky extends BaseComponent { ); } + public addSticky(stickyContent: HTMLDivElement): void { + if (this.nonStickyContent.current) { + stickyContent.appendChild(this.nonStickyContent.current); + } + } + + public resetSticky(): void { + if (this.nonStickyContent.current && this.root.current) { + this.root.current.appendChild(this.nonStickyContent.current); + } + } + + public setDistanceFromTop(container: HTMLDivElement): void { this.distanceFromTop = this._getNonStickyDistanceFromTop(container); } - private _getStickyStyles = (isSticky: boolean): React.CSSProperties => { + private _getStickyPlaceholderHeight(isSticky: boolean): React.CSSProperties { + const height = this.nonStickyContent.current ? this.nonStickyContent.current.offsetHeight : 0; + + return { + visibility: isSticky ? 'hidden' : 'visible', + height: isSticky ? 0 : height + }; + } + + private _getNonStickyPlaceholderHeight(): React.CSSProperties { + const { isStickyTop, isStickyBottom, } = this.state; + const height = this.nonStickyContent.current ? this.nonStickyContent.current.offsetHeight : 0; + return { - visibility: isSticky ? 'visible' : 'hidden', - backgroundColor: this.props.stickyBackgroundColor || this._getBackground() + display: isStickyTop || isStickyBottom ? 'block' : 'none', + height: height }; } @@ -156,9 +184,6 @@ export class Sticky extends BaseComponent { this.setState({ isStickyTop: this.canStickyTop && isStickyTop, isStickyBottom: isStickyBottom - }, () => { - // Update ScrollablePane's Sticky top and Sticky bottom heights - scrollablePane.updateStickyRefHeights(); }); } } From aac9e539b61c711006db5e14ed38dfc14da93ed0 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Sun, 22 Apr 2018 11:23:19 -0700 Subject: [PATCH 29/43] Add mutationObserver to check for Sticky component state changes --- .../ScrollablePane/ScrollablePane.base.tsx | 72 +++++++++++++++++-- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index ed5705646e23af..b0e914d7fb061e 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -42,6 +42,7 @@ export class ScrollablePaneBase extends BaseComponent(); private _subscribers: Set; private _stickies: Set; + private _mutationObserver: MutationObserver; constructor(props: IScrollablePaneProps) { super(props); @@ -98,11 +99,50 @@ export class ScrollablePaneBase extends BaseComponent { + // Function to check if mutation is occuring in stickyAbove or stickyBelow + function checkIfMutationIsSticky(mutationRecord: MutationRecord): boolean { + if (this.stickyAbove !== null && this.stickyBelow !== null) { + return this.stickyAbove.contains(mutationRecord.target) || this.stickyBelow.contains(mutationRecord.target); + } + return false; + } + + // If mutation occurs in sticky header or footer, then update sticky top/bottom heights + if (mutation.some(checkIfMutationIsSticky.bind(this))) { + this.updateStickyRefHeights(); + } else { + // Else if mutation occurs in scrollable region, then find sticky it belongs to and force update + let stickyList = Array.from(this._stickies).filter((sticky) => { + if (sticky.root.current) { + return sticky.root.current.contains(mutation[0].target); + } + }); + if (stickyList.length) { + stickyList.forEach((sticky) => { + sticky.forceUpdate(); + }); + } + } + }); + + if (this.root) { + this._mutationObserver.observe(this.root, { + childList: true, + attributes: true, + subtree: true, + characterData: true + }); + } + } } public componentWillUnmount() { this._events.off(this.contentContainer); this._events.off(window); + this._mutationObserver.disconnect(); } // Only updates if props/state change, just to prevent excessive setState with updateStickyRefHeights @@ -223,11 +263,15 @@ export class ScrollablePaneBase extends BaseComponent { - if (sticky.state.isStickyTop && sticky.stickyContentTop.current) { - stickyTopHeight += sticky.stickyContentTop.current.offsetHeight; - } - if (sticky.state.isStickyBottom && sticky.stickyContentBottom.current) { - stickyBottomHeight += sticky.stickyContentBottom.current.offsetHeight; + const { isStickyTop, isStickyBottom } = sticky.state; + if (sticky.nonStickyContent.current) { + if (isStickyTop) { + stickyTopHeight += sticky.nonStickyContent.current.offsetHeight + } + if (isStickyBottom) { + stickyBottomHeight += sticky.nonStickyContent.current.offsetHeight + } + this._checkStickyStatus(sticky); } }); @@ -254,6 +298,24 @@ export class ScrollablePaneBase extends BaseComponent { // If there's no children, append child to list, otherwise, sort though array and append at correct position if (!stickyContainer.children.length) { From 0080b465711ae871b284bd58d63e66e938f41ceb Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Sun, 22 Apr 2018 20:16:24 -0700 Subject: [PATCH 30/43] Change scrollablePane didUpdate to notify when stickyTop/Bottom height changes --- .../src/components/ScrollablePane/ScrollablePane.base.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index b0e914d7fb061e..3a494ecbafa267 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -160,8 +160,8 @@ export class ScrollablePaneBase extends BaseComponent Date: Sun, 22 Apr 2018 20:28:07 -0700 Subject: [PATCH 31/43] Update scrollablePane styles to use position absolute. Update default example. --- .../ScrollablePane/ScrollablePane.styles.ts | 6 ++- .../ScrollablePane.Default.Example.tsx | 37 ++++++++++++++----- .../examples/ScrollablePane.Example.scss | 4 +- .../src/components/Sticky/Sticky.tsx | 8 +++- 4 files changed, 42 insertions(+), 13 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts index 5ef477a7af806e..f2266f1c279089 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts @@ -29,7 +29,11 @@ export const getStyles = ( 'ms-ScrollablePane', { WebkitOverflowScrolling: 'touch', - position: 'relative' + position: 'absolute', + top: 0, + right: 0, + bottom: 0, + left: 0 }, maxHeightStyles, className diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx index 1b3d8c843962fc..3ae8655b79fb0b 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx @@ -4,6 +4,18 @@ import { Sticky, StickyPositionType } from 'office-ui-fabric-react/lib/Sticky'; import { lorem } from '@uifabric/example-app-base'; import './ScrollablePane.Example.scss'; +const colors = [ + '#eaeaea', + '#dadada', + '#d0d0d0', + '#c8c8c8', + '#a6a6a6', + '#c7e0f4', + '#71afe5', + '#eff6fc', + '#deecf9' +]; + export class ScrollablePaneDefaultExample extends React.Component { public render() { @@ -13,11 +25,17 @@ export class ScrollablePaneDefaultExample extends React.Component { } return ( - - { contentAreas.map((ele) => { - return ele; - }) } - +
    + + { contentAreas.map((ele) => { + return ele; + }) } + +
    ); } @@ -31,13 +49,14 @@ export class ScrollablePaneDefaultExample extends React.Component { } private _createContentArea(index: number) { - const style = this._getRandomColor(); - return ( -
    +
    Sticky Component #{ index + 1 } diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Example.scss b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Example.scss index 4e830872be9174..7ea3b6e048f937 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Example.scss +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Example.scss @@ -8,8 +8,8 @@ .sticky { @include ms-fontColor-neutralDark; - padding: 10px 20px; - font-size: 16px; + padding: 5px 20px 5px 10px; + font-size: 13px; -webkit-transition: font-size ease 0.3s; -moz-transition: font-size ease 0.3s; -o-transition: font-size ease 0.3s; diff --git a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx index 628e09d2f64428..93c6dabf7e7367 100644 --- a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx +++ b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx @@ -120,6 +120,7 @@ export class Sticky extends BaseComponent {
    { this.props.children }
    @@ -139,11 +140,16 @@ export class Sticky extends BaseComponent { } } - public setDistanceFromTop(container: HTMLDivElement): void { this.distanceFromTop = this._getNonStickyDistanceFromTop(container); } + private _getContentStyles(): React.CSSProperties { + return { + backgroundColor: this.props.stickyBackgroundColor || this._getBackground() + } + } + private _getStickyPlaceholderHeight(isSticky: boolean): React.CSSProperties { const height = this.nonStickyContent.current ? this.nonStickyContent.current.offsetHeight : 0; From 28709a79738d096251208c84fbcf387ea615f904 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Sun, 22 Apr 2018 20:34:08 -0700 Subject: [PATCH 32/43] Fix default example to not have duplicate colors --- .../examples/ScrollablePane.Default.Example.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx index 3ae8655b79fb0b..46f3edd6e5ba81 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx @@ -17,7 +17,6 @@ const colors = [ ]; export class ScrollablePaneDefaultExample extends React.Component { - public render() { const contentAreas: JSX.Element[] = []; for (let i = 0; i < 5; i++) { @@ -49,10 +48,12 @@ export class ScrollablePaneDefaultExample extends React.Component { } private _createContentArea(index: number) { + const color = colors.splice(Math.floor(Math.random() * colors.length), 1)[0]; + return (
    Date: Sun, 22 Apr 2018 20:36:10 -0700 Subject: [PATCH 33/43] Update details list example --- .../ScrollablePane.DetailsList.Example.tsx | 72 ++++++++++--------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx index 569ae58218134b..0248adbe4e445c 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx @@ -86,41 +86,47 @@ export class ScrollablePaneDetailsListExample extends React.Component<{}, { const { items, selectionDetails } = this.state; return ( - - { selectionDetails } - this.setState({ items: text ? _items.filter(i => i.name.toLowerCase().indexOf(text) > -1) : _items }) } - /> - -

    Item List

    -
    - - ) => ( - - { defaultRender({ - ...detailsHeaderProps, - onRenderColumnHeaderTooltip: (tooltipHostProps: ITooltipHostProps) => - }) } - - ) } - selection={ this._selection } - selectionPreservedOnEmptyClick={ true } - ariaLabelForSelectionColumn='Toggle selection' - ariaLabelForSelectAllCheckbox='Toggle selection for all items' +
    + + { selectionDetails } + alert(`Item invoked: ${item.name}`) } + onChanged={ text => this.setState({ items: text ? _items.filter(i => i.name.toLowerCase().indexOf(text) > -1) : _items }) } /> - - + +

    Item List

    +
    + + ) => ( + + { defaultRender({ + ...detailsHeaderProps, + onRenderColumnHeaderTooltip: (tooltipHostProps: ITooltipHostProps) => + }) } + + ) } + selection={ this._selection } + selectionPreservedOnEmptyClick={ true } + ariaLabelForSelectionColumn='Toggle selection' + ariaLabelForSelectAllCheckbox='Toggle selection for all items' + // tslint:disable-next-line:jsx-no-lambda + onItemInvoked={ (item) => alert(`Item invoked: ${item.name}`) } + /> + + +
    ); } From 59f2ab7491974c58a9c99edf6ff5300854ee24ab Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Sun, 22 Apr 2018 20:59:04 -0700 Subject: [PATCH 34/43] Update ScrollablePane Do's. Update example css --- .../ScrollablePane/docs/ScrollablePaneDos.md | 2 +- .../examples/ScrollablePane.Example.scss | 16 ---------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/docs/ScrollablePaneDos.md b/packages/office-ui-fabric-react/src/components/ScrollablePane/docs/ScrollablePaneDos.md index 0e7d2a148cd7bb..895026b77cd2a2 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/docs/ScrollablePaneDos.md +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/docs/ScrollablePaneDos.md @@ -1,4 +1,4 @@ -- Ensure that a parent component has a CSS height, or max-height attribute set (and any intermediary containers have an inherit, or explicit height/max-height set) +- ScrollablePane uses `position: absolute`. Ensure that the parent element has an explicit height, or has space already allocated for ScrollablePane (e.g: flexbox). - Use Sticky component on block level elements - Sticky component are ideally section headers and/or footers - Ensure that the total height of Sticky components do not exceed the height of the ScrollablePane \ No newline at end of file diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Example.scss b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Example.scss index 7ea3b6e048f937..f4f831c52db394 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Example.scss +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Example.scss @@ -10,26 +10,10 @@ @include ms-fontColor-neutralDark; padding: 5px 20px 5px 10px; font-size: 13px; - -webkit-transition: font-size ease 0.3s; - -moz-transition: font-size ease 0.3s; - -o-transition: font-size ease 0.3s; - -ms-transition: font-size ease 0.3s; - -webkit-transform: translateZ(0); - -moz-transform: translateZ(0); - -ms-transform: translateZ(0); - -o-transform: translateZ(0); - transform: translateZ(0); - will-change: font-size; border-top: 1px solid $ms-color-black; border-bottom: 1px solid $ms-color-black; } - .largeFont { - .sticky { - font-size: 20px; - } - } - .textContent { padding: 15px 10px; } From 0ef10da0cf26728b32256ff31de1972ebd702633 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Sun, 22 Apr 2018 21:00:45 -0700 Subject: [PATCH 35/43] Update sticky donts --- .../src/components/ScrollablePane/docs/ScrollablePaneDonts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/docs/ScrollablePaneDonts.md b/packages/office-ui-fabric-react/src/components/ScrollablePane/docs/ScrollablePaneDonts.md index 84f8a79e0cc17a..fa4363d3517c12 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/docs/ScrollablePaneDonts.md +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/docs/ScrollablePaneDonts.md @@ -1 +1 @@ -- Don't use Sticky on elements with margin top or bottom \ No newline at end of file +- Don't use Sticky on elements with `margin-top` or `margin-bottom` \ No newline at end of file From b8aab4c427b2a104d9c92e99e73a6347a879b419 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Sun, 22 Apr 2018 21:40:32 -0700 Subject: [PATCH 36/43] Fix lint --- .../ScrollablePane/ScrollablePane.base.tsx | 8 +++---- .../ScrollablePane.Default.Example.tsx | 23 +++++++------------ .../src/components/Sticky/Sticky.tsx | 13 ++--------- 3 files changed, 14 insertions(+), 30 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index efe77b32c3ffc4..7a35092e62c41b 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -100,7 +100,7 @@ export class ScrollablePaneBase extends BaseComponent { // Function to check if mutation is occuring in stickyAbove or stickyBelow function checkIfMutationIsSticky(mutationRecord: MutationRecord): boolean { @@ -115,7 +115,7 @@ export class ScrollablePaneBase extends BaseComponent { + const stickyList = Array.from(this._stickies).filter((sticky) => { if (sticky.root.current) { return sticky.root.current.contains(mutation[0].target); } @@ -266,10 +266,10 @@ export class ScrollablePaneBase extends BaseComponent +
    { contentAreas.map((ele) => { return ele; @@ -38,20 +39,12 @@ export class ScrollablePaneDefaultExample extends React.Component { ); } - private _getRandomColor(): string { - const letters = 'BCDEF'.split(''); - let color = '#'; - for (let i = 0; i < 6; i++) { - color += letters[Math.floor(Math.random() * letters.length)]; - } - return color; - } - private _createContentArea(index: number) { const color = colors.splice(Math.floor(Math.random() * colors.length), 1)[0]; return ( -
    {
    } -
    +
    { private _getContentStyles(): React.CSSProperties { return { backgroundColor: this.props.stickyBackgroundColor || this._getBackground() - } + }; } private _getStickyPlaceholderHeight(isSticky: boolean): React.CSSProperties { @@ -170,8 +169,6 @@ export class Sticky extends BaseComponent { } private _onScrollEvent = (container: HTMLElement, footerStickyContainer: HTMLElement): void => { - const { scrollablePane } = this.context; - if (this.root.current && this.nonStickyContent.current) { this.distanceFromTop = this._getNonStickyDistanceFromTop(container); let isStickyTop = false; @@ -209,7 +206,6 @@ export class Sticky extends BaseComponent { distance = container.clientHeight - footerStickyVisibleContainer.offsetHeight + this.stickyContentBottom.current.offsetTop; } -<<<<<<< HEAD return distance; } @@ -221,11 +217,6 @@ export class Sticky extends BaseComponent { while (currElem.offsetParent !== container) { distance += currElem.offsetTop; currElem = currElem.offsetParent as HTMLDivElement; -======= - setTimeout((): void => { - if (this.props.stickyClassName) { - this.content.children[0].classList.remove(this.props.stickyClassName); ->>>>>>> 57d14eb7535d07348628c034bff03646c0851bd2 } if (currElem.offsetParent === container) { From 489d24663208a341a19d55daabf050ace573936a Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Sun, 22 Apr 2018 21:42:22 -0700 Subject: [PATCH 37/43] more lint --- .../examples/ScrollablePane.Default.Example.tsx | 3 ++- .../examples/ScrollablePane.DetailsList.Example.tsx | 12 +++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx index ce61b56d175eb1..9c00b173450d0c 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.Default.Example.tsx @@ -29,7 +29,8 @@ export class ScrollablePaneDefaultExample extends React.Component { height: '900px', position: 'relative', maxHeight: 'inherit' - } }> + } } + > { contentAreas.map((ele) => { return ele; diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx index 8887e236c643a3..a6b7f86e54bddd 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/examples/ScrollablePane.DetailsList.Example.tsx @@ -84,11 +84,13 @@ export class ScrollablePaneDetailsListExample extends React.Component<{}, { const { items, selectionDetails } = this.state; return ( -
    +
    { selectionDetails } Date: Wed, 2 May 2018 15:36:35 -0700 Subject: [PATCH 38/43] Set refs as private properties of Sticky. Remove background #fff from stickytop/bottom. Add width on sticky component so element doesn't extend past to scrollbar. --- .../ScrollablePane/ScrollablePane.base.tsx | 44 +++++------ .../ScrollablePane/ScrollablePane.styles.ts | 1 - .../src/components/Sticky/Sticky.tsx | 75 ++++++++++++------- 3 files changed, 69 insertions(+), 51 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index 9fa11a3afbe068..ede89b106b9a46 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -113,8 +113,8 @@ export class ScrollablePaneBase extends BaseComponent { - if (sticky.root.current) { - return sticky.root.current.contains(mutation[0].target); + if (this.root) { + return this.root.contains(mutation[0].target); } }); if (stickyList.length) { @@ -243,12 +243,12 @@ export class ScrollablePaneBase extends BaseComponent { if (this.stickyAbove && this.stickyBelow) { - if (sticky.canStickyTop && sticky.stickyContentTop.current) { - this._addToStickyContainer(sticky, this.stickyAbove, sticky.stickyContentTop.current); + if (sticky.canStickyTop && sticky.stickyContentTop) { + this._addToStickyContainer(sticky, this.stickyAbove, sticky.stickyContentTop); } - if (sticky.canStickyBottom && sticky.stickyContentBottom.current) { - this._addToStickyContainer(sticky, this.stickyBelow, sticky.stickyContentBottom.current); + if (sticky.canStickyBottom && sticky.stickyContentBottom) { + this._addToStickyContainer(sticky, this.stickyBelow, sticky.stickyContentBottom); } } } @@ -261,12 +261,12 @@ export class ScrollablePaneBase extends BaseComponent { const { isStickyTop, isStickyBottom } = sticky.state; - if (sticky.nonStickyContent.current) { + if (sticky.nonStickyContent) { if (isStickyTop) { - stickyTopHeight += sticky.nonStickyContent.current.offsetHeight; + stickyTopHeight += sticky.nonStickyContent.offsetHeight; } if (isStickyBottom) { - stickyBottomHeight += sticky.nonStickyContent.current.offsetHeight; + stickyBottomHeight += sticky.nonStickyContent.offsetHeight; } this._checkStickyStatus(sticky); } @@ -296,17 +296,17 @@ export class ScrollablePaneBase extends BaseComponent { return a.distanceFromTop - b.distanceFromTop; }).filter((item) => { - const stickyContent = (stickyContainer === this.stickyAbove) ? item.stickyContentTop.current : item.stickyContentBottom.current; + const stickyContent = (stickyContainer === this.stickyAbove) ? item.stickyContentTop : item.stickyContentBottom; if (stickyContent) { return stickyChildrenElements.indexOf(stickyContent) > -1; } @@ -352,8 +352,8 @@ export class ScrollablePaneBase extends BaseComponent { - if (this.stickyAbove && sticky.stickyContentTop.current) { - this.stickyAbove.removeChild(sticky.stickyContentTop.current); + if (this.stickyAbove && sticky.stickyContentTop) { + this.stickyAbove.removeChild(sticky.stickyContentTop); } - if (this.stickyBelow && sticky.stickyContentBottom.current) { - this.stickyBelow.removeChild(sticky.stickyContentBottom.current); + if (this.stickyBelow && sticky.stickyContentBottom) { + this.stickyBelow.removeChild(sticky.stickyContentBottom); } } diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts index 7d1807ab50d0d4..641c073da8261f 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.styles.ts @@ -26,7 +26,6 @@ export const getStyles = ( pointerEvents: 'auto', width: '100%', zIndex: ZIndexes.ScrollablePane, - background: '#ffffff', overflowY: 'hidden', overflowX: 'auto' }; diff --git a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx index 63e24b2276f824..0adb875eabd1c7 100644 --- a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx +++ b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx @@ -33,10 +33,10 @@ export class Sticky extends BaseComponent { } }; - public root = createRef(); - public stickyContentTop = createRef(); - public stickyContentBottom = createRef(); - public nonStickyContent = createRef(); + private _root = createRef(); + private _stickyContentTop = createRef(); + private _stickyContentBottom = createRef(); + private _nonStickyContent = createRef(); public distanceFromTop: number; constructor(props: IStickyProps) { @@ -48,6 +48,22 @@ export class Sticky extends BaseComponent { this.distanceFromTop = 0; } + public get root(): HTMLDivElement | null { + return this._root.current; + } + + public get stickyContentTop(): HTMLDivElement | null { + return this._stickyContentTop.current; + } + + public get stickyContentBottom(): HTMLDivElement | null { + return this._stickyContentBottom.current; + } + + public get nonStickyContent(): HTMLDivElement | null { + return this._nonStickyContent.current; + } + public get canStickyTop(): boolean { return this.props.stickyPosition === StickyPositionType.Both || this.props.stickyPosition === StickyPositionType.Header; } @@ -90,12 +106,12 @@ export class Sticky extends BaseComponent { const { isStickyTop, isStickyBottom } = this.state; return ( -
    +
    { this.canStickyTop &&
    @@ -105,7 +121,7 @@ export class Sticky extends BaseComponent { this.canStickyBottom &&
    @@ -113,9 +129,9 @@ export class Sticky extends BaseComponent { }
    { this.props.children }
    @@ -124,14 +140,14 @@ export class Sticky extends BaseComponent { } public addSticky(stickyContent: HTMLDivElement): void { - if (this.nonStickyContent.current) { - stickyContent.appendChild(this.nonStickyContent.current); + if (this.nonStickyContent) { + stickyContent.appendChild(this.nonStickyContent); } } public resetSticky(): void { - if (this.nonStickyContent.current && this.root.current) { - this.root.current.appendChild(this.nonStickyContent.current); + if (this.nonStickyContent && this.root) { + this.root.appendChild(this.nonStickyContent); } } @@ -139,14 +155,17 @@ export class Sticky extends BaseComponent { this.distanceFromTop = this._getNonStickyDistanceFromTop(container); } - private _getContentStyles(): React.CSSProperties { - return { - backgroundColor: this.props.stickyBackgroundColor || this._getBackground() - }; + private _getContentStyles(isSticky: boolean): React.CSSProperties | undefined { + if (this.root) { + return { + backgroundColor: this.props.stickyBackgroundColor || this._getBackground(), + width: isSticky ? this.root.offsetWidth : 'auto' + }; + } } private _getStickyPlaceholderHeight(isSticky: boolean): React.CSSProperties { - const height = this.nonStickyContent.current ? this.nonStickyContent.current.offsetHeight : 0; + const height = this.nonStickyContent ? this.nonStickyContent.offsetHeight : 0; return { visibility: isSticky ? 'hidden' : 'visible', @@ -156,7 +175,7 @@ export class Sticky extends BaseComponent { private _getNonStickyPlaceholderHeight(): React.CSSProperties { const { isStickyTop, isStickyBottom, } = this.state; - const height = this.nonStickyContent.current ? this.nonStickyContent.current.offsetHeight : 0; + const height = this.nonStickyContent ? this.nonStickyContent.offsetHeight : 0; return { display: isStickyTop || isStickyBottom ? 'block' : 'none', @@ -165,14 +184,14 @@ export class Sticky extends BaseComponent { } private _onScrollEvent = (container: HTMLElement, footerStickyContainer: HTMLElement): void => { - if (this.root.current && this.nonStickyContent.current) { + if (this.root && this.nonStickyContent) { this.distanceFromTop = this._getNonStickyDistanceFromTop(container); let isStickyTop = false; let isStickyBottom = false; if (this.canStickyTop) { const distanceToStickTop = this.distanceFromTop - this._getStickyDistanceFromTop(); - isStickyTop = distanceToStickTop <= container.scrollTop; + isStickyTop = distanceToStickTop < container.scrollTop; } // Can sticky bottom if the scrollablePane - total sticky footer height is smaller than the sticky's distance from the top of the pane @@ -189,8 +208,8 @@ export class Sticky extends BaseComponent { private _getStickyDistanceFromTop = (): number => { let distance = 0; - if (this.stickyContentTop.current) { - distance = this.stickyContentTop.current.offsetTop; + if (this.stickyContentTop) { + distance = this.stickyContentTop.offsetTop; } return distance; @@ -198,8 +217,8 @@ export class Sticky extends BaseComponent { private _getStickyDistanceFromTopForFooter = (container: HTMLElement, footerStickyVisibleContainer: HTMLElement): number => { let distance = 0; - if (this.stickyContentBottom.current) { - distance = container.clientHeight - footerStickyVisibleContainer.offsetHeight + this.stickyContentBottom.current.offsetTop; + if (this.stickyContentBottom) { + distance = container.clientHeight - footerStickyVisibleContainer.offsetHeight + this.stickyContentBottom.offsetTop; } return distance; @@ -207,7 +226,7 @@ export class Sticky extends BaseComponent { private _getNonStickyDistanceFromTop = (container: HTMLElement): number => { let distance = 0; - let currElem = this.root.current; + let currElem = this.root; if (currElem) { while (currElem.offsetParent !== container) { @@ -224,11 +243,11 @@ export class Sticky extends BaseComponent { // Gets background of nearest parent element that has a declared background-color attribute private _getBackground(): string | undefined { - if (!this.root.current) { + if (!this.root) { return undefined; } - let curr: HTMLElement = this.root.current; + let curr: HTMLElement = this.root; while (window.getComputedStyle(curr).getPropertyValue('background-color') === 'rgba(0, 0, 0, 0)' || window.getComputedStyle(curr).getPropertyValue('background-color') === 'transparent') { From e04d2a79bdd578eff7db93edbcad2ddf846b97a9 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Wed, 2 May 2018 16:15:39 -0700 Subject: [PATCH 39/43] Fix order of public/private in Sticky --- .../office-ui-fabric-react/src/components/Sticky/Sticky.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx index 0adb875eabd1c7..963e7a8aca6fb8 100644 --- a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx +++ b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx @@ -33,11 +33,11 @@ export class Sticky extends BaseComponent { } }; + public distanceFromTop: number; private _root = createRef(); private _stickyContentTop = createRef(); private _stickyContentBottom = createRef(); private _nonStickyContent = createRef(); - public distanceFromTop: number; constructor(props: IStickyProps) { super(props); From 00a8b449e96156c58d6725c0af932e70166a0983 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Wed, 2 May 2018 16:49:57 -0700 Subject: [PATCH 40/43] Set width on stickyabove/below instead of Sticky component itself. --- .../components/ScrollablePane/ScrollablePane.base.tsx | 3 ++- .../src/components/Sticky/Sticky.tsx | 11 ++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index ede89b106b9a46..f7433fb28c273a 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -377,7 +377,8 @@ export class ScrollablePaneBase extends BaseComponent { return { - height: height + height: height, + width: this.contentContainer ? this.contentContainer.clientWidth : '100%' }; } } \ No newline at end of file diff --git a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx index 963e7a8aca6fb8..3e729beac019ba 100644 --- a/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx +++ b/packages/office-ui-fabric-react/src/components/Sticky/Sticky.tsx @@ -155,13 +155,10 @@ export class Sticky extends BaseComponent { this.distanceFromTop = this._getNonStickyDistanceFromTop(container); } - private _getContentStyles(isSticky: boolean): React.CSSProperties | undefined { - if (this.root) { - return { - backgroundColor: this.props.stickyBackgroundColor || this._getBackground(), - width: isSticky ? this.root.offsetWidth : 'auto' - }; - } + private _getContentStyles(isSticky: boolean): React.CSSProperties { + return { + backgroundColor: this.props.stickyBackgroundColor || this._getBackground() + }; } private _getStickyPlaceholderHeight(isSticky: boolean): React.CSSProperties { From b49fa9058fa9d19108830b4b4d0c64691902db8f Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Thu, 3 May 2018 16:31:59 -0700 Subject: [PATCH 41/43] Get rid of maxheight styles. Add throttle to scroll event. Change nonStickyPlaceholder to use position absolute instead of display block/none. --- .../ScrollablePane/ScrollablePane.base.tsx | 2 +- .../ScrollablePane/ScrollablePane.styles.ts | 28 ++++++++----------- .../src/components/Sticky/Sticky.tsx | 16 +++++++---- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx index f7433fb28c273a..3289ebc2a7a77e 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/ScrollablePane.base.tsx @@ -84,7 +84,7 @@ export class ScrollablePaneBase extends BaseComponent { private _getNonStickyPlaceholderHeight(): React.CSSProperties { const { isStickyTop, isStickyBottom, } = this.state; - const height = this.nonStickyContent ? this.nonStickyContent.offsetHeight : 0; - - return { - display: isStickyTop || isStickyBottom ? 'block' : 'none', - height: height - }; + if (isStickyTop || isStickyBottom) { + const height = this.nonStickyContent ? this.nonStickyContent.offsetHeight : 0; + return { + height: height + }; + } else { + return { + position: 'absolute' + }; + } } private _onScrollEvent = (container: HTMLElement, footerStickyContainer: HTMLElement): void => { From c5b0ef3f3ad2203122c5db551dcee269947be8e7 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Thu, 3 May 2018 16:35:44 -0700 Subject: [PATCH 42/43] Update Do's --- .../src/components/ScrollablePane/docs/ScrollablePaneDos.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/office-ui-fabric-react/src/components/ScrollablePane/docs/ScrollablePaneDos.md b/packages/office-ui-fabric-react/src/components/ScrollablePane/docs/ScrollablePaneDos.md index 895026b77cd2a2..6ed1153a059689 100644 --- a/packages/office-ui-fabric-react/src/components/ScrollablePane/docs/ScrollablePaneDos.md +++ b/packages/office-ui-fabric-react/src/components/ScrollablePane/docs/ScrollablePaneDos.md @@ -1,4 +1,4 @@ -- ScrollablePane uses `position: absolute`. Ensure that the parent element has an explicit height, or has space already allocated for ScrollablePane (e.g: flexbox). +- ScrollablePane uses `position: absolute`. Ensure that the parent element has an explicit `height` and `position: relative`, or has space already allocated for ScrollablePane (e.g: flexbox). - Use Sticky component on block level elements - Sticky component are ideally section headers and/or footers - Ensure that the total height of Sticky components do not exceed the height of the ScrollablePane \ No newline at end of file From f37feb87e2e40bd61798b6755835b912c1d75049 Mon Sep 17 00:00:00 2001 From: Eddie Liu Date: Thu, 3 May 2018 17:04:44 -0700 Subject: [PATCH 43/43] Add change file --- ...wl-fixScrollablePaneBehavior_2018-05-04-00-03.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 common/changes/office-ui-fabric-react/edwl-fixScrollablePaneBehavior_2018-05-04-00-03.json diff --git a/common/changes/office-ui-fabric-react/edwl-fixScrollablePaneBehavior_2018-05-04-00-03.json b/common/changes/office-ui-fabric-react/edwl-fixScrollablePaneBehavior_2018-05-04-00-03.json new file mode 100644 index 00000000000000..90b27657cf1bc3 --- /dev/null +++ b/common/changes/office-ui-fabric-react/edwl-fixScrollablePaneBehavior_2018-05-04-00-03.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "office-ui-fabric-react", + "comment": "ScrollablePane: Optimizations on how component functions. Change positioning from inheriting height/maxHeight of parent element to use position: absolute", + "type": "minor" + } + ], + "packageName": "office-ui-fabric-react", + "email": "edwl@microsoft.com" +} \ No newline at end of file