mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-01-24 12:45:18 +08:00
feat(data-table): selection.options
This commit is contained in:
parent
8d8b4c764f
commit
3581c3570f
@ -19,9 +19,12 @@ Rows can be selectable by making first column's type as `selection`.
|
||||
```
|
||||
|
||||
```js
|
||||
import { DataTableCheckOption } from 'naive-ui'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
type: 'selection',
|
||||
options: [DataTableCheckOption.CHECK_ALL, DataTableCheckOption.UNCHECK_ALL],
|
||||
disabled (row, index) {
|
||||
return row.name === 'Edward King 3'
|
||||
}
|
||||
|
@ -16,9 +16,12 @@
|
||||
```
|
||||
|
||||
```js
|
||||
import { DataTableCheckOption } from 'naive-ui'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
type: 'selection',
|
||||
options: [DataTableCheckOption.CHECK_ALL, DataTableCheckOption.UNCHECK_ALL],
|
||||
disabled (row, index) {
|
||||
return row.name === 'Edward King 3'
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
export { default as NDataTable } from './src/DataTable'
|
||||
export { DataTableCheckOption } from './src/TableParts/CheckMenu'
|
||||
export type { DataTableProps } from './src/DataTable'
|
||||
export type {
|
||||
RenderFilter as DataTableRenderFilter,
|
||||
@ -6,7 +7,7 @@ export type {
|
||||
ColumnKey as DataTableColumnKey,
|
||||
TableColumn as DataTableColumn,
|
||||
TableBaseColumn as DataTableBaseColumn,
|
||||
TableSelectionColumn as DataTableSelectionColumn,
|
||||
TableSelectionColumn as DataTableCheckOptionColumn,
|
||||
TableExpandColumn as DataTableExpandColumn,
|
||||
DataTableInst
|
||||
} from './src/interface'
|
||||
|
@ -225,6 +225,7 @@ export default defineComponent({
|
||||
treeMate: treeMateRef,
|
||||
mergedCurrentPage: mergedCurrentPageRef,
|
||||
paginatedData: paginatedDataRef,
|
||||
selectionColumn: selectionColumnRef,
|
||||
hoverKey,
|
||||
currentPage,
|
||||
mergedPagination,
|
||||
@ -247,8 +248,9 @@ export default defineComponent({
|
||||
allRowsChecked,
|
||||
mergedCheckedRowKeys
|
||||
} = useCheck(props, {
|
||||
paginatedDataRef,
|
||||
treeMateRef
|
||||
selectionColumnRef,
|
||||
treeMateRef,
|
||||
paginatedDataRef
|
||||
})
|
||||
const {
|
||||
mergedExpandedRowKeys,
|
||||
@ -299,6 +301,10 @@ export default defineComponent({
|
||||
mergedExpandedRowKeys,
|
||||
locale,
|
||||
rowKey: toRef(props, 'rowKey'),
|
||||
checkOptions: computed(() => {
|
||||
const { value: selectionColumn } = selectionColumnRef
|
||||
return selectionColumn?.options
|
||||
}),
|
||||
filterMenuCssVars: computed(() => {
|
||||
const {
|
||||
self: { actionDividerColor, actionPadding, actionButtonMargin }
|
||||
|
99
src/data-table/src/TableParts/CheckMenu.tsx
Normal file
99
src/data-table/src/TableParts/CheckMenu.tsx
Normal file
@ -0,0 +1,99 @@
|
||||
import { h, defineComponent, inject, computed } from 'vue'
|
||||
import { NDropdown } from '../../../dropdown'
|
||||
import { NBaseIcon } from '../../../_internal'
|
||||
import { ChevronDownIcon } from '../../../_internal/icons'
|
||||
import { dataTableInjectionKey } from '../interface'
|
||||
|
||||
export enum DataTableCheckOption {
|
||||
CHECK_ALL,
|
||||
UNCHECK_ALL
|
||||
}
|
||||
|
||||
function createSelectHandler (
|
||||
options:
|
||||
| Array<
|
||||
| DataTableCheckOption
|
||||
| { label: string, key: string | number, onSelect: () => void }
|
||||
>
|
||||
| undefined,
|
||||
doCheckAll: (checkWholeTable?: boolean) => void,
|
||||
doUncheckAll: (checkWholeTable?: boolean) => void
|
||||
): (key: string | number) => void {
|
||||
if (!options) return () => {}
|
||||
return (key: string | number) => {
|
||||
for (const option of options) {
|
||||
switch (key) {
|
||||
case DataTableCheckOption.CHECK_ALL:
|
||||
doCheckAll(true)
|
||||
return
|
||||
case DataTableCheckOption.UNCHECK_ALL:
|
||||
doUncheckAll(true)
|
||||
return
|
||||
default:
|
||||
if (typeof option === 'object' && option.key === key) {
|
||||
option.onSelect()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createDropdownOptions (
|
||||
options:
|
||||
| Array<
|
||||
| DataTableCheckOption
|
||||
| { label: string, key: string | number, onSelect: () => void }
|
||||
>
|
||||
| undefined
|
||||
): Array<{ label: string, key: string | number }> {
|
||||
if (!options) return []
|
||||
return options.map((option) => {
|
||||
switch (option) {
|
||||
case DataTableCheckOption.CHECK_ALL:
|
||||
return {
|
||||
label: '选择表格全部数据',
|
||||
key: DataTableCheckOption.CHECK_ALL
|
||||
}
|
||||
case DataTableCheckOption.UNCHECK_ALL:
|
||||
return {
|
||||
label: '选择表格全部数据取消',
|
||||
key: DataTableCheckOption.UNCHECK_ALL
|
||||
}
|
||||
default:
|
||||
return option
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DataTableCheckMenu',
|
||||
setup () {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const NDataTable = inject(dataTableInjectionKey)!
|
||||
const { doCheckAll, doUncheckAll } = NDataTable
|
||||
return {
|
||||
handleSelect: createSelectHandler(
|
||||
NDataTable.checkOptions,
|
||||
doCheckAll,
|
||||
doUncheckAll
|
||||
),
|
||||
options: computed(() => createDropdownOptions(NDataTable.checkOptions))
|
||||
}
|
||||
},
|
||||
render () {
|
||||
return (
|
||||
<NDropdown options={this.options} onSelect={this.handleSelect}>
|
||||
{{
|
||||
default: () => (
|
||||
<NBaseIcon clsPrefix="n" class="n-data-table-check-extra">
|
||||
{{
|
||||
default: () => <ChevronDownIcon />
|
||||
}}
|
||||
</NBaseIcon>
|
||||
)
|
||||
}}
|
||||
</NDropdown>
|
||||
)
|
||||
}
|
||||
})
|
@ -1,4 +1,4 @@
|
||||
import { h, defineComponent, inject, PropType, VNodeChild } from 'vue'
|
||||
import { h, defineComponent, inject, PropType, VNodeChild, Fragment } from 'vue'
|
||||
import { happensIn, pxfy } from 'seemly'
|
||||
import { formatLength } from '../../../_utils'
|
||||
import { NCheckbox } from '../../../checkbox'
|
||||
@ -13,11 +13,11 @@ import {
|
||||
} from '../utils'
|
||||
import {
|
||||
TableExpandColumn,
|
||||
TableSelectionColumn,
|
||||
TableColumnGroup,
|
||||
TableBaseColumn,
|
||||
dataTableInjectionKey
|
||||
} from '../interface'
|
||||
import CheckMenu from './CheckMenu'
|
||||
|
||||
function renderTitle (
|
||||
column: TableExpandColumn | TableBaseColumn | TableColumnGroup
|
||||
@ -35,11 +35,11 @@ export default defineComponent({
|
||||
setup () {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const NDataTable = inject(dataTableInjectionKey)!
|
||||
function handleCheckboxUpdateChecked (column: TableSelectionColumn): void {
|
||||
function handleCheckboxUpdateChecked (): void {
|
||||
if (NDataTable.someRowsChecked || NDataTable.allRowsChecked) {
|
||||
NDataTable.doUncheckAll(column)
|
||||
NDataTable.doUncheckAll()
|
||||
} else {
|
||||
NDataTable.doCheckAll(column)
|
||||
NDataTable.doCheckAll()
|
||||
}
|
||||
}
|
||||
function handleColHeaderClick (
|
||||
@ -75,7 +75,8 @@ export default defineComponent({
|
||||
rightActiveFixedColKey,
|
||||
rows,
|
||||
cols,
|
||||
mergedTheme
|
||||
mergedTheme,
|
||||
checkOptions
|
||||
},
|
||||
headerStyle,
|
||||
handleColHeaderClick,
|
||||
@ -145,15 +146,16 @@ export default defineComponent({
|
||||
}
|
||||
>
|
||||
{column.type === 'selection' ? (
|
||||
<NCheckbox
|
||||
key={currentPage}
|
||||
tableHeader
|
||||
checked={allRowsChecked}
|
||||
indeterminate={someRowsChecked}
|
||||
onUpdateChecked={() =>
|
||||
handleCheckboxUpdateChecked(column)
|
||||
}
|
||||
/>
|
||||
<>
|
||||
<NCheckbox
|
||||
key={currentPage}
|
||||
tableHeader
|
||||
checked={allRowsChecked}
|
||||
indeterminate={someRowsChecked}
|
||||
onUpdateChecked={handleCheckboxUpdateChecked}
|
||||
/>
|
||||
{checkOptions ? <CheckMenu /> : null}
|
||||
</>
|
||||
) : column.ellipsis === true ||
|
||||
(column.ellipsis && !column.ellipsis.tooltip) ? (
|
||||
<div
|
||||
|
@ -5,6 +5,7 @@ import { NLocale } from '../../locales'
|
||||
import { MergedTheme } from '../../_mixins'
|
||||
import { DataTableTheme } from '../styles'
|
||||
import { RowItem, ColItem } from './use-group-header'
|
||||
import { DataTableCheckOption } from './TableParts/CheckMenu'
|
||||
|
||||
export type FilterOptionValue = string | number
|
||||
export type ColumnKey = string | number
|
||||
@ -100,6 +101,7 @@ export type TableBaseColumn = {
|
||||
export type TableSelectionColumn = {
|
||||
type: 'selection'
|
||||
disabled?: (row: RowData) => boolean
|
||||
options?: DataTableCheckOptions
|
||||
|
||||
// to suppress type error in utils
|
||||
sorter?: never
|
||||
@ -127,11 +129,16 @@ export type TableColumn =
|
||||
| TableExpandColumn
|
||||
export type TableColumns = TableColumn[]
|
||||
|
||||
export type DataTableCheckOptions = Array<
|
||||
| DataTableCheckOption
|
||||
| { label: string, key: string | number, onSelect: () => void }
|
||||
>
|
||||
export interface DataTableInjection {
|
||||
checkOptions: DataTableCheckOptions | undefined
|
||||
hoverKey: RowKey | null
|
||||
mergedClsPrefix: string
|
||||
mergedTheme: MergedTheme<DataTableTheme>
|
||||
scrollX?: string | number
|
||||
scrollX: string | number | undefined
|
||||
rows: RowItem[][]
|
||||
cols: ColItem[]
|
||||
treeMate: TreeMate<RowData>
|
||||
@ -148,7 +155,7 @@ export interface DataTableInjection {
|
||||
mergedSortState: SortState | null
|
||||
mergedFilterState: FilterState
|
||||
loading: boolean
|
||||
rowClassName?: string | CreateRowClassName
|
||||
rowClassName: string | CreateRowClassName | undefined
|
||||
mergedCheckedRowKeys: RowKey[]
|
||||
locale: NLocale['DataTable']
|
||||
filterMenuCssVars: CSSProperties
|
||||
@ -162,8 +169,8 @@ export interface DataTableInjection {
|
||||
) => void
|
||||
doUpdateSorter: (sorter: SortState | null) => void
|
||||
doUpdateCheckedRowKeys: (keys: RowKey[]) => void
|
||||
doUncheckAll: (column: TableSelectionColumn) => void
|
||||
doCheckAll: (column: TableSelectionColumn) => void
|
||||
doUncheckAll: (checkWholeTable?: boolean) => void
|
||||
doCheckAll: (checkWholeTable?: boolean) => void
|
||||
handleTableHeaderScroll: (e: Event) => void
|
||||
handleTableBodyScroll: (e: Event) => void
|
||||
deriveActiveRightFixedColumn: (
|
||||
|
@ -214,10 +214,12 @@ export default c([
|
||||
cM('filterable', {
|
||||
paddingRight: '36px'
|
||||
}),
|
||||
fixedColumnStyle,
|
||||
cM('selection', `
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
line-height: 0;
|
||||
z-index: 3;
|
||||
`),
|
||||
cE('ellipsis', `
|
||||
display: inline-block;
|
||||
@ -236,8 +238,7 @@ export default c([
|
||||
c('&:hover', {
|
||||
backgroundColor: 'var(--merged-th-color-hover)'
|
||||
})
|
||||
]),
|
||||
fixedColumnStyle
|
||||
])
|
||||
]),
|
||||
cB('data-table-td', `
|
||||
text-align: start;
|
||||
@ -329,7 +330,17 @@ export default c([
|
||||
`)
|
||||
])
|
||||
])
|
||||
])
|
||||
]),
|
||||
cB('data-table-check-extra', `
|
||||
transition: color .3s var(--bezier);
|
||||
color: var(--th-icon-color);
|
||||
position: absolute;
|
||||
font-size: 14px;
|
||||
right: -4px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
z-index: 1;
|
||||
`)
|
||||
]),
|
||||
cB('data-table-filter-menu', [
|
||||
cB('scrollbar', {
|
||||
@ -387,11 +398,11 @@ export default c([
|
||||
|
||||
function createFixedColumnStyle (): CNode[] {
|
||||
return [
|
||||
cM('fixed-left', {
|
||||
left: 0,
|
||||
position: 'sticky',
|
||||
zIndex: 2
|
||||
}, [
|
||||
cM('fixed-left', `
|
||||
left: 0;
|
||||
position: sticky;
|
||||
z-index: 2;
|
||||
`, [
|
||||
c('&::after', `
|
||||
pointer-events: none;
|
||||
content: "";
|
||||
|
@ -9,11 +9,12 @@ import { TreeMate } from 'treemate'
|
||||
export function useCheck (
|
||||
props: DataTableSetupProps,
|
||||
data: {
|
||||
selectionColumnRef: ComputedRef<TableSelectionColumn | null>
|
||||
paginatedDataRef: ComputedRef<TmNode[]>
|
||||
treeMateRef: ComputedRef<TreeMate<RowData>>
|
||||
}
|
||||
) {
|
||||
const { paginatedDataRef, treeMateRef } = data
|
||||
const { paginatedDataRef, treeMateRef, selectionColumnRef } = data
|
||||
const uncontrolledCheckedRowKeysRef = ref(props.defaultCheckedRowKeys)
|
||||
const controlledCheckedRowKeysRef = toRef(props, 'checkedRowKeys')
|
||||
const mergedCheckedRowKeysRef = useMergedState(
|
||||
@ -47,9 +48,14 @@ export function useCheck (
|
||||
if (onCheckedRowKeysChange) call(onCheckedRowKeysChange, keys)
|
||||
uncontrolledCheckedRowKeysRef.value = keys
|
||||
}
|
||||
function doCheckAll (column: TableSelectionColumn): void {
|
||||
function doCheckAll (checkWholeTable: boolean = false): void {
|
||||
const { value: column } = selectionColumnRef
|
||||
if (!column) return
|
||||
const rowKeysToCheck: RowKey[] = []
|
||||
paginatedDataRef.value.forEach((tmNode) => {
|
||||
;(checkWholeTable
|
||||
? treeMateRef.value.treeNodes
|
||||
: paginatedDataRef.value
|
||||
).forEach((tmNode) => {
|
||||
if (column.disabled?.(tmNode.rawNode)) {
|
||||
return
|
||||
}
|
||||
@ -62,9 +68,14 @@ export function useCheck (
|
||||
.checkedKeys
|
||||
)
|
||||
}
|
||||
function doUncheckAll (column: TableSelectionColumn): void {
|
||||
function doUncheckAll (checkWholeTable: boolean = false): void {
|
||||
const { value: column } = selectionColumnRef
|
||||
if (!column) return
|
||||
const rowKeysToUncheck: RowKey[] = []
|
||||
paginatedDataRef.value.forEach((tmNode) => {
|
||||
;(checkWholeTable
|
||||
? treeMateRef.value.treeNodes
|
||||
: paginatedDataRef.value
|
||||
).forEach((tmNode) => {
|
||||
const { rawNode: row } = tmNode
|
||||
if (column.disabled?.(row)) {
|
||||
return
|
||||
|
@ -301,6 +301,17 @@ export function useTableData (
|
||||
}
|
||||
})
|
||||
|
||||
const selectionColumnRef = computed<TableSelectionColumn | null>(() => {
|
||||
return (
|
||||
(props.columns.find((col) => {
|
||||
if (col.type === 'selection') {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}) as TableSelectionColumn | undefined) || null
|
||||
)
|
||||
})
|
||||
|
||||
function doUpdatePage (page: number): void {
|
||||
const { 'onUpdate:page': onUpdatePage, onPageChange } = props
|
||||
if (onUpdatePage) call(onUpdatePage, page)
|
||||
@ -380,6 +391,7 @@ export function useTableData (
|
||||
mergedFilterState: mergedFilterStateRef,
|
||||
mergedSortState: mergedSortStateRef,
|
||||
hoverKey: ref<RowKey | null>(null),
|
||||
selectionColumn: selectionColumnRef,
|
||||
doUpdateFilters,
|
||||
doUpdateSorter,
|
||||
doUpdatePageSize,
|
||||
|
Loading…
Reference in New Issue
Block a user