@globalbrain/sefirot 4.14.1 → 4.15.0
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/SButton.vue +2 -2
- package/lib/components/SControlActionBarButton.vue +1 -1
- package/lib/components/SControlActionBarClose.vue +1 -1
- package/lib/components/SControlActionBarCollapse.vue +1 -1
- package/lib/components/SControlButton.vue +1 -1
- package/lib/components/SControlInputSearch.vue +4 -4
- package/lib/components/SControlPagination.vue +2 -2
- package/lib/components/SDropdownSectionDateRangeDateFromTo.vue +1 -1
- package/lib/components/SDropdownSectionDateRangeYear.vue +1 -1
- package/lib/components/SDropdownSectionDateRangeYearHalf.vue +1 -1
- package/lib/components/SDropdownSectionDateRangeYearQuarter.vue +1 -1
- package/lib/components/SErrorBoundary.vue +1 -1
- package/lib/components/SInputAddon.vue +1 -1
- package/lib/components/SInputCheckbox.vue +2 -2
- package/lib/components/SInputCheckboxes.vue +2 -2
- package/lib/components/SInputDate.vue +1 -1
- package/lib/components/SInputFile.vue +2 -2
- package/lib/components/SInputFileUploadItem.vue +1 -1
- package/lib/components/SInputHMS.vue +2 -2
- package/lib/components/SInputImage.vue +2 -2
- package/lib/components/SInputRadio.vue +2 -2
- package/lib/components/SInputRadios.vue +2 -2
- package/lib/components/SInputSegments.vue +2 -2
- package/lib/components/SInputSegmentsOption.vue +1 -1
- package/lib/components/SInputSelect.vue +2 -2
- package/lib/components/SInputSwitch.vue +2 -2
- package/lib/components/SInputSwitches.vue +1 -1
- package/lib/components/SInputYMD.vue +2 -2
- package/lib/components/SMarkdown.vue +1 -1
- package/lib/components/SModal.vue +1 -1
- package/lib/components/SPagination.vue +2 -2
- package/lib/components/SPill.vue +1 -1
- package/lib/components/STable.vue +95 -74
- package/lib/components/STableColumn.vue +1 -1
- package/lib/composables/Table.ts +1 -0
- package/lib/support/Reactivity.ts +11 -0
- package/package.json +1 -1
|
@@ -19,10 +19,10 @@ const props = defineProps<{
|
|
|
19
19
|
}>()
|
|
20
20
|
|
|
21
21
|
defineEmits<{
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
'update:model-value': [value: string | null]
|
|
23
|
+
'input': [value: string | null]
|
|
24
|
+
'blur': [value: string | null]
|
|
25
|
+
'enter': [value: string | null]
|
|
26
26
|
}>()
|
|
27
27
|
|
|
28
28
|
const { t } = useTrans({
|
|
@@ -29,8 +29,8 @@ const props = withDefaults(defineProps<{
|
|
|
29
29
|
})
|
|
30
30
|
|
|
31
31
|
const emit = defineEmits<{
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
'update:model-value': [value: boolean]
|
|
33
|
+
'change': [value: boolean]
|
|
34
34
|
}>()
|
|
35
35
|
|
|
36
36
|
const classes = computed(() => [
|
|
@@ -37,8 +37,8 @@ const props = withDefaults(defineProps<{
|
|
|
37
37
|
})
|
|
38
38
|
|
|
39
39
|
const emit = defineEmits<{
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
'update:model-value': [value: Value[]]
|
|
41
|
+
'change': [value: Value[]]
|
|
42
42
|
}>()
|
|
43
43
|
|
|
44
44
|
const _value = computed(() => {
|
|
@@ -26,8 +26,8 @@ const props = defineProps<{
|
|
|
26
26
|
}>()
|
|
27
27
|
|
|
28
28
|
const emit = defineEmits<{
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
'update:model-value': [file: File | File[] | null]
|
|
30
|
+
'change': [file: File | File[] | null]
|
|
31
31
|
}>()
|
|
32
32
|
|
|
33
33
|
const _value = computed(() => {
|
|
@@ -41,8 +41,8 @@ const props = defineProps<{
|
|
|
41
41
|
}>()
|
|
42
42
|
|
|
43
43
|
const emit = defineEmits<{
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
'update:model-value': [value: Value]
|
|
45
|
+
'change': [value: Value]
|
|
46
46
|
}>()
|
|
47
47
|
|
|
48
48
|
const _value = computed(() => {
|
|
@@ -42,8 +42,8 @@ const props = withDefaults(defineProps<{
|
|
|
42
42
|
})
|
|
43
43
|
|
|
44
44
|
const emit = defineEmits<{
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
'update:model-value': [file: File | null]
|
|
46
|
+
'change': [file: File | null]
|
|
47
47
|
}>()
|
|
48
48
|
|
|
49
49
|
const fileInput = ref<HTMLInputElement | null>(null)
|
|
@@ -24,8 +24,8 @@ const props = defineProps<{
|
|
|
24
24
|
}>()
|
|
25
25
|
|
|
26
26
|
const emit = defineEmits<{
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
'update:model-value': [value: boolean]
|
|
28
|
+
'change': [value: boolean]
|
|
29
29
|
}>()
|
|
30
30
|
|
|
31
31
|
const classes = computed(() => [
|
|
@@ -47,8 +47,8 @@ const props = withDefaults(defineProps<{
|
|
|
47
47
|
})
|
|
48
48
|
|
|
49
49
|
const emit = defineEmits<{
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
'update:model-value': [value: ValueType | NullValue]
|
|
51
|
+
'change': [value: ValueType | NullValue]
|
|
52
52
|
}>()
|
|
53
53
|
|
|
54
54
|
const _value = computed(() => {
|
|
@@ -38,8 +38,8 @@ const props = withDefaults(defineProps<{
|
|
|
38
38
|
})
|
|
39
39
|
|
|
40
40
|
const emit = defineEmits<{
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
'update:model-value': [value: Value]
|
|
42
|
+
'change': [value: Value]
|
|
43
43
|
}>()
|
|
44
44
|
|
|
45
45
|
const _value = computed(() => {
|
|
@@ -30,8 +30,8 @@ const props = withDefaults(defineProps<{
|
|
|
30
30
|
})
|
|
31
31
|
|
|
32
32
|
const emit = defineEmits<{
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
'update:model-value': [value: boolean]
|
|
34
|
+
'change': [value: boolean]
|
|
35
35
|
}>()
|
|
36
36
|
|
|
37
37
|
const _value = computed(() => {
|
|
@@ -42,8 +42,8 @@ const props = defineProps<{
|
|
|
42
42
|
}>()
|
|
43
43
|
|
|
44
44
|
const emit = defineEmits<{
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
'update:model-value': [value: Value]
|
|
46
|
+
'change': [value: Value]
|
|
47
47
|
}>()
|
|
48
48
|
|
|
49
49
|
const _value = computed(() => {
|
package/lib/components/SPill.vue
CHANGED
|
@@ -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
|
|
|
@@ -202,6 +184,21 @@ watch(() => unref(props.options.records), () => {
|
|
|
202
184
|
isSyncingBody = false
|
|
203
185
|
}, { flush: 'post' })
|
|
204
186
|
|
|
187
|
+
const frozenColumns = smartComputed(() => {
|
|
188
|
+
const columns = unref(props.options.columns)
|
|
189
|
+
const keys = Object.keys(columns).filter((key) => columns[key].freeze)
|
|
190
|
+
if (selected.value !== undefined && keys.length) {
|
|
191
|
+
keys.unshift('__select')
|
|
192
|
+
}
|
|
193
|
+
return keys.filter((key) => ordersToShow.value.includes(key))
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
const frozenColWidths = smartComputed(() => {
|
|
197
|
+
// eslint-disable-next-line no-void
|
|
198
|
+
void blockWidth.value
|
|
199
|
+
return frozenColumns.value.map((key) => getColWidth(key))
|
|
200
|
+
})
|
|
201
|
+
|
|
205
202
|
useResizeObserver(block, ([entry]) => {
|
|
206
203
|
blockWidth.value = entry.contentRect.width
|
|
207
204
|
})
|
|
@@ -256,10 +253,9 @@ watch(actionsColumnWidth, (newValue) => {
|
|
|
256
253
|
|
|
257
254
|
function stopObserving() {
|
|
258
255
|
const orders = ordersToShow.value
|
|
259
|
-
const lastOrder
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
: orders[orders.length - 1]
|
|
256
|
+
const lastOrder = orders[orders.length - 1] === 'actions'
|
|
257
|
+
? orders[orders.length - 2]
|
|
258
|
+
: orders[orders.length - 1]
|
|
263
259
|
colWidths[lastOrder] = 'auto'
|
|
264
260
|
resizeObserver.stop()
|
|
265
261
|
}
|
|
@@ -284,10 +280,7 @@ async function handleResize() {
|
|
|
284
280
|
}
|
|
285
281
|
|
|
286
282
|
const availableFill = row.value.getBoundingClientRect().width - totalWidth
|
|
287
|
-
updateColWidth(
|
|
288
|
-
nameOfColToGrow.value,
|
|
289
|
-
`calc(${availableFill}px + ${initialWidth})`
|
|
290
|
-
)
|
|
283
|
+
updateColWidth(nameOfColToGrow.value, `calc(${availableFill}px + ${initialWidth})`)
|
|
291
284
|
}
|
|
292
285
|
|
|
293
286
|
function syncHeadScroll() {
|
|
@@ -341,16 +334,50 @@ function getCell(key: string, index: number) {
|
|
|
341
334
|
return { type: 'custom' }
|
|
342
335
|
}
|
|
343
336
|
const col = unref(props.options.columns)[key]
|
|
344
|
-
return
|
|
337
|
+
return isSummary(index) && col?.summaryCell ? col?.summaryCell : col?.cell
|
|
345
338
|
}
|
|
346
339
|
|
|
347
|
-
function updateSelected(
|
|
348
|
-
if (Array.isArray(
|
|
349
|
-
|
|
350
|
-
emit('update:selected', selected)
|
|
351
|
-
}
|
|
340
|
+
function updateSelected(items: any) {
|
|
341
|
+
if (Array.isArray(selected.value)) {
|
|
342
|
+
selected.value = [...items] as any
|
|
352
343
|
} else {
|
|
353
|
-
|
|
344
|
+
selected.value = items
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function addSelected(item: any) {
|
|
349
|
+
updateSelected([...(selected.value as any), item])
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function removeSelected(item: any) {
|
|
353
|
+
updateSelected((selected.value as any[]).filter((i) => i !== item))
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function getColWidth(key: string) {
|
|
357
|
+
if (key === '__select') {
|
|
358
|
+
return '48px + var(--table-padding-left, 0)'
|
|
359
|
+
}
|
|
360
|
+
const adjustedWidth = colWidths[key]
|
|
361
|
+
if (adjustedWidth && adjustedWidth !== 'auto') {
|
|
362
|
+
return adjustedWidth
|
|
363
|
+
}
|
|
364
|
+
const el = row.value?.children?.[ordersToShow.value.indexOf(key)]
|
|
365
|
+
if (!el) {
|
|
366
|
+
return '0px'
|
|
367
|
+
}
|
|
368
|
+
return `${el.getBoundingClientRect().width}px`
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function getStyles(key: string) {
|
|
372
|
+
const length = frozenColumns.value.length
|
|
373
|
+
if (length === 0) { return }
|
|
374
|
+
const i = frozenColumns.value.indexOf(key)
|
|
375
|
+
if (i < 0) { return }
|
|
376
|
+
const widthSum = frozenColWidths.value.slice(0, i).join(' + ')
|
|
377
|
+
return {
|
|
378
|
+
'--table-col-position': 'sticky',
|
|
379
|
+
'--table-col-z-index': length - i, // left to right decreasing
|
|
380
|
+
'--table-col-left': widthSum ? `calc(${widthSum})` : '0px'
|
|
354
381
|
}
|
|
355
382
|
}
|
|
356
383
|
</script>
|
|
@@ -369,11 +396,7 @@ function updateSelected(selected: any) {
|
|
|
369
396
|
/>
|
|
370
397
|
|
|
371
398
|
<div class="table" role="grid">
|
|
372
|
-
<div
|
|
373
|
-
class="container head"
|
|
374
|
-
ref="head"
|
|
375
|
-
@scroll="syncHeadScroll"
|
|
376
|
-
>
|
|
399
|
+
<div class="container head" ref="head" @scroll="syncHeadScroll">
|
|
377
400
|
<div class="block" ref="block">
|
|
378
401
|
<div class="row" ref="row">
|
|
379
402
|
<STableItem
|
|
@@ -381,6 +404,7 @@ function updateSelected(selected: any) {
|
|
|
381
404
|
:key="key"
|
|
382
405
|
:name="key"
|
|
383
406
|
:class-name="unref(options.columns)[key]?.className"
|
|
407
|
+
:style="getStyles(key)"
|
|
384
408
|
:width="colWidths[key]"
|
|
385
409
|
>
|
|
386
410
|
<STableColumn
|
|
@@ -421,10 +445,7 @@ function updateSelected(selected: any) {
|
|
|
421
445
|
position: 'relative'
|
|
422
446
|
}"
|
|
423
447
|
>
|
|
424
|
-
<div
|
|
425
|
-
v-for="{ index, key: __key, size, start } in virtualItems"
|
|
426
|
-
:key="__key"
|
|
427
|
-
>
|
|
448
|
+
<div v-for="{ index, key: __key, size, start } in virtualItems" :key="__key">
|
|
428
449
|
<div
|
|
429
450
|
class="row"
|
|
430
451
|
:class="isSummaryOrLastClass(index)"
|
|
@@ -442,6 +463,7 @@ function updateSelected(selected: any) {
|
|
|
442
463
|
:key="key"
|
|
443
464
|
:name="key"
|
|
444
465
|
:class-name="unref(options.columns)[key]?.className"
|
|
466
|
+
:style="getStyles(key)"
|
|
445
467
|
:width="colWidths[key]"
|
|
446
468
|
>
|
|
447
469
|
<STableCell
|
|
@@ -456,14 +478,14 @@ function updateSelected(selected: any) {
|
|
|
456
478
|
<template v-if="key === '__select' && !isSummary(index)">
|
|
457
479
|
<SInputCheckbox
|
|
458
480
|
v-if="Array.isArray(selected)"
|
|
459
|
-
:model-value="
|
|
460
|
-
@update:model-value="c =>
|
|
481
|
+
:model-value="selected.includes(indexes[index])"
|
|
482
|
+
@update:model-value="(c) => (c ? addSelected : removeSelected)(indexes[index])"
|
|
461
483
|
:disabled="options.disableSelection?.(recordsWithSummary[index]) === true"
|
|
462
484
|
/>
|
|
463
485
|
<SInputRadio
|
|
464
486
|
v-else
|
|
465
487
|
:model-value="selected === indexes[index]"
|
|
466
|
-
@update:model-value="c => updateSelected(c ? indexes[index] : null)"
|
|
488
|
+
@update:model-value="(c) => updateSelected(c ? indexes[index] : null)"
|
|
467
489
|
:disabled="options.disableSelection?.(recordsWithSummary[index]) === true"
|
|
468
490
|
/>
|
|
469
491
|
</template>
|
|
@@ -609,8 +631,7 @@ function updateSelected(selected: any) {
|
|
|
609
631
|
}
|
|
610
632
|
|
|
611
633
|
.STable .col-__select {
|
|
612
|
-
--table-padding-left
|
|
613
|
-
--table-col-width: 48px;
|
|
634
|
+
--table-col-width: calc(48px + var(--table-padding-left, 0));
|
|
614
635
|
|
|
615
636
|
:deep(.input) {
|
|
616
637
|
align-items: center;
|
package/lib/composables/Table.ts
CHANGED
|
@@ -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