feat(components): [table] overflow tooltip supports enterable and customization (#10984)

* feat(components): [table] overflow tooltip supports `enterable`

* fix(components): [table] fix modifiers merge

* fix(components): [table] refine logic & fix popperClass isn't respected

* docs(components): [table] add docs for `tooltip-options` & `show-overflow-tooltip`

* docs(components): [table]

* docs(components): [table] update version tag

Co-authored-by: Xc <124118265@qq.com>
This commit is contained in:
Zhongxiang Wang
2022-12-22 12:20:07 +08:00
committed by GitHub
parent 74e6e8d105
commit cf5847263f
10 changed files with 186 additions and 127 deletions

View File

@@ -231,44 +231,45 @@ table/table-layout
## Table Attributes
| Name | Description | Type | Accepted Values | Default |
| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | ------------------------------------ | ------------------------------------------------------------------------------ |
| data | Table data | array | — | — |
| height | Table's height. By default it has an `auto` height. If its value is a number, the height is measured in pixels; if its value is a string, the value will be assigned to element's style.height, the height is affected by external styles | string / number | — | — |
| max-height | Table's max-height. The legal value is a number or the height in px. | string / number | — | — |
| stripe | whether Table is striped | boolean | — | false |
| border | whether Table has vertical border | boolean | — | false |
| size | size of Table | string | large / default /small | — |
| fit | whether width of column automatically fits its container | boolean | — | true |
| show-header | whether Table header is visible | boolean | — | true |
| highlight-current-row | whether current row is highlighted | boolean | — | false |
| current-row-key | key of current row, a set only prop | string / number | — | — |
| row-class-name | function that returns custom class names for a row, or a string assigning class names for every row | function(\{ row, rowIndex \}) / string | — | — |
| row-style | function that returns custom style for a row, or an object assigning custom style for every row | function(\{ row, rowIndex \}) / object | — | — |
| cell-class-name | function that returns custom class names for a cell, or a string assigning class names for every cell | function(\{ row, column, rowIndex, columnIndex \}) / string | — | — |
| cell-style | function that returns custom style for a cell, or an object assigning custom style for every cell | function(\{ row, column, rowIndex, columnIndex \}) / object | — | — |
| header-row-class-name | function that returns custom class names for a row in table header, or a string assigning class names for every row in table header | function(\{ row, rowIndex }\) / string | — | — |
| header-row-style | function that returns custom style for a row in table header, or an object assigning custom style for every row in table header | function(\{ row, rowIndex \}) / object | — | — |
| header-cell-class-name | function that returns custom class names for a cell in table header, or a string assigning class names for every cell in table header | function(\{ row, column, rowIndex, columnIndex \}) / string | — | — |
| header-cell-style | function that returns custom style for a cell in table header, or an object assigning custom style for every cell in table header | function(\{ row, column, rowIndex, columnIndex \}) / object | — | — |
| row-key | key of row data, used for optimizing rendering. Required if `reserve-selection` is on or display tree data. When its type is String, multi-level access is supported, e.g. `user.info.id`, but `user.info[0].id` is not supported, in which case `Function` should be used. | function(row) / string | — | — |
| empty-text | Displayed text when data is empty. You can customize this area with `#empty` | string | — | No Data |
| default-expand-all | whether expand all rows by default, works when the table has a column type="expand" or contains tree structure data | boolean | — | false |
| expand-row-keys | set expanded rows by this prop, prop's value is the keys of expand rows, you should set row-key before using this prop | array | — | — |
| default-sort | set the default sort column and order. property `prop` is used to set default sort column, property `order` is used to set default sort order | object | (order: 'ascending' \| 'descending') | if `prop` is set, and `order` is not set, then `order` is default to ascending |
| tooltip-effect | tooltip `effect` property | string | dark / light | dark |
| show-summary | whether to display a summary row | boolean | — | false |
| sum-text | displayed text for the first column of summary row | string | — | Sum |
| summary-method | custom summary method | function(\{ columns, data \}) | — | — |
| span-method | method that returns rowspan and colspan | function(\{ row, column, rowIndex, columnIndex \}) | — | — |
| select-on-indeterminate | controls the behavior of master checkbox in multi-select tables when only some rows are selected (but not all). If true, all rows will be selected, else deselected. | boolean | — | true |
| indent | horizontal indentation of tree data | number | — | 16 |
| lazy | whether to lazy loading data | boolean | — | — |
| load | method for loading child row data, only works when `lazy` is true | function(row, treeNode, resolve) | — | — |
| tree-props | configuration for rendering nested data | object | — | `{ hasChildren: 'hasChildren', children: 'children' }` |
| table-layout | Sets the algorithm used to lay out table cells, rows, and columns | string | fixed / auto | fixed |
| scrollbar-always-on | always show scrollbar | boolean | — | false |
| flexible<VersionTag version="2.2.1" /> | ensure main axis minimum-size doesn't follow the content | boolean | — | false |
| Name | Description | Type | Accepted Values | Default |
| ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| data | Table data | array | — | — |
| height | Table's height. By default it has an `auto` height. If its value is a number, the height is measured in pixels; if its value is a string, the value will be assigned to element's style.height, the height is affected by external styles | string / number | — | — |
| max-height | Table's max-height. The legal value is a number or the height in px. | string / number | — | — |
| stripe | whether Table is striped | boolean | — | false |
| border | whether Table has vertical border | boolean | — | false |
| size | size of Table | string | large / default /small | — |
| fit | whether width of column automatically fits its container | boolean | — | true |
| show-header | whether Table header is visible | boolean | — | true |
| highlight-current-row | whether current row is highlighted | boolean | — | false |
| current-row-key | key of current row, a set only prop | string / number | — | — |
| row-class-name | function that returns custom class names for a row, or a string assigning class names for every row | function(\{ row, rowIndex \}) / string | — | — |
| row-style | function that returns custom style for a row, or an object assigning custom style for every row | function(\{ row, rowIndex \}) / object | — | — |
| cell-class-name | function that returns custom class names for a cell, or a string assigning class names for every cell | function(\{ row, column, rowIndex, columnIndex \}) / string | — | — |
| cell-style | function that returns custom style for a cell, or an object assigning custom style for every cell | function(\{ row, column, rowIndex, columnIndex \}) / object | — | — |
| header-row-class-name | function that returns custom class names for a row in table header, or a string assigning class names for every row in table header | function(\{ row, rowIndex }\) / string | — | — |
| header-row-style | function that returns custom style for a row in table header, or an object assigning custom style for every row in table header | function(\{ row, rowIndex \}) / object | — | — |
| header-cell-class-name | function that returns custom class names for a cell in table header, or a string assigning class names for every cell in table header | function(\{ row, column, rowIndex, columnIndex \}) / string | — | — |
| header-cell-style | function that returns custom style for a cell in table header, or an object assigning custom style for every cell in table header | function(\{ row, column, rowIndex, columnIndex \}) / object | — | — |
| row-key | key of row data, used for optimizing rendering. Required if `reserve-selection` is on or display tree data. When its type is String, multi-level access is supported, e.g. `user.info.id`, but `user.info[0].id` is not supported, in which case `Function` should be used. | function(row) / string | — | — |
| empty-text | Displayed text when data is empty. You can customize this area with `#empty` | string | — | No Data |
| default-expand-all | whether expand all rows by default, works when the table has a column type="expand" or contains tree structure data | boolean | — | false |
| expand-row-keys | set expanded rows by this prop, prop's value is the keys of expand rows, you should set row-key before using this prop | array | — | — |
| default-sort | set the default sort column and order. property `prop` is used to set default sort column, property `order` is used to set default sort order | object | (order: 'ascending' \| 'descending') | if `prop` is set, and `order` is not set, then `order` is default to ascending |
| tooltip-effect | the `effect` of the overflow tooltip | string | dark / light | dark |
| tooltip-options<VersionTag version="2.2.28" /> | the options for the overflow tooltip, [see the following tooltip component](tooltip.html#attributes) | ^[object]`Pick<ElTooltipProps, 'effect' \| 'enterable' \| 'hideAfter' \| 'offset' \| 'placement' \| 'popperClass' \| 'popperOptions' \| 'showAfter' \| 'showArrow'>` | [refer to tooltip](tooltip.html#attributes) | ^[object]`{ enterable: true, placement: 'top', showArrow: true, hideAfter: 200, popperOptions: { strategy: 'fixed' } }` |
| show-summary | whether to display a summary row | boolean | — | false |
| sum-text | displayed text for the first column of summary row | string | — | Sum |
| summary-method | custom summary method | function(\{ columns, data \}) | — | — |
| span-method | method that returns rowspan and colspan | function(\{ row, column, rowIndex, columnIndex \}) | | — |
| select-on-indeterminate | controls the behavior of master checkbox in multi-select tables when only some rows are selected (but not all). If true, all rows will be selected, else deselected. | boolean | — | true |
| indent | horizontal indentation of tree data | number | — | 16 |
| lazy | whether to lazy loading data | boolean | — | — |
| load | method for loading child row data, only works when `lazy` is true | function(row, treeNode, resolve) | — | — |
| tree-props | configuration for rendering nested data | object | | `{ hasChildren: 'hasChildren', children: 'children' }` |
| table-layout | Sets the algorithm used to lay out table cells, rows, and columns | string | fixed / auto | fixed |
| scrollbar-always-on | always show scrollbar | boolean | — | false |
| flexible<VersionTag version="2.2.1" /> | ensure main axis minimum-size doesn't follow the content | boolean | — | false |
## Table Events
@@ -321,35 +322,35 @@ table/table-layout
## Table-column Attributes
| Name | Description | Type | Accepted Values | Default |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- |
| type | type of the column. If set to `selection`, the column will display checkbox. If set to `index`, the column will display index of the row (staring from 1). If set to `expand`, the column will display expand icon. | string | selection / index / expand | — |
| index | customize indices for each row, works on columns with `type=index` | number / function(index) | — | — |
| label | column label | string | — | — |
| column-key | column's key. If you need to use the filter-change event, you need this attribute to identify which column is being filtered | string | — | — |
| prop | field name. You can also use its alias: `property` | string | — | — |
| width | column width | string / number | — | — |
| min-width | column minimum width. Columns with `width` has a fixed width, while columns with `min-width` has a width that is distributed in proportion | string / number | — | — |
| fixed | whether column is fixed at left / right. Will be fixed at left if `true` | string / boolean | true / 'left' / 'right' | — |
| render-header | render function for table header of this column | function(\{ column, $index \}) | — | — |
| sortable | whether column can be sorted. Remote sorting can be done by setting this attribute to 'custom' and listening to the `sort-change` event of Table | boolean / string | custom | false |
| sort-method | sorting method, works when `sortable` is `true`. Should return a number, just like Array.sort | function(a, b) | — | — |
| sort-by | specify which property to sort by, works when `sortable` is `true` and `sort-method` is `undefined`. If set to an Array, the column will sequentially sort by the next property if the previous one is equal | function(row, index) / string / array | — | — |
| sort-orders | the order of the sorting strategies used when sorting the data, works when `sortable` is `true`. Accepts an array, as the user clicks on the header, the column is sorted in order of the elements in the array | array | (the elements in the array need to be one of the following: `ascending`, `descending` and `null` restores to the original order) | ['ascending', 'descending', null] |
| resizable | whether column width can be resized, works when `border` of `el-table` is `true` | boolean | — | true |
| formatter | function that formats cell content | function(row, column, cellValue, index) | — | — |
| show-overflow-tooltip | whether to hide extra content and show them in a tooltip when hovering on the cell | boolean | — | false |
| align | alignment | string | left / center / right | left |
| header-align | alignment of the table header. If omitted, the value of the above `align` attribute will be applied | string | left / center / right | — |
| class-name | class name of cells in the column | string | — | — |
| label-class-name | class name of the label of this column | string | — | — |
| selectable | function that determines if a certain row can be selected, works when `type` is 'selection' | function(row, index) | — | — |
| reserve-selection | whether to reserve selection after data refreshing, works when `type` is 'selection'. Note that `row-key` is required for this to work | boolean | — | false |
| filters | an array of data filtering options. For each element in this array, `text` and `value` are required | `Array<{text: string, value: string}>` | — | — |
| filter-placement | placement for the filter dropdown | string | top / top-start / top-end / bottom / bottom-start / bottom-end / left / left-start / left-end / right / right-start / right-end | — |
| filter-multiple | whether data filtering supports multiple options | boolean | — | true |
| filter-method | data filtering method. If `filter-multiple` is on, this method will be called multiple times for each row, and a row will display if one of the calls returns `true` | function(value, row, column) | — | — |
| filtered-value | filter value for selected data, might be useful when table header is rendered with `render-header` | array | — | — |
| Name | Description | Type | Accepted Values | Default |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- |
| type | type of the column. If set to `selection`, the column will display checkbox. If set to `index`, the column will display index of the row (staring from 1). If set to `expand`, the column will display expand icon. | string | selection / index / expand | — |
| index | customize indices for each row, works on columns with `type=index` | number / function(index) | — | — |
| label | column label | string | — | — |
| column-key | column's key. If you need to use the filter-change event, you need this attribute to identify which column is being filtered | string | — | — |
| prop | field name. You can also use its alias: `property` | string | — | — |
| width | column width | string / number | — | — |
| min-width | column minimum width. Columns with `width` has a fixed width, while columns with `min-width` has a width that is distributed in proportion | string / number | — | — |
| fixed | whether column is fixed at left / right. Will be fixed at left if `true` | string / boolean | true / 'left' / 'right' | — |
| render-header | render function for table header of this column | function(\{ column, $index \}) | — | — |
| sortable | whether column can be sorted. Remote sorting can be done by setting this attribute to 'custom' and listening to the `sort-change` event of Table | boolean / string | custom | false |
| sort-method | sorting method, works when `sortable` is `true`. Should return a number, just like Array.sort | function(a, b) | — | — |
| sort-by | specify which property to sort by, works when `sortable` is `true` and `sort-method` is `undefined`. If set to an Array, the column will sequentially sort by the next property if the previous one is equal | function(row, index) / string / array | — | — |
| sort-orders | the order of the sorting strategies used when sorting the data, works when `sortable` is `true`. Accepts an array, as the user clicks on the header, the column is sorted in order of the elements in the array | array | (the elements in the array need to be one of the following: `ascending`, `descending` and `null` restores to the original order) | ['ascending', 'descending', null] |
| resizable | whether column width can be resized, works when `border` of `el-table` is `true` | boolean | — | true |
| formatter | function that formats cell content | function(row, column, cellValue, index) | — | — |
| show-overflow-tooltip | whether to hide extra content and show them in a tooltip when hovering on the cell | boolean \| [`object`](#table-attributes)<VersionTag version="2.2.28" /> | Refer to table [tooltip-options](#table-attributes) | |
| align | alignment | string | left / center / right | left |
| header-align | alignment of the table header. If omitted, the value of the above `align` attribute will be applied | string | left / center / right | — |
| class-name | class name of cells in the column | string | — | — |
| label-class-name | class name of the label of this column | string | — | — |
| selectable | function that determines if a certain row can be selected, works when `type` is 'selection' | function(row, index) | — | — |
| reserve-selection | whether to reserve selection after data refreshing, works when `type` is 'selection'. Note that `row-key` is required for this to work | boolean | — | false |
| filters | an array of data filtering options. For each element in this array, `text` and `value` are required | `Array<{text: string, value: string}>` | — | — |
| filter-placement | placement for the filter dropdown | string | top / top-start / top-end / bottom / bottom-start / bottom-end / left / left-start / left-end / right / right-start / right-end | — |
| filter-multiple | whether data filtering supports multiple options | boolean | — | true |
| filter-method | data filtering method. If `filter-multiple` is on, this method will be called multiple times for each row, and a row will display if one of the calls returns `true` | function(value, row, column) | — | — |
| filtered-value | filter value for selected data, might be useful when table header is rendered with `render-header` | array | — | — |
## Table-column Slots

View File

@@ -160,14 +160,6 @@ describe('table column', () => {
wrapper.unmount()
})
it('show-tooltip-when-overflow', async () => {
// old version prop name
const wrapper = createTable('show-tooltip-when-overflow')
await doubleWait()
expect(wrapper.findAll('.el-tooltip').length).toEqual(5)
wrapper.unmount()
})
it('align', async () => {
const wrapper = createTable(
'align="left"',

View File

@@ -7,6 +7,7 @@ import type {
DefaultRow,
Table,
} from '../table/defaults'
import type { TableOverflowTooltipOptions } from '../util'
interface TableBodyProps<T> {
store: Store<T>
@@ -16,7 +17,8 @@ interface TableBodyProps<T> {
rowStyle: ColumnStyle<T>
fixed: string
highlight: boolean
tooltipEffect: string
tooltipEffect?: string
tooltipOptions?: TableOverflowTooltipOptions
}
const defaultProps = {
@@ -26,6 +28,9 @@ const defaultProps = {
},
stripe: Boolean,
tooltipEffect: String,
tooltipOptions: {
type: Object as PropType<TableBodyProps<DefaultRow>['tooltipOptions']>,
},
context: {
default: () => ({}),
type: Object as PropType<TableBodyProps<DefaultRow>['context']>,

View File

@@ -6,6 +6,7 @@ import { createTablePopper, getCell, getColumnByCell } from '../util'
import { TABLE_INJECTION_KEY } from '../tokens'
import type { TableColumnCtx } from '../table-column/defaults'
import type { TableBodyProps } from './defaults'
import type { TableOverflowTooltipOptions } from '../util'
function useEvents<T>(props: Partial<TableBodyProps<T>>) {
const parent = inject(TABLE_INJECTION_KEY)
@@ -49,7 +50,7 @@ function useEvents<T>(props: Partial<TableBodyProps<T>>) {
const handleCellMouseEnter = (
event: MouseEvent,
row: T,
tooltipEffect: string
tooltipOptions: TableOverflowTooltipOptions
) => {
const table = parent
const cell = getCell(event)
@@ -72,6 +73,10 @@ function useEvents<T>(props: Partial<TableBodyProps<T>>) {
)
}
if (!tooltipOptions) {
return
}
// 判断是否text-overflow, 如果是就显示tooltip
const cellChild = (event.target as HTMLElement).querySelector(
'.cell'
@@ -107,11 +112,7 @@ function useEvents<T>(props: Partial<TableBodyProps<T>>) {
parent?.refs.tableWrapper,
cell,
cell.innerText || cell.textContent,
{
placement: 'top',
strategy: 'fixed',
},
tooltipEffect
tooltipOptions
)
}
}

View File

@@ -1,5 +1,6 @@
// @ts-nocheck
import { computed, h, inject } from 'vue'
import { merge } from 'lodash-unified'
import { useNamespace } from '@element-plus/hooks'
import { getRowIdentity } from '../util'
import { TABLE_INJECTION_KEY } from '../tokens'
@@ -48,7 +49,7 @@ function useRender<T>(props: Partial<TableBodyProps<T>>) {
treeRowData?: TreeNode,
expanded = false
) => {
const { tooltipEffect, store } = props
const { tooltipEffect, tooltipOptions, store } = props
const { indent, columns } = store.states
const rowClasses = getRowClass(row, $index)
let display = true
@@ -112,6 +113,15 @@ function useRender<T>(props: Partial<TableBodyProps<T>>) {
const baseKey = `${$index},${cellIndex}`
const patchKey = columnData.columnKey || columnData.rawColumnKey || ''
const tdChildren = cellChildren(cellIndex, column, data)
const mergedTooltipOptions =
column.showOverflowTooltip &&
merge(
{
effect: tooltipEffect,
},
tooltipOptions,
column.showOverflowTooltip
)
return h(
'td',
{
@@ -121,7 +131,7 @@ function useRender<T>(props: Partial<TableBodyProps<T>>) {
rowspan,
colspan,
onMouseenter: ($event) =>
handleCellMouseEnter($event, row, tooltipEffect),
handleCellMouseEnter($event, row, mergedTooltipOptions),
onMouseleave: handleCellMouseLeave,
},
[tdChildren]

View File

@@ -1,6 +1,7 @@
// @ts-nocheck
import type { ComponentInternalInstance, PropType, Ref, VNode } from 'vue'
import type { DefaultRow, Table } from '../table/defaults'
import type { TableOverflowTooltipOptions } from '../util'
type CI<T> = { column: TableColumnCtx<T>; $index: number }
@@ -33,8 +34,7 @@ interface TableColumnCtx<T> {
rawColumnKey: string
align: string
headerAlign: string
showTooltipWhenOverflow: boolean
showOverflowTooltip: boolean
showOverflowTooltip?: boolean | TableOverflowTooltipOptions
fixed: boolean | string
formatter: (
row: T,
@@ -113,8 +113,9 @@ export default {
columnKey: String,
align: String,
headerAlign: String,
showTooltipWhenOverflow: Boolean,
showOverflowTooltip: Boolean,
showOverflowTooltip: [Boolean, Object] as PropType<
TableColumnCtx<DefaultRow>['showOverflowTooltip']
>,
fixed: [Boolean, String],
formatter: Function as PropType<TableColumnCtx<DefaultRow>['formatter']>,
selectable: Function as PropType<TableColumnCtx<DefaultRow>['selectable']>,

View File

@@ -73,8 +73,7 @@ export default defineComponent({
property: props.prop || props.property,
align: realAlign,
headerAlign: realHeaderAlign,
showOverflowTooltip:
props.showOverflowTooltip || props.showTooltipWhenOverflow,
showOverflowTooltip: props.showOverflowTooltip,
// filter 相关属性
filterable: props.filters || props.filterMethod,
filteredValue: [],

View File

@@ -92,6 +92,7 @@
:highlight="highlightCurrentRow"
:row-class-name="rowClassName"
:tooltip-effect="tooltipEffect"
:tooltip-options="tooltipOptions"
:row-style="rowStyle"
:store="store"
:stripe="stripe"

View File

@@ -10,6 +10,7 @@ import type { Nullable } from '@element-plus/utils'
import type { Store } from '../store'
import type { TableColumnCtx } from '../table-column/defaults'
import type TableLayout from '../table-layout'
import type { TableOverflowTooltipOptions } from '../util'
export type DefaultRow = any
@@ -115,6 +116,7 @@ interface TableProps<T> {
defaultExpandAll?: boolean
defaultSort?: Sort
tooltipEffect?: string
tooltipOptions?: TableOverflowTooltipOptions
spanMethod?: (data: {
row: T
rowIndex: number
@@ -226,6 +228,7 @@ export default {
defaultExpandAll: Boolean,
defaultSort: Object as PropType<TableProps<DefaultRow>['defaultSort']>,
tooltipEffect: String,
tooltipOptions: Object as PropType<TableProps<DefaultRow>['tooltipOptions']>,
spanMethod: Function as PropType<TableProps<DefaultRow>['spanMethod']>,
selectOnIndeterminate: {
type: Boolean,

View File

@@ -1,24 +1,40 @@
// @ts-nocheck
import { createPopper } from '@popperjs/core'
import { flatMap, get } from 'lodash-unified'
import { flatMap, get, merge } from 'lodash-unified'
import escapeHtml from 'escape-html'
import { hasOwn, isArray, isBoolean, throwError } from '@element-plus/utils'
import { useZIndex } from '@element-plus/hooks'
import type {
IPopperOptions,
PopperInstance,
} from '@element-plus/components/popper'
import {
hasOwn,
isArray,
isBoolean,
isObject,
throwError,
} from '@element-plus/utils'
import { useDelayedToggle, useZIndex } from '@element-plus/hooks'
import type { PopperInstance } from '@element-plus/components/popper'
import type { Nullable } from '@element-plus/utils'
import type { TableColumnCtx } from './table-column/defaults'
import type { ElTooltipProps } from '@element-plus/components/tooltip'
export type TableOverflowTooltipOptions = Partial<
Pick<
ElTooltipProps,
| 'effect'
| 'enterable'
| 'hideAfter'
| 'offset'
| 'placement'
| 'popperClass'
| 'popperOptions'
| 'showAfter'
| 'showArrow'
// | 'transition'
>
>
export const getCell = function (event: Event) {
return (event.target as HTMLElement)?.closest('td')
}
const isObject = function (obj: unknown): boolean {
return obj !== null && typeof obj === 'object'
}
export const orderBy = function <T>(
array: T[],
sortKey: string,
@@ -315,16 +331,27 @@ export function createTablePopper(
parentNode: HTMLElement | undefined,
trigger: HTMLElement,
popperContent: string,
popperOptions: Partial<IPopperOptions>,
tooltipEffect: string
tooltipOptions?: TableOverflowTooltipOptions
) {
// TODO transition
tooltipOptions = merge(
{
enterable: true,
showArrow: true,
} as TableOverflowTooltipOptions,
tooltipOptions
)
const { nextZIndex } = useZIndex()
const ns = parentNode?.dataset.prefix
const scrollContainer = parentNode?.querySelector(`.${ns}-scrollbar__wrap`)
function renderContent(): HTMLDivElement {
const isLight = tooltipEffect === 'light'
const isLight = tooltipOptions.effect === 'light'
const content = document.createElement('div')
content.className = `${ns}-popper ${isLight ? 'is-light' : 'is-dark'}`
content.className = [
`${ns}-popper`,
isLight ? 'is-light' : 'is-dark',
tooltipOptions.popperClass || '',
].join(' ')
popperContent = escapeHtml(popperContent)
content.innerHTML = popperContent
content.style.zIndex = String(nextZIndex())
@@ -345,37 +372,56 @@ export function createTablePopper(
try {
popperInstance && popperInstance.destroy()
content && parentNode?.removeChild(content)
trigger.removeEventListener('mouseenter', showPopper)
trigger.removeEventListener('mouseleave', removePopper)
trigger.removeEventListener('mouseenter', onOpen)
trigger.removeEventListener('mouseleave', onClose)
scrollContainer?.removeEventListener('scroll', removePopper)
removePopper = undefined
} catch {}
}
let popperInstance: Nullable<PopperInstance> = null
let onOpen = showPopper
let onClose = removePopper
if (tooltipOptions.enterable) {
;({ onOpen, onClose } = useDelayedToggle({
showAfter: tooltipOptions.showAfter,
hideAfter: tooltipOptions.hideAfter,
open: showPopper,
close: removePopper,
}))
}
const content = renderContent()
const arrow = renderArrow()
content.appendChild(arrow)
content.onmouseenter = onOpen
content.onmouseleave = onClose
const modifiers = []
if (tooltipOptions.offset) {
modifiers.push({
name: 'offset',
options: {
offset: [0, tooltipOptions.offset],
},
})
}
if (tooltipOptions.showArrow) {
const arrow = content.appendChild(renderArrow())
modifiers.push({
name: 'arrow',
options: {
element: arrow,
padding: 10,
},
})
}
const popperOptions = tooltipOptions.popperOptions || {}
popperInstance = createPopper(trigger, content, {
strategy: 'absolute',
modifiers: [
{
name: 'offset',
options: {
offset: [0, 8],
},
},
{
name: 'arrow',
options: {
element: arrow,
padding: 10,
},
},
],
placement: tooltipOptions.placement || 'top',
strategy: 'fixed',
...popperOptions,
modifiers: popperOptions.modifiers
? modifiers.concat(popperOptions.modifiers)
: modifiers,
})
trigger.addEventListener('mouseenter', showPopper)
trigger.addEventListener('mouseleave', removePopper)
trigger.addEventListener('mouseenter', onOpen)
trigger.addEventListener('mouseleave', onClose)
scrollContainer?.addEventListener('scroll', removePopper)
return popperInstance
}