Skip to content

Commit e54cbae

Browse files
brc-ddkiaking
andauthored
feat(table): support selecting single row (#477)
Co-authored-by: Kia King Ishii <[email protected]>
1 parent 85752d5 commit e54cbae

File tree

4 files changed

+361
-67
lines changed

4 files changed

+361
-67
lines changed

lib/components/SInputRadio.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const props = defineProps<{
1717
checkIcon?: IconifyIcon | DefineComponent
1818
checkText?: string
1919
checkColor?: Color
20-
text: string
20+
text?: string
2121
disabled?: boolean
2222
modelValue: boolean
2323
validation?: Validatable
@@ -68,7 +68,7 @@ function onClick() {
6868
<div class="check" />
6969
</div>
7070

71-
<p class="text">{{ text }}</p>
71+
<p class="text" v-if="text">{{ text }}</p>
7272
</div>
7373
</div>
7474
<template v-if="$slots.info" #info><slot name="info" /></template>

lib/components/STable.vue

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<script setup lang="ts">
1+
<script setup lang="ts" generic="S extends any[] | any | undefined = undefined">
22
import { useVirtualizer } from '@tanstack/vue-virtual'
33
import { useResizeObserver } from '@vueuse/core'
44
import xor from 'lodash-es/xor'
@@ -15,6 +15,7 @@ import {
1515
import { type Table } from '../composables/Table'
1616
import { getTextWidth } from '../support/Text'
1717
import SInputCheckbox from './SInputCheckbox.vue'
18+
import SInputRadio from './SInputRadio.vue'
1819
import SSpinner from './SSpinner.vue'
1920
import STableCell from './STableCell.vue'
2021
import STableColumn from './STableColumn.vue'
@@ -24,11 +25,11 @@ import STableItem from './STableItem.vue'
2425
2526
const props = defineProps<{
2627
options: Table
27-
selected?: unknown[]
28+
selected?: S
2829
}>()
2930
3031
const emit = defineEmits<{
31-
(e: 'update:selected', value: unknown[]): void
32+
(e: 'update:selected', value: S): void
3233
}>()
3334
3435
const head = shallowRef<HTMLElement | null>(null)
@@ -41,7 +42,7 @@ const ordersToShow = computed(() => {
4142
const show = unref(props.options.columns)[key]?.show
4243
return toValue(show) !== false
4344
})
44-
if (!props.selected) {
45+
if (props.selected === undefined) {
4546
return orders
4647
}
4748
return ['__select', ...orders]
@@ -126,7 +127,7 @@ const recordsWithSummary = computed(() => {
126127
})
127128
128129
const indexes = computed(() => {
129-
if (!props.selected) {
130+
if (props.selected === undefined) {
130131
return []
131132
}
132133
const records = unref(props.options.records) ?? []
@@ -139,9 +140,6 @@ const selectedIndexes = reactive(new Set())
139140
140141
const control = computed({
141142
get() {
142-
if (!props.selected) {
143-
return false
144-
}
145143
const selected = indexes.value.filter((index) => {
146144
return selectedIndexes.has(index)
147145
})
@@ -165,12 +163,11 @@ const control = computed({
165163
})
166164
167165
watch(indexes, (newValue, oldValue) => {
168-
if (!props.selected) {
169-
return
166+
if (Array.isArray(props.selected)) {
167+
xor(newValue, oldValue).forEach((index) => {
168+
selectedIndexes.delete(index)
169+
})
170170
}
171-
xor(newValue, oldValue).forEach((index) => {
172-
selectedIndexes.delete(index)
173-
})
174171
})
175172
176173
const virtualizerOptions = computed(() => ({
@@ -343,8 +340,12 @@ function getCell(key: string, index: number) {
343340
return (isSummary(index) && col?.summaryCell) ? col?.summaryCell : col?.cell
344341
}
345342
346-
function updateSelected(selected: unknown[]) {
347-
if (xor(selected, props.selected ?? []).length) {
343+
function updateSelected(selected: any) {
344+
if (Array.isArray(props.selected)) {
345+
if (xor(selected, props.selected ?? []).length) {
346+
emit('update:selected', selected)
347+
}
348+
} else {
348349
emit('update:selected', selected)
349350
}
350351
}
@@ -361,7 +362,7 @@ function updateSelected(selected: unknown[]) {
361362
:actions="unref(options.actions)"
362363
:borderless="unref(options.borderless)"
363364
:on-reset="options.onReset"
364-
:selected="selected"
365+
:selected="Array.isArray(selected) ? selected : undefined"
365366
/>
366367

367368
<div class="table" role="grid">
@@ -389,7 +390,7 @@ function updateSelected(selected: unknown[]) {
389390
@resize="(value) => updateColWidth(key, value, true)"
390391
>
391392
<SInputCheckbox
392-
v-if="key === '__select' && unref(options.records)?.length"
393+
v-if="Array.isArray(selected) && key === '__select' && unref(options.records)?.length"
393394
v-model="control"
394395
/>
395396
</STableColumn>
@@ -444,11 +445,18 @@ function updateSelected(selected: unknown[]) {
444445
:record="recordsWithSummary[index]"
445446
:records="unref(options.records)!"
446447
>
447-
<SInputCheckbox
448-
v-if="key === '__select' && !isSummary(index)"
449-
:value="selectedIndexes.has(indexes[index])"
450-
@change="c => selectedIndexes[c ? 'add' : 'delete'](indexes[index])"
451-
/>
448+
<template v-if="key === '__select' && !isSummary(index)">
449+
<SInputCheckbox
450+
v-if="Array.isArray(selected)"
451+
:model-value="selectedIndexes.has(indexes[index])"
452+
@update:model-value="c => selectedIndexes[c ? 'add' : 'delete'](indexes[index])"
453+
/>
454+
<SInputRadio
455+
v-else
456+
:model-value="selected === indexes[index]"
457+
@update:model-value="c => updateSelected(c ? indexes[index] : null)"
458+
/>
459+
</template>
452460
</STableCell>
453461
</STableItem>
454462
</div>
@@ -598,6 +606,7 @@ function updateSelected(selected: unknown[]) {
598606
align-items: center;
599607
padding: 0 16px;
600608
min-height: 40px;
609+
user-select: none;
601610
}
602611
603612
:deep(.container) {

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
},
7373
"devDependencies": {
7474
"@globalbrain/eslint-config": "^1.5.2",
75-
"@histoire/plugin-vue": "0.17.9",
75+
"@histoire/plugin-vue": "^0.16.5",
7676
"@iconify-icons/ph": "^1.2.5",
7777
"@iconify-icons/ri": "^1.2.10",
7878
"@iconify/vue": "^4.1.1",
@@ -91,7 +91,7 @@
9191
"eslint": "^8.56.0",
9292
"fuse.js": "^7.0.0",
9393
"happy-dom": "^13.3.8",
94-
"histoire": "0.17.9",
94+
"histoire": "^0.16.5",
9595
"lodash-es": "^4.17.21",
9696
"markdown-it": "^14.0.0",
9797
"normalize.css": "^8.0.1",

0 commit comments

Comments
 (0)