Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Merge pull request #6110 from matrix-org/gsouquet/sticky-header-sizing
Browse files Browse the repository at this point in the history
  • Loading branch information
germain-gg authored May 28, 2021
2 parents 4a0d43d + 650b683 commit 71b217e
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 11 deletions.
1 change: 1 addition & 0 deletions res/css/views/rooms/_RoomSublist.scss
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ limitations under the License.
&.mx_RoomSublist_headerContainer_sticky {
position: fixed;
height: 32px; // to match the header container
// width set by JS because of a compat issue between Firefox and Chrome
width: calc(100% - 15px);
}

Expand Down
2 changes: 2 additions & 0 deletions src/@types/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import TypingStore from "../stores/TypingStore";
import { EventIndexPeg } from "../indexing/EventIndexPeg";
import {VoiceRecordingStore} from "../stores/VoiceRecordingStore";
import PerformanceMonitor from "../performance";
import UIStore from "../stores/UIStore";

declare global {
interface Window {
Expand Down Expand Up @@ -82,6 +83,7 @@ declare global {
mxEventIndexPeg: EventIndexPeg;
mxPerformanceMonitor: PerformanceMonitor;
mxPerformanceEntryNames: any;
mxUIStore: UIStore;
}

interface Document {
Expand Down
31 changes: 30 additions & 1 deletion src/components/structures/LeftPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ const cssClasses = [

@replaceableComponent("structures.LeftPanel")
export default class LeftPanel extends React.Component<IProps, IState> {
private ref: React.RefObject<HTMLDivElement> = createRef();
private listContainerRef: React.RefObject<HTMLDivElement> = createRef();
private groupFilterPanelWatcherRef: string;
private bgImageWatcherRef: string;
Expand All @@ -93,13 +94,26 @@ export default class LeftPanel extends React.Component<IProps, IState> {
});
}

public componentDidMount() {
UIStore.instance.trackElementDimensions("ListContainer", this.listContainerRef.current);
UIStore.instance.on("ListContainer", this.refreshStickyHeaders);
}

public componentWillUnmount() {
SettingsStore.unwatchSetting(this.groupFilterPanelWatcherRef);
SettingsStore.unwatchSetting(this.bgImageWatcherRef);
BreadcrumbsStore.instance.off(UPDATE_EVENT, this.onBreadcrumbsUpdate);
RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate);
OwnProfileStore.instance.off(UPDATE_EVENT, this.onBackgroundImageUpdate);
SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.updateActiveSpace);
UIStore.instance.stopTrackingElementDimensions("ListContainer");
UIStore.instance.removeListener("ListContainer", this.refreshStickyHeaders);
}

public componentDidUpdate(prevProps: IProps, prevState: IState): void {
if (prevState.activeSpace !== this.state.activeSpace) {
this.refreshStickyHeaders();
}
}

private updateActiveSpace = (activeSpace: Room) => {
Expand Down Expand Up @@ -245,10 +259,24 @@ export default class LeftPanel extends React.Component<IProps, IState> {
if (!header.classList.contains("mx_RoomSublist_headerContainer_sticky")) {
header.classList.add("mx_RoomSublist_headerContainer_sticky");
}

const listDimensions = UIStore.instance.getElementDimensions("ListContainer");
if (listDimensions) {
const headerRightMargin = 15; // calculated from margins and widths to align with non-sticky tiles
const headerStickyWidth = listDimensions.width - headerRightMargin;
const newWidth = `${headerStickyWidth}px`;
if (header.style.width !== newWidth) {
header.style.width = newWidth;
}
}
} else if (!style.stickyTop && !style.stickyBottom) {
if (header.classList.contains("mx_RoomSublist_headerContainer_sticky")) {
header.classList.remove("mx_RoomSublist_headerContainer_sticky");
}

if (header.style.width) {
header.style.removeProperty('width');
}
}
}

Expand Down Expand Up @@ -407,6 +435,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
onBlur={this.onBlur}
isMinimized={this.props.isMinimized}
activeSpace={this.state.activeSpace}
onListCollapse={this.refreshStickyHeaders}
/>;

const containerClasses = classNames({
Expand All @@ -420,7 +449,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
);

return (
<div className={containerClasses}>
<div className={containerClasses} ref={this.ref}>
{leftLeftPanel}
<aside className="mx_LeftPanel_roomListContainer">
{this.renderHeader()}
Expand Down
12 changes: 8 additions & 4 deletions src/components/structures/MatrixChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
private accountPasswordTimer?: NodeJS.Timeout;
private focusComposer: boolean;
private subTitleStatus: string;
private prevWindowWidth: number;

private readonly loggedInView: React.RefObject<LoggedInViewType>;
private readonly dispatcherRef: any;
Expand Down Expand Up @@ -277,6 +278,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
}
}

this.prevWindowWidth = UIStore.instance.windowWidth || 1000;
UIStore.instance.on(UI_EVENTS.Resize, this.handleResize);

this.pageChanging = false;
Expand Down Expand Up @@ -1821,13 +1823,15 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
const LHS_THRESHOLD = 1000;
const width = UIStore.instance.windowWidth;

if (width <= LHS_THRESHOLD && !this.state.collapseLhs) {
dis.dispatch({ action: 'hide_left_panel' });
}
if (width > LHS_THRESHOLD && this.state.collapseLhs) {
if (this.prevWindowWidth < LHS_THRESHOLD && width >= LHS_THRESHOLD) {
dis.dispatch({ action: 'show_left_panel' });
}

if (this.prevWindowWidth >= LHS_THRESHOLD && width < LHS_THRESHOLD) {
dis.dispatch({ action: 'hide_left_panel' });
}

this.prevWindowWidth = width;
this.state.resizeNotifier.notifyWindowResized();
};

Expand Down
2 changes: 2 additions & 0 deletions src/components/views/rooms/RoomList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ interface IProps {
onKeyDown: (ev: React.KeyboardEvent) => void;
onFocus: (ev: React.FocusEvent) => void;
onBlur: (ev: React.FocusEvent) => void;
onListCollapse?: (isExpanded: boolean) => void;
resizeNotifier: ResizeNotifier;
isMinimized: boolean;
activeSpace: Room;
Expand Down Expand Up @@ -538,6 +539,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
extraTiles={extraTiles}
resizeNotifier={this.props.resizeNotifier}
alwaysVisible={ALWAYS_VISIBLE_TAGS.includes(orderedTagId)}
onListCollapse={this.props.onListCollapse}
/>
});
}
Expand Down
4 changes: 4 additions & 0 deletions src/components/views/rooms/RoomSublist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ interface IProps {
alwaysVisible?: boolean;
resizeNotifier: ResizeNotifier;
extraTiles?: ReactComponentElement<typeof ExtraTile>[];
onListCollapse?: (isExpanded: boolean) => void;

// TODO: Account for https://github.com/vector-im/element-web/issues/14179
}
Expand Down Expand Up @@ -472,6 +473,9 @@ export default class RoomSublist extends React.Component<IProps, IState> {
private toggleCollapsed = () => {
this.layout.isCollapsed = this.state.isExpanded;
this.setState({isExpanded: !this.layout.isCollapsed});
if (this.props.onListCollapse) {
this.props.onListCollapse(!this.layout.isCollapsed)
}
};

private onHeaderKeyDown = (ev: React.KeyboardEvent) => {
Expand Down
51 changes: 45 additions & 6 deletions src/stores/UIStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ export enum UI_EVENTS {

export type ResizeObserverCallbackFunction = (entries: ResizeObserverEntry[]) => void;


export default class UIStore extends EventEmitter {
private static _instance: UIStore = null;

private resizeObserver: ResizeObserver;

private uiElementDimensions = new Map<string, DOMRectReadOnly>();
private trackedUiElements = new Map<Element, string>();

public windowWidth: number;
public windowHeight: number;

Expand Down Expand Up @@ -60,14 +62,51 @@ export default class UIStore extends EventEmitter {
}
}

public getElementDimensions(name: string): DOMRectReadOnly {
return this.uiElementDimensions.get(name);
}

public trackElementDimensions(name: string, element: Element): void {
this.trackedUiElements.set(element, name);
this.resizeObserver.observe(element);
}

public stopTrackingElementDimensions(name: string): void {
let trackedElement: Element;
this.trackedUiElements.forEach((trackedElementName, element) => {
if (trackedElementName === name) {
trackedElement = element;
}
});
if (trackedElement) {
this.resizeObserver.unobserve(trackedElement);
this.uiElementDimensions.delete(name);
this.trackedUiElements.delete(trackedElement);
}
}

public isTrackingElementDimensions(name: string): boolean {
return this.uiElementDimensions.has(name);
}

private resizeObserverCallback = (entries: ResizeObserverEntry[]) => {
const { width, height } = entries
.find(entry => entry.target === document.body)
.contentRect;
const windowEntry = entries.find(entry => entry.target === document.body);

this.windowWidth = width;
this.windowHeight = height;
if (windowEntry) {
this.windowWidth = windowEntry.contentRect.width;
this.windowHeight = windowEntry.contentRect.height;
}

entries.forEach(entry => {
const trackedElementName = this.trackedUiElements.get(entry.target);
if (trackedElementName) {
this.uiElementDimensions.set(trackedElementName, entry.contentRect);
this.emit(trackedElementName, UI_EVENTS.Resize, entry);
}
});

this.emit(UI_EVENTS.Resize, entries);
}
}

window.mxUIStore = UIStore.instance;

0 comments on commit 71b217e

Please sign in to comment.