You've already forked matrix-react-sdk
							
							
				mirror of
				https://github.com/matrix-org/matrix-react-sdk.git
				synced 2025-11-04 11:51:45 +03:00 
			
		
		
		
	Convert Resizer to Typescript and create a Percentage based sizer
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
		
							
								
								
									
										178
									
								
								src/resizer/resizer.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								src/resizer/resizer.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,178 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2018 New Vector Ltd
 | 
			
		||||
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
classNames:
 | 
			
		||||
    // class on resize-handle
 | 
			
		||||
    handle: string
 | 
			
		||||
    // class on resize-handle
 | 
			
		||||
    reverse: string
 | 
			
		||||
    // class on resize-handle
 | 
			
		||||
    vertical: string
 | 
			
		||||
    // class on container
 | 
			
		||||
    resizing: string
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import FixedDistributor from "./distributors/fixed";
 | 
			
		||||
import Sizer from "./sizer";
 | 
			
		||||
import ResizeItem from "./item";
 | 
			
		||||
 | 
			
		||||
interface IClassNames {
 | 
			
		||||
    handle?: string;
 | 
			
		||||
    reverse?: string;
 | 
			
		||||
    vertical?: string;
 | 
			
		||||
    resizing?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IConfig {
 | 
			
		||||
    onResizeStart?(): void;
 | 
			
		||||
    onResizeStop?(): void;
 | 
			
		||||
    onResized?(size: number, id: string, element: HTMLElement): void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default class Resizer<C extends IConfig = IConfig> {
 | 
			
		||||
    private classNames: IClassNames;
 | 
			
		||||
 | 
			
		||||
    // TODO move vertical/horizontal to config option/container class
 | 
			
		||||
    // as it doesn't make sense to mix them within one container/Resizer
 | 
			
		||||
    constructor(
 | 
			
		||||
        private readonly container: HTMLElement,
 | 
			
		||||
        private readonly distributorCtor: {
 | 
			
		||||
            new(item: ResizeItem): FixedDistributor<C, any>;
 | 
			
		||||
            createItem(resizeHandle: HTMLDivElement, resizer: Resizer, sizer: Sizer): ResizeItem;
 | 
			
		||||
            createSizer(containerElement: HTMLElement, vertical: boolean, reverse: boolean): Sizer;
 | 
			
		||||
        },
 | 
			
		||||
        public readonly config?: C,
 | 
			
		||||
    ) {
 | 
			
		||||
        if (!container) {
 | 
			
		||||
            throw new Error("Resizer requires a non-null `container` arg");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.classNames = {
 | 
			
		||||
            handle: "resizer-handle",
 | 
			
		||||
            reverse: "resizer-reverse",
 | 
			
		||||
            vertical: "resizer-vertical",
 | 
			
		||||
            resizing: "resizer-resizing",
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public setClassNames(classNames: IClassNames) {
 | 
			
		||||
        this.classNames = classNames;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public attach() {
 | 
			
		||||
        this.container.addEventListener("mousedown", this.onMouseDown, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public detach() {
 | 
			
		||||
        this.container.removeEventListener("mousedown", this.onMouseDown, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
    Gives the distributor for a specific resize handle, as if you would have started
 | 
			
		||||
    to drag that handle. Can be used to manipulate the size of an item programmatically.
 | 
			
		||||
    @param {number} handleIndex the index of the resize handle in the container
 | 
			
		||||
    @return {Distributor} a new distributor for the given handle
 | 
			
		||||
    */
 | 
			
		||||
    public forHandleAt(handleIndex: number): FixedDistributor<C> {
 | 
			
		||||
        const handles = this.getResizeHandles();
 | 
			
		||||
        const handle = handles[handleIndex];
 | 
			
		||||
        if (handle) {
 | 
			
		||||
            const {distributor} = this.createSizerAndDistributor(<HTMLDivElement>handle);
 | 
			
		||||
            return distributor;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public forHandleWithId(id: string): FixedDistributor<C> {
 | 
			
		||||
        const handles = this.getResizeHandles();
 | 
			
		||||
        const handle = handles.find((h) => h.getAttribute("data-id") === id);
 | 
			
		||||
        if (handle) {
 | 
			
		||||
            const {distributor} = this.createSizerAndDistributor(<HTMLDivElement>handle);
 | 
			
		||||
            return distributor;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public isReverseResizeHandle(el: HTMLElement): boolean {
 | 
			
		||||
        return el && el.classList.contains(this.classNames.reverse);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public isResizeHandle(el: HTMLElement): boolean {
 | 
			
		||||
        return el && el.classList.contains(this.classNames.handle);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private onMouseDown = (event: MouseEvent) => {
 | 
			
		||||
        // use closest in case the resize handle contains
 | 
			
		||||
        // child dom nodes that can be the target
 | 
			
		||||
        const resizeHandle = event.target && (<HTMLElement>event.target).closest(`.${this.classNames.handle}`);
 | 
			
		||||
        if (!resizeHandle || resizeHandle.parentElement !== this.container) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // prevent starting a drag operation
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
 | 
			
		||||
        // mark as currently resizing
 | 
			
		||||
        if (this.classNames.resizing) {
 | 
			
		||||
            this.container.classList.add(this.classNames.resizing);
 | 
			
		||||
        }
 | 
			
		||||
        if (this.config.onResizeStart) {
 | 
			
		||||
            this.config.onResizeStart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const {sizer, distributor} = this.createSizerAndDistributor(<HTMLDivElement>resizeHandle);
 | 
			
		||||
        distributor.start();
 | 
			
		||||
 | 
			
		||||
        const onMouseMove = (event) => {
 | 
			
		||||
            const offset = sizer.offsetFromEvent(event);
 | 
			
		||||
            distributor.resizeFromContainerOffset(offset);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        const body = document.body;
 | 
			
		||||
        const finishResize = () => {
 | 
			
		||||
            if (this.classNames.resizing) {
 | 
			
		||||
                this.container.classList.remove(this.classNames.resizing);
 | 
			
		||||
            }
 | 
			
		||||
            if (this.config.onResizeStop) {
 | 
			
		||||
                this.config.onResizeStop();
 | 
			
		||||
            }
 | 
			
		||||
            distributor.finish();
 | 
			
		||||
            body.removeEventListener("mouseup", finishResize, false);
 | 
			
		||||
            document.removeEventListener("mouseleave", finishResize, false);
 | 
			
		||||
            body.removeEventListener("mousemove", onMouseMove, false);
 | 
			
		||||
        };
 | 
			
		||||
        body.addEventListener("mouseup", finishResize, false);
 | 
			
		||||
        document.addEventListener("mouseleave", finishResize, false);
 | 
			
		||||
        body.addEventListener("mousemove", onMouseMove, false);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private createSizerAndDistributor(
 | 
			
		||||
        resizeHandle: HTMLDivElement,
 | 
			
		||||
    ): {sizer: Sizer, distributor: FixedDistributor<any>} {
 | 
			
		||||
        const vertical = resizeHandle.classList.contains(this.classNames.vertical);
 | 
			
		||||
        const reverse = this.isReverseResizeHandle(resizeHandle);
 | 
			
		||||
        const Distributor = this.distributorCtor;
 | 
			
		||||
        const sizer = Distributor.createSizer(this.container, vertical, reverse);
 | 
			
		||||
        const item = Distributor.createItem(resizeHandle, this, sizer);
 | 
			
		||||
        const distributor = new Distributor(item);
 | 
			
		||||
        return {sizer, distributor};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private getResizeHandles() {
 | 
			
		||||
        return Array.from(this.container.children).filter(el => {
 | 
			
		||||
            return this.isResizeHandle(<HTMLElement>el);
 | 
			
		||||
        }) as HTMLElement[];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user