@globalbrain/sefirot 4.14.1 → 4.14.2
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/lib/components/STable.vue +49 -72
- package/lib/support/Reactivity.ts +11 -0
- package/package.json +1 -1
|
@@ -1,18 +1,10 @@
|
|
|
1
|
-
<script setup lang="ts" generic="S extends any
|
|
1
|
+
<script setup lang="ts" generic="S extends any = undefined">
|
|
2
2
|
import { useVirtualizer } from '@tanstack/vue-virtual'
|
|
3
3
|
import { useResizeObserver } from '@vueuse/core'
|
|
4
4
|
import xor from 'lodash-es/xor'
|
|
5
|
-
import {
|
|
6
|
-
computed,
|
|
7
|
-
nextTick,
|
|
8
|
-
reactive,
|
|
9
|
-
ref,
|
|
10
|
-
shallowRef,
|
|
11
|
-
toValue,
|
|
12
|
-
unref,
|
|
13
|
-
watch
|
|
14
|
-
} from 'vue'
|
|
5
|
+
import { computed, nextTick, reactive, ref, shallowRef, toValue, unref, watch } from 'vue'
|
|
15
6
|
import { type Table } from '../composables/Table'
|
|
7
|
+
import { smartComputed } from '../support/Reactivity'
|
|
16
8
|
import { getTextWidth } from '../support/Text'
|
|
17
9
|
import SInputCheckbox from './SInputCheckbox.vue'
|
|
18
10
|
import SInputRadio from './SInputRadio.vue'
|
|
@@ -23,28 +15,24 @@ import STableFooter from './STableFooter.vue'
|
|
|
23
15
|
import STableHeader from './STableHeader.vue'
|
|
24
16
|
import STableItem from './STableItem.vue'
|
|
25
17
|
|
|
26
|
-
const props = defineProps<{
|
|
27
|
-
|
|
28
|
-
selected?: S
|
|
29
|
-
}>()
|
|
30
|
-
|
|
31
|
-
const emit = defineEmits<{
|
|
32
|
-
(e: 'update:selected', value: S): void
|
|
33
|
-
}>()
|
|
18
|
+
const props = defineProps<{ options: Table }>()
|
|
19
|
+
const selected = defineModel<S>('selected')
|
|
34
20
|
|
|
35
21
|
const head = shallowRef<HTMLElement | null>(null)
|
|
36
22
|
const body = shallowRef<HTMLElement | null>(null)
|
|
37
23
|
const block = shallowRef<HTMLElement | null>(null)
|
|
38
24
|
const row = shallowRef<HTMLElement | null>(null)
|
|
39
25
|
|
|
40
|
-
const ordersToShow =
|
|
26
|
+
const ordersToShow = smartComputed(() => {
|
|
41
27
|
const orders = unref(props.options.orders).filter((key) => {
|
|
42
28
|
const show = unref(props.options.columns)[key]?.show
|
|
43
29
|
return toValue(show) !== false
|
|
44
30
|
})
|
|
45
|
-
|
|
31
|
+
|
|
32
|
+
if (selected.value === undefined) {
|
|
46
33
|
return orders
|
|
47
34
|
}
|
|
35
|
+
|
|
48
36
|
return ['__select', ...orders]
|
|
49
37
|
})
|
|
50
38
|
|
|
@@ -126,51 +114,45 @@ const recordsWithSummary = computed(() => {
|
|
|
126
114
|
return summary ? [...records, summary] : records
|
|
127
115
|
})
|
|
128
116
|
|
|
129
|
-
const indexes =
|
|
130
|
-
if (
|
|
117
|
+
const indexes = smartComputed(() => {
|
|
118
|
+
if (selected.value === undefined) {
|
|
131
119
|
return []
|
|
132
120
|
}
|
|
121
|
+
|
|
133
122
|
const records = unref(props.options.records) ?? []
|
|
134
123
|
const indexField = unref(props.options.indexField)
|
|
135
124
|
|
|
136
|
-
return records.map((record, i) => indexField ? record[indexField] : i)
|
|
125
|
+
return records.map((record, i) => (indexField ? record[indexField] : i))
|
|
137
126
|
})
|
|
138
127
|
|
|
139
|
-
const selectedIndexes = reactive(new Set(Array.isArray(props.selected) ? props.selected : []))
|
|
140
|
-
|
|
141
128
|
const control = computed({
|
|
142
129
|
get() {
|
|
143
|
-
if (Array.isArray(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
130
|
+
if (Array.isArray(selected.value)) {
|
|
131
|
+
if (!selected.value.length) {
|
|
132
|
+
return false
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (selected.value.length === indexes.value.length) {
|
|
136
|
+
return true
|
|
137
|
+
}
|
|
147
138
|
}
|
|
148
139
|
|
|
149
|
-
return 'indeterminate'
|
|
140
|
+
return 'indeterminate'
|
|
150
141
|
},
|
|
151
142
|
|
|
152
143
|
set(newValue) {
|
|
153
144
|
if (newValue === false) {
|
|
154
|
-
|
|
145
|
+
updateSelected([])
|
|
155
146
|
} else if (newValue === true) {
|
|
156
|
-
indexes.value
|
|
157
|
-
selectedIndexes.add(index)
|
|
158
|
-
})
|
|
147
|
+
updateSelected(indexes.value)
|
|
159
148
|
}
|
|
160
149
|
}
|
|
161
150
|
})
|
|
162
151
|
|
|
163
152
|
watch(indexes, (newValue, oldValue) => {
|
|
164
|
-
if (Array.isArray(
|
|
165
|
-
xor(newValue, oldValue)
|
|
166
|
-
|
|
167
|
-
})
|
|
168
|
-
}
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
watch(selectedIndexes, (newValue) => {
|
|
172
|
-
if (Array.isArray(props.selected)) {
|
|
173
|
-
updateSelected(Array.from(newValue))
|
|
153
|
+
if (Array.isArray(selected.value)) {
|
|
154
|
+
const removed = xor(newValue, oldValue)
|
|
155
|
+
updateSelected(selected.value.filter((item) => !removed.includes(item)))
|
|
174
156
|
}
|
|
175
157
|
})
|
|
176
158
|
|
|
@@ -256,10 +238,9 @@ watch(actionsColumnWidth, (newValue) => {
|
|
|
256
238
|
|
|
257
239
|
function stopObserving() {
|
|
258
240
|
const orders = ordersToShow.value
|
|
259
|
-
const lastOrder
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
: orders[orders.length - 1]
|
|
241
|
+
const lastOrder = orders[orders.length - 1] === 'actions'
|
|
242
|
+
? orders[orders.length - 2]
|
|
243
|
+
: orders[orders.length - 1]
|
|
263
244
|
colWidths[lastOrder] = 'auto'
|
|
264
245
|
resizeObserver.stop()
|
|
265
246
|
}
|
|
@@ -284,10 +265,7 @@ async function handleResize() {
|
|
|
284
265
|
}
|
|
285
266
|
|
|
286
267
|
const availableFill = row.value.getBoundingClientRect().width - totalWidth
|
|
287
|
-
updateColWidth(
|
|
288
|
-
nameOfColToGrow.value,
|
|
289
|
-
`calc(${availableFill}px + ${initialWidth})`
|
|
290
|
-
)
|
|
268
|
+
updateColWidth(nameOfColToGrow.value, `calc(${availableFill}px + ${initialWidth})`)
|
|
291
269
|
}
|
|
292
270
|
|
|
293
271
|
function syncHeadScroll() {
|
|
@@ -341,18 +319,24 @@ function getCell(key: string, index: number) {
|
|
|
341
319
|
return { type: 'custom' }
|
|
342
320
|
}
|
|
343
321
|
const col = unref(props.options.columns)[key]
|
|
344
|
-
return
|
|
322
|
+
return isSummary(index) && col?.summaryCell ? col?.summaryCell : col?.cell
|
|
345
323
|
}
|
|
346
324
|
|
|
347
|
-
function updateSelected(
|
|
348
|
-
if (Array.isArray(
|
|
349
|
-
|
|
350
|
-
emit('update:selected', selected)
|
|
351
|
-
}
|
|
325
|
+
function updateSelected(items: any) {
|
|
326
|
+
if (Array.isArray(selected.value)) {
|
|
327
|
+
selected.value = [...items] as any
|
|
352
328
|
} else {
|
|
353
|
-
|
|
329
|
+
selected.value = items
|
|
354
330
|
}
|
|
355
331
|
}
|
|
332
|
+
|
|
333
|
+
function addSelected(item: any) {
|
|
334
|
+
updateSelected([...(selected.value as any), item])
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function removeSelected(item: any) {
|
|
338
|
+
updateSelected((selected.value as any[]).filter((i) => i !== item))
|
|
339
|
+
}
|
|
356
340
|
</script>
|
|
357
341
|
|
|
358
342
|
<template>
|
|
@@ -369,11 +353,7 @@ function updateSelected(selected: any) {
|
|
|
369
353
|
/>
|
|
370
354
|
|
|
371
355
|
<div class="table" role="grid">
|
|
372
|
-
<div
|
|
373
|
-
class="container head"
|
|
374
|
-
ref="head"
|
|
375
|
-
@scroll="syncHeadScroll"
|
|
376
|
-
>
|
|
356
|
+
<div class="container head" ref="head" @scroll="syncHeadScroll">
|
|
377
357
|
<div class="block" ref="block">
|
|
378
358
|
<div class="row" ref="row">
|
|
379
359
|
<STableItem
|
|
@@ -421,10 +401,7 @@ function updateSelected(selected: any) {
|
|
|
421
401
|
position: 'relative'
|
|
422
402
|
}"
|
|
423
403
|
>
|
|
424
|
-
<div
|
|
425
|
-
v-for="{ index, key: __key, size, start } in virtualItems"
|
|
426
|
-
:key="__key"
|
|
427
|
-
>
|
|
404
|
+
<div v-for="{ index, key: __key, size, start } in virtualItems" :key="__key">
|
|
428
405
|
<div
|
|
429
406
|
class="row"
|
|
430
407
|
:class="isSummaryOrLastClass(index)"
|
|
@@ -456,14 +433,14 @@ function updateSelected(selected: any) {
|
|
|
456
433
|
<template v-if="key === '__select' && !isSummary(index)">
|
|
457
434
|
<SInputCheckbox
|
|
458
435
|
v-if="Array.isArray(selected)"
|
|
459
|
-
:model-value="
|
|
460
|
-
@update:model-value="c =>
|
|
436
|
+
:model-value="selected.includes(indexes[index])"
|
|
437
|
+
@update:model-value="(c) => (c ? addSelected : removeSelected)(indexes[index])"
|
|
461
438
|
:disabled="options.disableSelection?.(recordsWithSummary[index]) === true"
|
|
462
439
|
/>
|
|
463
440
|
<SInputRadio
|
|
464
441
|
v-else
|
|
465
442
|
:model-value="selected === indexes[index]"
|
|
466
|
-
@update:model-value="c => updateSelected(c ? indexes[index] : null)"
|
|
443
|
+
@update:model-value="(c) => updateSelected(c ? indexes[index] : null)"
|
|
467
444
|
:disabled="options.disableSelection?.(recordsWithSummary[index]) === true"
|
|
468
445
|
/>
|
|
469
446
|
</template>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ComputedRef, computed } from 'vue'
|
|
2
|
+
|
|
3
|
+
export function smartComputed<T>(
|
|
4
|
+
getter: () => T,
|
|
5
|
+
comparator = (oldValue: T, newValue: T) => JSON.stringify(oldValue) === JSON.stringify(newValue)
|
|
6
|
+
): ComputedRef<T> {
|
|
7
|
+
return computed((oldValue) => {
|
|
8
|
+
const newValue = getter()
|
|
9
|
+
return oldValue === undefined || !comparator(oldValue, newValue) ? newValue : oldValue
|
|
10
|
+
})
|
|
11
|
+
}
|
package/package.json
CHANGED