UNPKG

bitandblack-rows

Version:

A small and simple CSS gutter to create rows and cells using the flexbox model.

252 lines (213 loc) 7.5 kB
/** * Bit&Black Rows * * @copyright Copyright (c) Bit&Black * @author Tobias Köngeter <hello@bitandblack.com> * @link https://www.bitandblack.com */ /** * Receiving information about the cell positions in the grid. */ class Position { private _resizeObserver: ResizeObserver = null; private _addCssClassesForOutsideCells: boolean = true; private _addDataAttributesAboutCellPositions: boolean = false; private _cssClassFirstOfRow: string = "row__cell--first-of-row"; private _cssClassLastOfRow: string = "row__cell--last-of-row"; private _cssClassFirstOfColumn: string = "row__cell--first-of-column"; private _cssClassLastOfColumn: string = "row__cell--last-of-column"; public constructor() { this.resizeObserverCallback = this.resizeObserverCallback.bind(this); this._resizeObserver = new ResizeObserver( this.resizeObserverCallback ); } /** * Add a rows-container element. * * @param element {HTMLElement} * @return self */ public add(element: HTMLElement): this { this._resizeObserver.observe(element); return this; } /** * Removes a rows-container element from observing. * * @param element {HTMLElement} * @return self */ public remove(element: HTMLElement): this { this._resizeObserver.unobserve(element); this.removeElement(element); return this; } /** * Tells if adding CSS classes to outside laying cells has been enabled or disabled. */ public addCssClassesForOutsideCells(): boolean { return this._addCssClassesForOutsideCells; } /** * Enable or disable adding CSS classes to outside laying cells. * * @param addCssClassesForOutsideCells {boolean} */ public setAddCssClassesForOutsideCells(addCssClassesForOutsideCells: boolean): this { this._addCssClassesForOutsideCells = addCssClassesForOutsideCells; return this; } /** * Tells if adding data attributes to each cell with information about its position has been enabled or disabled. */ public addDataAttributesAboutCellPositions(): boolean { return this._addDataAttributesAboutCellPositions; } /** * Enable or disable adding data attributes to each cell with information about its position. * * @param addDataAttributesAboutCellPositions {boolean} */ public setAddDataAttributesAboutCellPositions(addDataAttributesAboutCellPositions: boolean): this { this._addDataAttributesAboutCellPositions = addDataAttributesAboutCellPositions; return this; } /** * @return {string} */ public getCssClassFirstOfRow(): string { return this._cssClassFirstOfRow; } /** * @param cssClassFirstOfRow {string} * @return self */ public setCssClassFirstOfRow(cssClassFirstOfRow: string): this { this._cssClassFirstOfRow = cssClassFirstOfRow; return this; } /** * @return {string} */ public getCssClassLastOfRow(): string { return this._cssClassLastOfRow; } /** * @param cssClassLastOfRow {string} * @return self */ public setCssClassLastOfRow(cssClassLastOfRow: string): this { this._cssClassLastOfRow = cssClassLastOfRow; return this; } /** * @return {string} */ public getCssClassFirstOfColumn(): string { return this._cssClassFirstOfColumn; } /** * @param cssClassFirstOfColumn {string} * @return self */ public setCssClassFirstOfColumn(cssClassFirstOfColumn: string): this { this._cssClassFirstOfColumn = cssClassFirstOfColumn; return this; } /** * @return {string} */ public getCssClassLastOfColumn(): string { return this._cssClassLastOfColumn; } /** * @param cssClassLastOfColumn {string} * @return self */ public setCssClassLastOfColumn(cssClassLastOfColumn: string): this { this._cssClassLastOfColumn = cssClassLastOfColumn; return this; } /** * @param resizeObserverEntries {ResizeObserverEntry[]} * @private */ private resizeObserverCallback(resizeObserverEntries: ResizeObserverEntry[]): void { for (const resizeObserverEntry of resizeObserverEntries) { this.handleEntry(resizeObserverEntry); } }; /** * @param resizeObserverEntry {ResizeObserverEntry} * @private */ private handleEntry(resizeObserverEntry: ResizeObserverEntry): void { const rowElement: HTMLElement = resizeObserverEntry.target as HTMLElement; const rowCells: HTMLElement[] = Array.from(rowElement.children) as HTMLElement[]; let columnCounter = 0; let rowCounter = 0; for (const [index, rowCell] of Object.entries(rowCells)) { const rowCellIndex = Number.parseInt(index); const rowCellFirst: HTMLElement = rowCells[0]; const rowCellPrevious: HTMLElement = rowCells[rowCellIndex - 1]; const rowCellNext: HTMLElement = rowCells[rowCellIndex + 1]; const rowCellLast: HTMLElement = rowCells[rowCells.length - 1]; const isFirstOfRow = !rowCellPrevious || rowCell.offsetTop !== rowCellPrevious.offsetTop; const isLastOfRow = !rowCellNext || rowCell.offsetTop !== rowCellNext.offsetTop; const isFirstOfColumn = rowCell.offsetTop === rowCellFirst.offsetTop; const isLastOfColumn = rowCell.offsetTop === rowCellLast.offsetTop; if (true === this.addCssClassesForOutsideCells()) { rowCell.classList.toggle( this.getCssClassFirstOfRow(), isFirstOfRow ); rowCell.classList.toggle( this.getCssClassLastOfRow(), isLastOfRow ); rowCell.classList.toggle( this.getCssClassFirstOfColumn(), isFirstOfColumn ); rowCell.classList.toggle( this.getCssClassLastOfColumn(), isLastOfColumn ); } if (true === this.addDataAttributesAboutCellPositions()) { rowCell.dataset.nthOfColumn = columnCounter.toString(); rowCell.dataset.nthOfRow = rowCounter.toString(); } ++columnCounter; if (isLastOfRow) { columnCounter = 0; ++rowCounter; } } } /** * @param rowElement {HTMLElement} * @private */ private removeElement(rowElement: HTMLElement): void { const rowCells: HTMLElement[] = Array.from(rowElement.children) as HTMLElement[]; for (const [, rowCell] of Object.entries(rowCells)) { rowCell.classList.remove( this.getCssClassFirstOfRow(), ); rowCell.classList.remove( this.getCssClassLastOfRow(), ); rowCell.classList.remove( this.getCssClassFirstOfColumn(), ); rowCell.classList.remove( this.getCssClassLastOfColumn(), ); delete rowCell.dataset.nthOfColumn; delete rowCell.dataset.nthOfRow; } } } export { Position };