-
-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(plugin): create new Custom Tooltip plugin
- Loading branch information
1 parent
ed6bc7c
commit 4c8c4f6
Showing
16 changed files
with
294 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
108 changes: 108 additions & 0 deletions
108
packages/common/src/extensions/slickCustomTooltipExtension.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import { CustomTooltipOption, GridOption, SlickDataView, SlickEventData, SlickEventHandler, SlickGrid, SlickNamespace } from '../interfaces/index'; | ||
import { getHtmlElementOffset, sanitizeTextByAvailableSanitizer } from '../services/utilities'; | ||
import { SharedService } from '../services/shared.service'; | ||
|
||
// using external SlickGrid JS libraries | ||
declare const Slick: SlickNamespace; | ||
|
||
export class SlickCustomTooltip { | ||
protected _addonOptions?: CustomTooltipOption; | ||
protected _defaultOptions = { | ||
className: 'slick-custom-tooltip', | ||
offsetLeft: 0, | ||
offsetTop: 5, | ||
hideArrow: false, | ||
} as CustomTooltipOption; | ||
protected _grid!: SlickGrid; | ||
protected _eventHandler: SlickEventHandler; | ||
|
||
constructor(protected readonly sharedService: SharedService) { | ||
this._eventHandler = new Slick.EventHandler(); | ||
} | ||
|
||
get addonOptions(): CustomTooltipOption | undefined { | ||
return this._addonOptions; | ||
} | ||
|
||
get className(): string { | ||
return this._addonOptions?.className ?? 'slick-custom-tooltip'; | ||
} | ||
get dataView(): SlickDataView { | ||
return this._grid.getData<SlickDataView>() || {}; | ||
} | ||
|
||
/** Getter for the Grid Options pulled through the Grid Object */ | ||
get gridOptions(): GridOption { | ||
return this._grid.getOptions() || {}; | ||
} | ||
|
||
/** Getter for the grid uid */ | ||
get gridUid(): string { | ||
return this._grid.getUID() || ''; | ||
} | ||
get gridUidSelector(): string { | ||
return this.gridUid ? `.${this.gridUid}` : ''; | ||
} | ||
|
||
init(grid: SlickGrid) { | ||
this._grid = grid; | ||
this._eventHandler | ||
.subscribe(grid.onMouseEnter, this.handleOnMouseEnter.bind(this) as EventListener) | ||
.subscribe(grid.onMouseLeave, this.handleOnMouseLeave.bind(this) as EventListener); | ||
} | ||
|
||
dispose() { | ||
this._eventHandler.unsubscribeAll(); | ||
} | ||
|
||
handleOnMouseEnter(e: SlickEventData) { | ||
if (this._grid && e) { | ||
const cell = this._grid.getCellFromEvent(e); | ||
if (cell) { | ||
const item = this.dataView.getItem(cell.row); | ||
const columnDef = this._grid.getColumns()[cell.cell]; | ||
if (item && columnDef) { | ||
this._addonOptions = { ...this._defaultOptions, ...(this.sharedService?.gridOptions?.customTooltip), ...(columnDef?.customTooltip) }; | ||
|
||
let showTooltip = true; | ||
if (typeof this._addonOptions?.usabilityOverride === 'function') { | ||
showTooltip = this._addonOptions.usabilityOverride({ cell: cell.cell, row: cell.row, dataContext: item, column: columnDef, grid: this._grid }); | ||
} | ||
|
||
if (showTooltip && typeof this._addonOptions?.formatter === 'function') { | ||
const itemValue = item.hasOwnProperty(columnDef.field) ? item[columnDef.field] : null; | ||
const value = sanitizeTextByAvailableSanitizer(this.gridOptions, itemValue); | ||
const tooltipText = this._addonOptions.formatter(cell.row, cell.cell, value, columnDef, item, this._grid); | ||
|
||
// create the tooltip DOM element with the text returned by the Formatter | ||
const tooltipElm = document.createElement('div'); | ||
tooltipElm.className = `${this.className} ${this.gridUid}`; | ||
tooltipElm.innerHTML = typeof tooltipText === 'object' ? tooltipText.text : tooltipText; | ||
document.body.appendChild(tooltipElm); | ||
|
||
// reposition the tooltip on top of the cell that triggered the mouse over event | ||
const cellPosition = getHtmlElementOffset(this._grid.getCellNode(cell.row, cell.cell)); | ||
tooltipElm.style.left = `${cellPosition.left}px`; | ||
tooltipElm.style.top = `${cellPosition.top - tooltipElm.clientHeight - (this._addonOptions?.offsetTop ?? 0)}px`; | ||
|
||
// user could optionally hide the tooltip arrow (we can simply update the CSS variables, that's the only way we have to update CSS pseudo) | ||
const root = document.documentElement; | ||
if (this._addonOptions?.hideArrow) { | ||
root.style.setProperty('--slick-tooltip-arrow-border-left', '0'); | ||
root.style.setProperty('--slick-tooltip-arrow-border-right', '0'); | ||
} | ||
if (this._addonOptions?.arrowMarginLeft) { | ||
const marginLeft = typeof this._addonOptions.arrowMarginLeft === 'string' ? this._addonOptions.arrowMarginLeft : `${this._addonOptions.arrowMarginLeft}px`; | ||
root.style.setProperty('--slick-tooltip-arrow-margin-left', marginLeft); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
handleOnMouseLeave() { | ||
const prevTooltip = document.body.querySelector(`.${this.className}${this.gridUidSelector}`); | ||
prevTooltip?.remove(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
35 changes: 35 additions & 0 deletions
35
packages/common/src/interfaces/customTooltipOption.interface.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { Column, Formatter, SlickGrid } from './index'; | ||
|
||
export interface CustomTooltipOption { | ||
/** | ||
* defaults to 25(px), left margin to display the arrow. | ||
* when a number is provided it will assume the value is in pixel, | ||
* or else we could also a string for example "50%" would show the arrow in the center. | ||
*/ | ||
arrowMarginLeft?: number | string; | ||
|
||
/** defaults to False, should we hide the tooltip pointer arrow? */ | ||
hideArrow?: boolean; | ||
|
||
/** defaults to "slick-custom-tooltip" */ | ||
className?: string; | ||
|
||
/** Formatter to execute for display the data that will show */ | ||
formatter: Formatter; | ||
|
||
/** defaults to 0, optional left offset, it must be a positive/negative number (in pixel) that will be added to the offset position calculation of the tooltip container. */ | ||
offsetLeft?: number; | ||
|
||
/** defaults to 0, optional top offset, it must be a positive/negative number (in pixel) that will be added to the offset position calculation of the tooltip container. */ | ||
offsetTop?: number; | ||
|
||
// -- | ||
// callback functions | ||
// ------------------- | ||
|
||
// -- | ||
// Methods | ||
|
||
/** Callback method that user can override the default behavior of showing the tooltip. If it returns False, then the tooltip won't show */ | ||
usabilityOverride?: (args: { cell: number; row: number; column: Column; dataContext: any; grid: SlickGrid; }) => boolean; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.