@bagelink/vue 1.0.16 → 1.0.22
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/dist/components/Spreadsheet/Index.vue.d.ts +89 -1
- package/dist/components/Spreadsheet/Index.vue.d.ts.map +1 -1
- package/dist/components/Spreadsheet/SpreadsheetTable.vue.d.ts +37 -0
- package/dist/components/Spreadsheet/SpreadsheetTable.vue.d.ts.map +1 -0
- package/dist/composables/useSchemaField.d.ts.map +1 -1
- package/dist/index.cjs +1070 -940
- package/dist/index.mjs +1070 -940
- package/dist/style.css +45 -19
- package/dist/utils/BagelFormUtils.d.ts +11 -0
- package/dist/utils/BagelFormUtils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/Spreadsheet/Index.vue +176 -257
- package/src/components/Spreadsheet/SpreadsheetTable.vue +316 -0
- package/src/composables/useSchemaField.ts +3 -1
- package/src/utils/BagelFormUtils.ts +30 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import { Btn,
|
|
3
|
-
import { computed, ref, watch, nextTick } from 'vue'
|
|
2
|
+
import { Btn, CheckInput, TextInput } from '@bagelink/vue'
|
|
3
|
+
import { computed, ref, watch, nextTick, onUnmounted } from 'vue'
|
|
4
|
+
import Dropdown from '../Dropdown.vue'
|
|
5
|
+
import SpreadsheetTable from './SpreadsheetTable.vue'
|
|
4
6
|
|
|
5
7
|
// Define column configuration types
|
|
6
8
|
type ColumnFormat = 'text' | 'number' | 'currency' | 'date' | 'percentage' | 'image' | 'boolean'
|
|
@@ -91,6 +93,9 @@ function emitUpdate() {
|
|
|
91
93
|
emit('update:modelValue', localRows.value.map(row => unflattenObject({ ...row })))
|
|
92
94
|
}
|
|
93
95
|
|
|
96
|
+
// After other ref declarations but before the columns computed property
|
|
97
|
+
const visibleColumns = ref<string[]>([])
|
|
98
|
+
|
|
94
99
|
// Sort state
|
|
95
100
|
const sortColumn = ref<string | null>(null)
|
|
96
101
|
const sortDirection = ref<'asc' | 'desc'>('asc')
|
|
@@ -178,7 +183,7 @@ function isCellEditable(columnKey: string): boolean {
|
|
|
178
183
|
return !(column?.locked ?? false)
|
|
179
184
|
}
|
|
180
185
|
|
|
181
|
-
//
|
|
186
|
+
// Update the sortByColumn function to preserve column visibility
|
|
182
187
|
function sortByColumn(columnKey: string) {
|
|
183
188
|
const column = columns.value.find(col => col.key === columnKey)
|
|
184
189
|
if (!column?.sortable) return
|
|
@@ -202,8 +207,16 @@ function sortByColumn(columnKey: string) {
|
|
|
202
207
|
return aVal < bVal ? -modifier : modifier
|
|
203
208
|
})
|
|
204
209
|
|
|
210
|
+
// Save the current visibleColumns state
|
|
211
|
+
const currentVisibleColumns = [...visibleColumns.value]
|
|
212
|
+
|
|
205
213
|
localRows.value = sorted
|
|
206
214
|
emitUpdate()
|
|
215
|
+
|
|
216
|
+
// Restore the visibleColumns state after the update
|
|
217
|
+
nextTick(() => {
|
|
218
|
+
visibleColumns.value = currentVisibleColumns
|
|
219
|
+
})
|
|
207
220
|
}
|
|
208
221
|
|
|
209
222
|
// Variables to handle cell selection
|
|
@@ -232,15 +245,15 @@ function setInputRef(el: any, key: string) {
|
|
|
232
245
|
}
|
|
233
246
|
}
|
|
234
247
|
|
|
235
|
-
// Determines if the given cell is within the currently selected range
|
|
236
|
-
function isCellSelected(row: number, col: number): boolean {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
}
|
|
248
|
+
// // Determines if the given cell is within the currently selected range
|
|
249
|
+
// function isCellSelected(row: number, col: number): boolean {
|
|
250
|
+
// if (!selectionStart.value || !selectionEnd.value) return false
|
|
251
|
+
// const startRow = Math.min(selectionStart.value.row, selectionEnd.value.row)
|
|
252
|
+
// const endRow = Math.max(selectionStart.value.row, selectionEnd.value.row)
|
|
253
|
+
// const startCol = Math.min(selectionStart.value.col, selectionEnd.value.col)
|
|
254
|
+
// const endCol = Math.max(selectionStart.value.col, selectionEnd.value.col)
|
|
255
|
+
// return row >= startRow && row <= endRow && col >= startCol && col <= endCol
|
|
256
|
+
// }
|
|
244
257
|
|
|
245
258
|
// Mouse event handlers to manage the selection range
|
|
246
259
|
function handleMouseDown(row: number, col: number) {
|
|
@@ -356,13 +369,25 @@ function updateCell(rowIndex: number, key: string, newValue: string | boolean) {
|
|
|
356
369
|
emitUpdate()
|
|
357
370
|
}
|
|
358
371
|
|
|
359
|
-
//
|
|
372
|
+
// After other ref declarations but before computed properties
|
|
373
|
+
// const visibleColumns = ref<string[]>([])
|
|
374
|
+
|
|
375
|
+
// After the columns computed property
|
|
376
|
+
// Initialize visibleColumns with all columns when columns change
|
|
377
|
+
watch(() => columns.value, (newColumns) => {
|
|
378
|
+
if (newColumns.length > 0 && visibleColumns.value.length === 0) {
|
|
379
|
+
visibleColumns.value = newColumns.filter(col => !col.hidden).map(col => col.key)
|
|
380
|
+
}
|
|
381
|
+
})
|
|
382
|
+
|
|
383
|
+
// Update the fixedColumns computed property
|
|
360
384
|
const fixedColumns = computed(() => {
|
|
361
|
-
return columns.value.filter(col => col.fixed && !col.hidden)
|
|
385
|
+
return columns.value.filter(col => col.fixed && !col.hidden && visibleColumns.value.includes(col.key))
|
|
362
386
|
})
|
|
363
387
|
|
|
388
|
+
// Update the scrollableColumns computed property
|
|
364
389
|
const scrollableColumns = computed(() => {
|
|
365
|
-
return columns.value.filter(col => !col.fixed && !col.hidden)
|
|
390
|
+
return columns.value.filter(col => !col.fixed && !col.hidden && visibleColumns.value.includes(col.key))
|
|
366
391
|
})
|
|
367
392
|
|
|
368
393
|
// Update createEmptyRow to use defaultValue from column config
|
|
@@ -418,7 +443,16 @@ async function copySelection() {
|
|
|
418
443
|
}
|
|
419
444
|
}
|
|
420
445
|
|
|
421
|
-
//
|
|
446
|
+
// Add a ref for the search input
|
|
447
|
+
const searchInputRef = ref<any>(null)
|
|
448
|
+
|
|
449
|
+
// Add a method to check if the search input is focused
|
|
450
|
+
function isSearchFocused(): boolean {
|
|
451
|
+
const inputElement = searchInputRef.value?.$el?.querySelector('input')
|
|
452
|
+
return document.activeElement === inputElement
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Update the pasteSelection function to handle search focus
|
|
422
456
|
async function pasteSelection() {
|
|
423
457
|
if (!selectionStart.value) return
|
|
424
458
|
|
|
@@ -543,8 +577,8 @@ function handleCellKeyDown(event: KeyboardEvent, row: number, col: number) {
|
|
|
543
577
|
// Update keyboard shortcuts to include undo/redo
|
|
544
578
|
function handleSpreadsheetKeyDown(event: KeyboardEvent) {
|
|
545
579
|
// Don't intercept keyboard shortcuts when editing a cell
|
|
546
|
-
if (editingCell.value) return
|
|
547
|
-
|
|
580
|
+
if (editingCell.value || isSearchFocused()) return
|
|
581
|
+
console.log('handleSpreadsheetKeyDown', event)
|
|
548
582
|
const isCtrlOrCmd = event.ctrlKey || event.metaKey
|
|
549
583
|
|
|
550
584
|
if (isCtrlOrCmd) {
|
|
@@ -593,6 +627,64 @@ const filteredRows = computed(() => {
|
|
|
593
627
|
})
|
|
594
628
|
})
|
|
595
629
|
})
|
|
630
|
+
|
|
631
|
+
// Add after other ref declarations
|
|
632
|
+
const columnWidths = ref<Map<string, number>>(new Map())
|
|
633
|
+
const isResizing = ref(false)
|
|
634
|
+
const resizingColumn = ref<string | null>(null)
|
|
635
|
+
const startX = ref<number>(0)
|
|
636
|
+
const startWidth = ref<number>(0)
|
|
637
|
+
|
|
638
|
+
// Add after other function declarations
|
|
639
|
+
function handleResizeStart(e: MouseEvent, columnKey: string) {
|
|
640
|
+
isResizing.value = true
|
|
641
|
+
resizingColumn.value = columnKey
|
|
642
|
+
startX.value = e.pageX
|
|
643
|
+
|
|
644
|
+
// Find the column header element
|
|
645
|
+
const columnHeader = (e.target as HTMLElement).closest('th')
|
|
646
|
+
if (!columnHeader) return
|
|
647
|
+
|
|
648
|
+
// Get the actual computed width of the column
|
|
649
|
+
const computedWidth = columnHeader.getBoundingClientRect().width
|
|
650
|
+
const currentWidth = columnWidths.value.get(columnKey) || computedWidth
|
|
651
|
+
startWidth.value = currentWidth
|
|
652
|
+
|
|
653
|
+
// Add event listeners for mousemove and mouseup
|
|
654
|
+
document.addEventListener('mousemove', handleResizeMove)
|
|
655
|
+
document.addEventListener('mouseup', handleResizeEnd)
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
function handleResizeMove(e: MouseEvent) {
|
|
659
|
+
if (!isResizing.value || !resizingColumn.value) return
|
|
660
|
+
|
|
661
|
+
e.preventDefault()
|
|
662
|
+
|
|
663
|
+
const diff = e.pageX - startX.value
|
|
664
|
+
const newWidth = Math.max(80, startWidth.value + diff) // Keep minimum width of 80px
|
|
665
|
+
|
|
666
|
+
columnWidths.value.set(resizingColumn.value, newWidth)
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
function handleResizeEnd() {
|
|
670
|
+
isResizing.value = false
|
|
671
|
+
resizingColumn.value = null
|
|
672
|
+
|
|
673
|
+
// Remove event listeners
|
|
674
|
+
document.removeEventListener('mousemove', handleResizeMove)
|
|
675
|
+
document.removeEventListener('mouseup', handleResizeEnd)
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// Clean up event listeners when component is unmounted
|
|
679
|
+
onUnmounted(() => {
|
|
680
|
+
document.removeEventListener('mousemove', handleResizeMove)
|
|
681
|
+
document.removeEventListener('mouseup', handleResizeEnd)
|
|
682
|
+
})
|
|
683
|
+
|
|
684
|
+
// Add a computed property for visible column options
|
|
685
|
+
const columnOptions = computed(() => {
|
|
686
|
+
return columns.value.filter(col => !col.hidden)
|
|
687
|
+
})
|
|
596
688
|
</script>
|
|
597
689
|
|
|
598
690
|
<template>
|
|
@@ -600,7 +692,22 @@ const filteredRows = computed(() => {
|
|
|
600
692
|
<div class="flex gap-05 py-05 justify-content-end m_flex-wrap">
|
|
601
693
|
<label v-if="label" class="label me-auto">{{ label }}</label>
|
|
602
694
|
<div class="flex gap-075">
|
|
603
|
-
<
|
|
695
|
+
<Dropdown flat thin icon="view_column">
|
|
696
|
+
<div class="p-05">
|
|
697
|
+
<div class="flex space-between">
|
|
698
|
+
<Btn flat thin small value="Select All" @click="visibleColumns = columnOptions.map(col => col.key)" />
|
|
699
|
+
<Btn flat thin small value="Clear All" @click="visibleColumns = []" />
|
|
700
|
+
</div>
|
|
701
|
+
<CheckInput
|
|
702
|
+
v-for="col in columnOptions"
|
|
703
|
+
:key="col.key"
|
|
704
|
+
v-model="visibleColumns"
|
|
705
|
+
:value="col.key"
|
|
706
|
+
:label="col.label || col.key"
|
|
707
|
+
/>
|
|
708
|
+
</div>
|
|
709
|
+
</Dropdown>
|
|
710
|
+
<TextInput ref="searchInputRef" v-model="search" icon="search" placeholder="Search" class="m-0 max-w200px" />
|
|
604
711
|
<Btn v-tooltip="'Paste'" flat thin round icon="paste" @click="pasteSelection" />
|
|
605
712
|
<Btn v-tooltip="'copy'" flat thin round icon="copy" @click="copySelection" />
|
|
606
713
|
<Btn v-tooltip="'Undo'" flat thin round icon="undo" :disabled="!canUndo" @click="undo" />
|
|
@@ -610,156 +717,57 @@ const filteredRows = computed(() => {
|
|
|
610
717
|
<div class="spreadsheet" @mouseup="handleMouseUp">
|
|
611
718
|
<div class="flex w-100p relative">
|
|
612
719
|
<!-- Fixed Columns -->
|
|
613
|
-
<
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
v-for="col in fixedColumns"
|
|
639
|
-
:key="col.key"
|
|
640
|
-
:class="{
|
|
641
|
-
selected: isCellSelected(rowIndex, fixedColumns.indexOf(col)),
|
|
642
|
-
locked: !isCellEditable(col.key),
|
|
643
|
-
}"
|
|
644
|
-
:style="{ width: col.width }"
|
|
645
|
-
:tabindex="col.hidden ? undefined : 0"
|
|
646
|
-
@mousedown="handleMouseDown(rowIndex, fixedColumns.indexOf(col))"
|
|
647
|
-
@mouseover="handleMouseOver(rowIndex, fixedColumns.indexOf(col))"
|
|
648
|
-
@focusin="handleMouseOver(rowIndex, fixedColumns.indexOf(col))"
|
|
649
|
-
@dblclick="startEditing(rowIndex, fixedColumns.indexOf(col))"
|
|
650
|
-
@keydown="handleCellKeyDown($event, rowIndex, fixedColumns.indexOf(col))"
|
|
651
|
-
>
|
|
652
|
-
<template v-if="editingCell && editingCell.row === rowIndex && editingCell.col === fixedColumns.indexOf(col)">
|
|
653
|
-
<input
|
|
654
|
-
:ref="el => setInputRef(el, `cell-${rowIndex}-${fixedColumns.indexOf(col)}`)"
|
|
655
|
-
:value="row[col.key]"
|
|
656
|
-
type="text"
|
|
657
|
-
class="spreadsheet-input"
|
|
658
|
-
@input="(e: Event) => updateCell(rowIndex, col.key, (e.target as HTMLInputElement).value)"
|
|
659
|
-
@blur="handleStopEditingAndBlur(false)"
|
|
660
|
-
@keydown.enter.prevent="handleStopEditingAndBlur(false)"
|
|
661
|
-
@keydown.esc.prevent="handleStopEditingAndBlur(true)"
|
|
662
|
-
@mousedown.stop
|
|
663
|
-
>
|
|
664
|
-
<span class="spreadsheet-cell spreadsheetCellPlaceHolder">{{ formatCellValue(row[col.key], col.format) }}</span>
|
|
665
|
-
</template>
|
|
666
|
-
<template v-else>
|
|
667
|
-
<template v-if="col.format === 'image'">
|
|
668
|
-
<div class="h40px w-100p flex align-items-center justify-content-center overflow-hidden">
|
|
669
|
-
<img class=" w-100p h-100p contain radius-05" :src="row[col.key]" :alt="col.label || col.key">
|
|
670
|
-
</div>
|
|
671
|
-
</template>
|
|
672
|
-
<template v-else-if="col.format === 'boolean'">
|
|
673
|
-
<CheckInput
|
|
674
|
-
:modelValue="!!row[col.key]"
|
|
675
|
-
:disabled="!isCellEditable(col.key)"
|
|
676
|
-
@update:modelValue="(value: boolean | any[] | undefined) => updateCell(rowIndex, col.key, !!value)"
|
|
677
|
-
@mousedown.stop
|
|
678
|
-
/>
|
|
679
|
-
</template>
|
|
680
|
-
<template v-else>
|
|
681
|
-
<span class="spreadsheet-cell">{{ formatCellValue(row[col.key], col.format) }}</span>
|
|
682
|
-
</template>
|
|
683
|
-
</template>
|
|
684
|
-
</td>
|
|
685
|
-
</tr>
|
|
686
|
-
</tbody>
|
|
687
|
-
</table>
|
|
720
|
+
<SpreadsheetTable
|
|
721
|
+
v-if="fixedColumns.length"
|
|
722
|
+
:columns="fixedColumns"
|
|
723
|
+
:rows="filteredRows"
|
|
724
|
+
:is-fixed="true"
|
|
725
|
+
:show-row-numbers="true"
|
|
726
|
+
:column-widths="columnWidths"
|
|
727
|
+
:sort-column="sortColumn"
|
|
728
|
+
:sort-direction="sortDirection"
|
|
729
|
+
:selection-start="selectionStart"
|
|
730
|
+
:selection-end="selectionEnd"
|
|
731
|
+
:editing-cell="editingCell"
|
|
732
|
+
:base-column-index="0"
|
|
733
|
+
class="sticky z-2 start-0 bg-white"
|
|
734
|
+
@sortColumn="sortByColumn"
|
|
735
|
+
@resizeStart="handleResizeStart"
|
|
736
|
+
@selectRow="selectEntireRow"
|
|
737
|
+
@cellMouseDown="handleMouseDown"
|
|
738
|
+
@cellMouseOver="handleMouseOver"
|
|
739
|
+
@cellEditStart="startEditing"
|
|
740
|
+
@cellKeyDown="handleCellKeyDown"
|
|
741
|
+
@updateCell="updateCell"
|
|
742
|
+
@stopEditing="handleStopEditingAndBlur"
|
|
743
|
+
@setInputRef="setInputRef"
|
|
744
|
+
/>
|
|
688
745
|
|
|
689
746
|
<!-- Scrollable Columns -->
|
|
690
747
|
<div class="flex-shrink flex-grow overflow-x">
|
|
691
|
-
<
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
:key="col.key"
|
|
715
|
-
:class="{
|
|
716
|
-
selected: isCellSelected(rowIndex, fixedColumns.length + colIndex),
|
|
717
|
-
locked: !isCellEditable(col.key),
|
|
718
|
-
}"
|
|
719
|
-
:style="{ width: col.width }"
|
|
720
|
-
:tabindex="col.hidden ? undefined : 0"
|
|
721
|
-
@mousedown="handleMouseDown(rowIndex, fixedColumns.length + colIndex)"
|
|
722
|
-
@mouseover="handleMouseOver(rowIndex, fixedColumns.length + colIndex)"
|
|
723
|
-
@focusin="handleMouseOver(rowIndex, fixedColumns.length + colIndex)"
|
|
724
|
-
@dblclick="startEditing(rowIndex, fixedColumns.length + colIndex)"
|
|
725
|
-
@keydown="handleCellKeyDown($event, rowIndex, fixedColumns.length + colIndex)"
|
|
726
|
-
>
|
|
727
|
-
<template v-if="editingCell && editingCell.row === rowIndex && editingCell.col === (fixedColumns.length + colIndex)">
|
|
728
|
-
<input
|
|
729
|
-
:ref="el => setInputRef(el, `cell-${rowIndex}-${fixedColumns.length + colIndex}`)"
|
|
730
|
-
:value="row[col.key]"
|
|
731
|
-
type="text"
|
|
732
|
-
class="spreadsheet-input"
|
|
733
|
-
@input="(e: Event) => updateCell(rowIndex, col.key, (e.target as HTMLInputElement).value)"
|
|
734
|
-
@blur="handleStopEditingAndBlur(false)"
|
|
735
|
-
@keydown.enter.prevent="handleStopEditingAndBlur(false)"
|
|
736
|
-
@keydown.esc.prevent="handleStopEditingAndBlur(true)"
|
|
737
|
-
@mousedown.stop
|
|
738
|
-
>
|
|
739
|
-
<span class="spreadsheet-cell spreadsheetCellPlaceHolder">{{ formatCellValue(row[col.key], col.format) }}</span>
|
|
740
|
-
</template>
|
|
741
|
-
<template v-else>
|
|
742
|
-
<template v-if="col.format === 'image'">
|
|
743
|
-
<div v-if="row[col.key]" class="h40px w-100p flex align-items-center justify-content-center overflow-hidden">
|
|
744
|
-
<img class=" w-100p h-100p contain radius-05" :src="row[col.key]" :alt="col.label || col.key">
|
|
745
|
-
</div>
|
|
746
|
-
</template>
|
|
747
|
-
<template v-else-if="col.format === 'boolean'">
|
|
748
|
-
<CheckInput
|
|
749
|
-
:modelValue="!!row[col.key]"
|
|
750
|
-
:disabled="!isCellEditable(col.key)"
|
|
751
|
-
@update:modelValue="(value: boolean | any[] | undefined) => updateCell(rowIndex, col.key, !!value)"
|
|
752
|
-
@mousedown.stop
|
|
753
|
-
/>
|
|
754
|
-
</template>
|
|
755
|
-
<template v-else>
|
|
756
|
-
<span class="spreadsheet-cell">{{ formatCellValue(row[col.key], col.format) }}</span>
|
|
757
|
-
</template>
|
|
758
|
-
</template>
|
|
759
|
-
</td>
|
|
760
|
-
</tr>
|
|
761
|
-
</tbody>
|
|
762
|
-
</table>
|
|
748
|
+
<SpreadsheetTable
|
|
749
|
+
:columns="scrollableColumns"
|
|
750
|
+
:rows="filteredRows"
|
|
751
|
+
:is-fixed="false"
|
|
752
|
+
:show-row-numbers="!fixedColumns.length"
|
|
753
|
+
:column-widths="columnWidths"
|
|
754
|
+
:sort-column="sortColumn"
|
|
755
|
+
:sort-direction="sortDirection"
|
|
756
|
+
:selection-start="selectionStart"
|
|
757
|
+
:selection-end="selectionEnd"
|
|
758
|
+
:editing-cell="editingCell"
|
|
759
|
+
:base-column-index="fixedColumns.length"
|
|
760
|
+
@sortColumn="sortByColumn"
|
|
761
|
+
@resizeStart="handleResizeStart"
|
|
762
|
+
@selectRow="selectEntireRow"
|
|
763
|
+
@cellMouseDown="handleMouseDown"
|
|
764
|
+
@cellMouseOver="handleMouseOver"
|
|
765
|
+
@cellEditStart="startEditing"
|
|
766
|
+
@cellKeyDown="handleCellKeyDown"
|
|
767
|
+
@updateCell="updateCell"
|
|
768
|
+
@stopEditing="handleStopEditingAndBlur"
|
|
769
|
+
@setInputRef="setInputRef"
|
|
770
|
+
/>
|
|
763
771
|
</div>
|
|
764
772
|
</div>
|
|
765
773
|
<Btn v-if="allowAddRow" outline thin round icon="add" value="Add Row" class="mt-05" @click="addRow" />
|
|
@@ -768,97 +776,8 @@ const filteredRows = computed(() => {
|
|
|
768
776
|
</template>
|
|
769
777
|
|
|
770
778
|
<style scoped>
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
}
|
|
774
|
-
.spreadsheet table {
|
|
775
|
-
border-collapse: collapse;
|
|
776
|
-
}
|
|
777
|
-
.spreadsheet th, .spreadsheet td {
|
|
778
|
-
border: 1px solid var(--border-color);
|
|
779
|
-
padding: 0.1rem 0.5rem;
|
|
780
|
-
min-width: 80px;
|
|
781
|
-
background: var(--bgl-white);
|
|
782
|
-
user-select: none;
|
|
783
|
-
}
|
|
784
|
-
.spreadsheet th {
|
|
785
|
-
background: var(--input-bg);
|
|
786
|
-
white-space: nowrap;
|
|
787
|
-
position: relative;
|
|
788
|
-
padding: 0.25rem 0.5rem;
|
|
789
|
-
font-weight: 500;
|
|
790
|
-
text-align: start;
|
|
791
|
-
}
|
|
792
|
-
.spreadsheet th .bgl_icon-font{
|
|
793
|
-
vertical-align: middle;
|
|
794
|
-
}
|
|
795
|
-
.spreadsheet td.selected {
|
|
796
|
-
background: var(--bgl-primary-light);
|
|
797
|
-
}
|
|
798
|
-
.spreadsheet td.locked {
|
|
799
|
-
background: var(--bgl-gray-light);
|
|
800
|
-
cursor: default;
|
|
801
|
-
}
|
|
802
|
-
.spreadsheet td.locked.selected {
|
|
803
|
-
background: var(--bgl-primary-light);
|
|
804
|
-
}
|
|
805
|
-
.spreadsheet td {
|
|
806
|
-
height: 40px;
|
|
807
|
-
vertical-align: middle;
|
|
808
|
-
}
|
|
809
|
-
.spreadsheet td:has(img){
|
|
810
|
-
padding: 0;
|
|
811
|
-
}
|
|
812
|
-
.spreadsheet td span{
|
|
813
|
-
display: block;
|
|
814
|
-
display: -webkit-box;
|
|
815
|
-
max-width: 100%;
|
|
816
|
-
-webkit-box-orient: vertical;
|
|
817
|
-
overflow: hidden;
|
|
818
|
-
text-overflow: ellipsis;
|
|
819
|
-
-webkit-line-clamp: 1;
|
|
820
|
-
word-break: break-all;
|
|
821
|
-
}
|
|
822
|
-
.spreadsheet input {
|
|
823
|
-
width: 100%;
|
|
824
|
-
border: none;
|
|
825
|
-
background: transparent;
|
|
826
|
-
padding: 0;
|
|
827
|
-
margin: 0;
|
|
828
|
-
min-height: 0;
|
|
829
|
-
min-width: 0;
|
|
830
|
-
}
|
|
831
|
-
.spreadsheet input:focus {
|
|
832
|
-
outline: 2px solid var(--bgl-primary);
|
|
833
|
-
outline-offset: 6px;
|
|
834
|
-
}
|
|
835
|
-
.spreadsheet th.sortable {
|
|
836
|
-
cursor: pointer;
|
|
837
|
-
}
|
|
838
|
-
.row-number-header, .row-number {
|
|
839
|
-
width: fit-content;
|
|
840
|
-
min-width: fit-content !important;
|
|
841
|
-
padding: 0.1rem 0.7rem !important;
|
|
842
|
-
}
|
|
843
|
-
.spreadsheet td .bgl-checkbox{
|
|
844
|
-
margin: 0;
|
|
845
|
-
text-align: center;
|
|
846
|
-
justify-content: center;
|
|
847
|
-
|
|
848
|
-
}
|
|
849
|
-
.spreadsheet td:has(.bgl-checkbox){
|
|
850
|
-
text-align: center;
|
|
851
|
-
background: var(--input-bg);
|
|
852
|
-
}
|
|
853
|
-
.spreadsheet td:has(:checked){
|
|
854
|
-
background: var(--bgl-primary-light);
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
.spreadsheetCellPlaceHolder{
|
|
858
|
-
height: 0px;
|
|
859
|
-
overflow: hidden;
|
|
860
|
-
opacity: 0;
|
|
861
|
-
pointer-events: none;
|
|
779
|
+
/* Spreadsheet container styles */
|
|
780
|
+
.spreadsheet {
|
|
862
781
|
user-select: none;
|
|
863
782
|
}
|
|
864
783
|
</style>
|