mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-19 22:41:42 +01:00
feat(Table): add click event for the entire row (#353)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
54
docs/components/content/examples/TableExampleClickable.vue
Normal file
54
docs/components/content/examples/TableExampleClickable.vue
Normal file
@@ -0,0 +1,54 @@
|
||||
<script setup>
|
||||
const people = [{
|
||||
id: 1,
|
||||
name: 'Lindsay Walton',
|
||||
title: 'Front-end Developer',
|
||||
email: 'lindsay.walton@example.com',
|
||||
role: 'Member'
|
||||
}, {
|
||||
id: 2,
|
||||
name: 'Courtney Henry',
|
||||
title: 'Designer',
|
||||
email: 'courtney.henry@example.com',
|
||||
role: 'Admin'
|
||||
}, {
|
||||
id: 3,
|
||||
name: 'Tom Cook',
|
||||
title: 'Director of Product',
|
||||
email: 'tom.cook@example.com',
|
||||
role: 'Member'
|
||||
}, {
|
||||
id: 4,
|
||||
name: 'Whitney Francis',
|
||||
title: 'Copywriter',
|
||||
email: 'whitney.francis@example.com',
|
||||
role: 'Admin'
|
||||
}, {
|
||||
id: 5,
|
||||
name: 'Leonard Krasner',
|
||||
title: 'Senior Designer',
|
||||
email: 'leonard.krasner@example.com',
|
||||
role: 'Owner'
|
||||
}, {
|
||||
id: 6,
|
||||
name: 'Floyd Miles',
|
||||
title: 'Principal Designer',
|
||||
email: 'floyd.miles@example.com',
|
||||
role: 'Member'
|
||||
}]
|
||||
|
||||
function select (row) {
|
||||
const index = selected.value.findIndex((item) => item.id === row.id)
|
||||
if (index === -1) {
|
||||
selected.value.push(row)
|
||||
} else {
|
||||
selected.value.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
const selected = ref([people[1]])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UTable v-model="selected" :rows="people" @select="select" />
|
||||
</template>
|
||||
@@ -327,6 +327,44 @@ const selected = ref([people[1]])
|
||||
You can use the `by` prop to compare objects by a field instead of comparing object instances. We've replicated the behavior of Headless UI [Combobox](https://headlessui.com/vue/combobox#binding-objects-as-values).
|
||||
::
|
||||
|
||||
### Clickable
|
||||
|
||||
Add a `select` listener on your Table to make the rows clickable. The function will receive the row as the first argument.
|
||||
|
||||
You can use this to navigate to a page, open a modal or even to select the row manually.
|
||||
|
||||
::component-example{class="grid"}
|
||||
---
|
||||
padding: false
|
||||
overflowClass: 'overflow-x-auto'
|
||||
---
|
||||
|
||||
#default
|
||||
:table-example-clickable{class="flex-1"}
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const people = [...]
|
||||
|
||||
function select (row) {
|
||||
const index = selected.value.findIndex((item) => item.id === row.id)
|
||||
if (index === -1) {
|
||||
selected.value.push(row)
|
||||
} else {
|
||||
selected.value.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
const selected = ref([people[1]])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UTable v-model="selected" :rows="people" @select="select" />
|
||||
</template>
|
||||
```
|
||||
::
|
||||
|
||||
### Searchable
|
||||
|
||||
You can easily use the [Input](/forms/input) component to filter the rows.
|
||||
|
||||
@@ -8,7 +8,8 @@ const table = {
|
||||
tbody: 'divide-y divide-gray-200 dark:divide-gray-800',
|
||||
tr: {
|
||||
base: '',
|
||||
selected: 'bg-gray-50 dark:bg-gray-800/50'
|
||||
selected: 'bg-gray-50 dark:bg-gray-800/50',
|
||||
active: 'hover:bg-gray-50 dark:hover:bg-gray-800/50 cursor-pointer'
|
||||
},
|
||||
th: {
|
||||
base: 'text-left rtl:text-right',
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody :class="ui.tbody">
|
||||
<tr v-for="(row, index) in rows" :key="index" :class="[ui.tr.base, isSelected(row) && ui.tr.selected]">
|
||||
<tr v-for="(row, index) in rows" :key="index" :class="[ui.tr.base, isSelected(row) && ui.tr.selected, $attrs.onSelect && ui.tr.active]" @click="() => onSelect(row)">
|
||||
<td v-if="modelValue" class="ps-4">
|
||||
<UCheckbox v-model="selected" :value="row" />
|
||||
<UCheckbox v-model="selected" :value="row" @click.stop />
|
||||
</td>
|
||||
|
||||
<td v-for="(column, subIndex) in columns" :key="subIndex" :class="[ui.td.base, ui.td.padding, ui.td.color, ui.td.font, ui.td.size]">
|
||||
@@ -69,6 +69,7 @@ import { ref, computed, defineComponent, toRaw } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import { capitalize, orderBy } from 'lodash-es'
|
||||
import { defu } from 'defu'
|
||||
import { omit } from 'lodash-es'
|
||||
import type { Button } from '../../types/button'
|
||||
import { useAppConfig } from '#imports'
|
||||
// TODO: Remove
|
||||
@@ -92,7 +93,7 @@ export default defineComponent({
|
||||
default: () => defaultComparator
|
||||
},
|
||||
rows: {
|
||||
type: Array as PropType<{ [key: string]: any }[]>,
|
||||
type: Array as PropType<{ [key: string]: any, click?: Function }[]>,
|
||||
default: () => []
|
||||
},
|
||||
columns: {
|
||||
@@ -137,13 +138,13 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
setup (props, { emit }) {
|
||||
setup (props, { emit, attrs }) {
|
||||
// TODO: Remove
|
||||
const appConfig = useAppConfig()
|
||||
|
||||
const ui = computed<Partial<typeof appConfig.ui.table>>(() => defu({}, props.ui, appConfig.ui.table))
|
||||
|
||||
const columns = computed(() => props.columns ?? Object.keys(props.rows[0] ?? {}).map((key) => ({ key, label: capitalize(key), sortable: false })))
|
||||
const columns = computed(() => props.columns ?? Object.keys(omit(props.rows[0] ?? {}, ['click'])).map((key) => ({ key, label: capitalize(key), sortable: false })))
|
||||
|
||||
const sort = ref(defu({}, props.sort, { column: null, direction: 'asc' }))
|
||||
|
||||
@@ -200,6 +201,15 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
|
||||
function onSelect (row) {
|
||||
if (!attrs.onSelect) {
|
||||
return
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
attrs.onSelect(row)
|
||||
}
|
||||
|
||||
return {
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
ui,
|
||||
@@ -214,7 +224,8 @@ export default defineComponent({
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
emptyState,
|
||||
isSelected,
|
||||
onSort
|
||||
onSort,
|
||||
onSelect
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user