@redseed/redseed-ui-vue3 8.32.0 → 8.32.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import DropdownMenu from '../DropdownMenu/DropdownMenu.vue'
|
|
4
|
+
import ButtonTertiary from '../Button/ButtonTertiary.vue'
|
|
5
|
+
import Icon from '../Icon/Icon.vue'
|
|
6
|
+
import { AdjustmentsHorizontalIcon, CheckIcon } from '@heroicons/vue/24/outline'
|
|
7
|
+
|
|
8
|
+
const props = defineProps({
|
|
9
|
+
columns: {
|
|
10
|
+
type: Array,
|
|
11
|
+
required: true,
|
|
12
|
+
validator: value => value.every(c => typeof c === 'object' && c.key && c.name !== undefined),
|
|
13
|
+
},
|
|
14
|
+
label: {
|
|
15
|
+
type: String,
|
|
16
|
+
default: 'Columns',
|
|
17
|
+
},
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const visibleKeys = defineModel('visibleKeys', { type: Array, required: true })
|
|
21
|
+
|
|
22
|
+
const isVisible = (key) => visibleKeys.value.includes(key)
|
|
23
|
+
|
|
24
|
+
function toggle(key) {
|
|
25
|
+
if (visibleKeys.value.includes(key)) {
|
|
26
|
+
visibleKeys.value = visibleKeys.value.filter(k => k !== key)
|
|
27
|
+
} else {
|
|
28
|
+
visibleKeys.value = [...visibleKeys.value, key]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const visibleCount = computed(() => visibleKeys.value.length)
|
|
33
|
+
const totalCount = computed(() => props.columns.length)
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<template>
|
|
37
|
+
<DropdownMenu right class="rsui-column-picker">
|
|
38
|
+
<template #trigger="{ open, isOpen }">
|
|
39
|
+
<ButtonTertiary :aria-expanded="isOpen" @click="open">
|
|
40
|
+
<Icon sm><AdjustmentsHorizontalIcon /></Icon>
|
|
41
|
+
{{ label }}
|
|
42
|
+
<span class="rsui-column-picker__count">{{ visibleCount }}/{{ totalCount }}</span>
|
|
43
|
+
</ButtonTertiary>
|
|
44
|
+
</template>
|
|
45
|
+
|
|
46
|
+
<ul class="rsui-column-picker__list" role="none">
|
|
47
|
+
<li v-for="column in columns"
|
|
48
|
+
:key="column.key"
|
|
49
|
+
class="rsui-column-picker__item"
|
|
50
|
+
role="menuitemcheckbox"
|
|
51
|
+
:aria-checked="isVisible(column.key)"
|
|
52
|
+
tabindex="0"
|
|
53
|
+
@click.stop="toggle(column.key)"
|
|
54
|
+
@keydown.enter.self.prevent="toggle(column.key)"
|
|
55
|
+
@keydown.space.self.prevent="toggle(column.key)"
|
|
56
|
+
>
|
|
57
|
+
<span :class="['rsui-column-picker__check', { 'rsui-column-picker__check--on': isVisible(column.key) }]"
|
|
58
|
+
aria-hidden="true"
|
|
59
|
+
>
|
|
60
|
+
<CheckIcon v-if="isVisible(column.key)" />
|
|
61
|
+
</span>
|
|
62
|
+
<span class="rsui-column-picker__label">{{ column.name || column.key }}</span>
|
|
63
|
+
</li>
|
|
64
|
+
</ul>
|
|
65
|
+
</DropdownMenu>
|
|
66
|
+
</template>
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import { computed, ref, watch } from 'vue'
|
|
2
3
|
import { Card, CardHeader } from '../Card'
|
|
3
4
|
import Tr from './Tr.vue'
|
|
4
5
|
import Th from './Th.vue'
|
|
5
6
|
import Td from './Td.vue'
|
|
7
|
+
import ColumnPicker from './ColumnPicker.vue'
|
|
6
8
|
|
|
7
9
|
const titleId = _.uniqueId('table-title-')
|
|
8
10
|
|
|
@@ -39,6 +41,47 @@ const props = defineProps({
|
|
|
39
41
|
type: String,
|
|
40
42
|
default: undefined,
|
|
41
43
|
},
|
|
44
|
+
// When true, Table renders an internal ColumnPicker in the header actions and
|
|
45
|
+
// manages column visibility itself. Use `v-model:visibleKeys` to persist or
|
|
46
|
+
// override the selection externally; without v-model, all columns are visible
|
|
47
|
+
// by default and toggling is purely local.
|
|
48
|
+
columnPicker: {
|
|
49
|
+
type: Boolean,
|
|
50
|
+
default: false,
|
|
51
|
+
},
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
// v-model:visibleKeys — undefined means "uncontrolled" / use internal default (all visible).
|
|
55
|
+
const visibleKeys = defineModel('visibleKeys', {
|
|
56
|
+
type: Array,
|
|
57
|
+
default: undefined,
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
// Internal fallback when no v-model is bound but columnPicker is enabled.
|
|
61
|
+
const internalVisibleKeys = ref(props.columns.map(c => c.key))
|
|
62
|
+
|
|
63
|
+
watch(() => props.columns, (next) => {
|
|
64
|
+
// Keep internal state in sync if the columns array changes (e.g. consumer adds/removes a column).
|
|
65
|
+
const knownKeys = next.map(c => c.key)
|
|
66
|
+
internalVisibleKeys.value = internalVisibleKeys.value.filter(k => knownKeys.includes(k))
|
|
67
|
+
for (const key of knownKeys) {
|
|
68
|
+
if (!internalVisibleKeys.value.includes(key)) internalVisibleKeys.value.push(key)
|
|
69
|
+
}
|
|
70
|
+
}, { deep: true })
|
|
71
|
+
|
|
72
|
+
const effectiveVisibleKeys = computed({
|
|
73
|
+
get: () => visibleKeys.value ?? internalVisibleKeys.value,
|
|
74
|
+
set: (next) => {
|
|
75
|
+
if (visibleKeys.value !== undefined) {
|
|
76
|
+
visibleKeys.value = next
|
|
77
|
+
} else {
|
|
78
|
+
internalVisibleKeys.value = next
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const visibleColumns = computed(() => {
|
|
84
|
+
return props.columns.filter(column => effectiveVisibleKeys.value.includes(column.key))
|
|
42
85
|
})
|
|
43
86
|
</script>
|
|
44
87
|
|
|
@@ -67,8 +110,12 @@ const props = defineProps({
|
|
|
67
110
|
<slot name="subtitle"></slot>
|
|
68
111
|
</template>
|
|
69
112
|
|
|
70
|
-
<template #actions v-if="$slots.actions">
|
|
113
|
+
<template #actions v-if="$slots.actions || columnPicker">
|
|
71
114
|
<slot name="actions"></slot>
|
|
115
|
+
<ColumnPicker v-if="columnPicker"
|
|
116
|
+
:columns="columns"
|
|
117
|
+
v-model:visibleKeys="effectiveVisibleKeys"
|
|
118
|
+
/>
|
|
72
119
|
</template>
|
|
73
120
|
|
|
74
121
|
<template #more-actions v-if="$slots['more-actions']">
|
|
@@ -93,9 +140,9 @@ const props = defineProps({
|
|
|
93
140
|
:aria-label="!showHeader || !$slots.title ? ariaLabel : undefined"
|
|
94
141
|
>
|
|
95
142
|
<caption v-if="!showHeader && $slots.title"><slot name="title"></slot></caption>
|
|
96
|
-
<thead v-if="
|
|
143
|
+
<thead v-if="visibleColumns.length">
|
|
97
144
|
<Tr>
|
|
98
|
-
<Th v-for="column in
|
|
145
|
+
<Th v-for="column in visibleColumns"
|
|
99
146
|
:key="column.key"
|
|
100
147
|
scope="col"
|
|
101
148
|
:alignment="column?.alignment"
|
|
@@ -119,7 +166,7 @@ const props = defineProps({
|
|
|
119
166
|
:clickable="row.clickable ?? clickableRows"
|
|
120
167
|
@click="$emit('click:row', row)"
|
|
121
168
|
>
|
|
122
|
-
<Td v-for="column in
|
|
169
|
+
<Td v-for="column in visibleColumns"
|
|
123
170
|
:key="column.key"
|
|
124
171
|
:alignment="column?.alignment"
|
|
125
172
|
:fixed="fixedColumns"
|