@tipolox/litgrid-web 1.0.3 → 1.2.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/README.md +3 -0
- package/dist/components/DataGrid.d.ts +28 -1
- package/dist/components/DataGrid.d.ts.map +1 -1
- package/dist/components/DataGrid.js +272 -62
- package/dist/components/DataGrid.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/types.d.ts +26 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +8 -4
- package/src/DataGrid.ts +1 -0
- package/src/clipboard/serializeSelectedCells.ts +62 -0
- package/src/clipboard/serializeSelectedRows.ts +42 -0
- package/src/columnState/columnState.ts +102 -0
- package/src/components/DataGrid.ts +3317 -0
- package/src/index.ts +20 -0
- package/src/sizing/columnSizing.ts +25 -0
- package/src/sizing/constants.ts +3 -0
- package/src/sizing/rowSizing.ts +5 -0
- package/src/theme/darkTheme.ts +34 -0
- package/src/theme/lightTheme.ts +35 -0
- package/src/types.ts +138 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { GridSelection } from '@tipolox/litgrid-core'
|
|
2
|
+
import type { GridColumn } from '../types.js'
|
|
3
|
+
|
|
4
|
+
type SerializeSelectedRowsOptions = {
|
|
5
|
+
selection: GridSelection
|
|
6
|
+
rows: unknown[]
|
|
7
|
+
columns: GridColumn[]
|
|
8
|
+
getCellValue: (column: GridColumn, row: unknown, rowIndex: number) => unknown
|
|
9
|
+
formatValue: (value: unknown) => string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function isRowSelection(selection: GridSelection) {
|
|
13
|
+
return selection.mode === 'row' || selection.mode === 'multi-row'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function serializeSelectedRows({
|
|
17
|
+
selection,
|
|
18
|
+
rows,
|
|
19
|
+
columns,
|
|
20
|
+
getCellValue,
|
|
21
|
+
formatValue
|
|
22
|
+
}: SerializeSelectedRowsOptions): string | null {
|
|
23
|
+
if (!isRowSelection(selection) || selection.rowIndexes.size === 0) {
|
|
24
|
+
return null
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const selectedRowIndexes = [...selection.rowIndexes]
|
|
28
|
+
.filter((rowIndex) => Number.isInteger(rowIndex) && rowIndex >= 0 && rowIndex < rows.length)
|
|
29
|
+
.sort((left, right) => left - right)
|
|
30
|
+
|
|
31
|
+
if (selectedRowIndexes.length === 0) {
|
|
32
|
+
return null
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return selectedRowIndexes.map((rowIndex) => {
|
|
36
|
+
const row = rows[rowIndex]
|
|
37
|
+
|
|
38
|
+
return columns
|
|
39
|
+
.map((column) => formatValue(getCellValue(column, row, rowIndex)))
|
|
40
|
+
.join('\t')
|
|
41
|
+
}).join('\n')
|
|
42
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { GridColumn } from '../types.js'
|
|
2
|
+
import { normalizeColumnWidth } from '../sizing/columnSizing.js'
|
|
3
|
+
|
|
4
|
+
export type GridColumnStateColumn = {
|
|
5
|
+
key: string
|
|
6
|
+
width?: number
|
|
7
|
+
visible: boolean
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type GridColumnState = {
|
|
11
|
+
version: 1
|
|
12
|
+
columns: GridColumnStateColumn[]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type ColumnStateChangeDetail = {
|
|
16
|
+
reason: 'resize' | 'reorder' | 'visibility' | 'restore' | 'reset' | 'set'
|
|
17
|
+
state: GridColumnState
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type ResolvedColumnState = {
|
|
21
|
+
columns: GridColumn[]
|
|
22
|
+
widths: Map<string, number>
|
|
23
|
+
hiddenKeys: Set<string>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function createColumnState(
|
|
27
|
+
columns: GridColumn[],
|
|
28
|
+
widths: Map<string, number>,
|
|
29
|
+
hiddenKeys: Set<string>
|
|
30
|
+
): GridColumnState {
|
|
31
|
+
return {
|
|
32
|
+
version: 1,
|
|
33
|
+
columns: columns.map((column) => {
|
|
34
|
+
const width = widths.get(column.key)
|
|
35
|
+
return {
|
|
36
|
+
key: column.key,
|
|
37
|
+
...(width === undefined ? {} : { width }),
|
|
38
|
+
visible: !hiddenKeys.has(column.key)
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function resolveColumnState(
|
|
45
|
+
state: unknown,
|
|
46
|
+
sourceColumns: GridColumn[]
|
|
47
|
+
): ResolvedColumnState | null {
|
|
48
|
+
if (!isGridColumnState(state)) return null
|
|
49
|
+
|
|
50
|
+
const sourceByKey = new Map(sourceColumns.map((column) => [column.key, column]))
|
|
51
|
+
const consumedKeys = new Set<string>()
|
|
52
|
+
const columns: GridColumn[] = []
|
|
53
|
+
const widths = new Map<string, number>()
|
|
54
|
+
const hiddenKeys = new Set<string>()
|
|
55
|
+
|
|
56
|
+
for (const entry of state.columns) {
|
|
57
|
+
const column = sourceByKey.get(entry.key)
|
|
58
|
+
if (!column || consumedKeys.has(entry.key)) continue
|
|
59
|
+
|
|
60
|
+
consumedKeys.add(entry.key)
|
|
61
|
+
columns.push(column)
|
|
62
|
+
if (!entry.visible) hiddenKeys.add(entry.key)
|
|
63
|
+
if (typeof entry.width === 'number' && Number.isFinite(entry.width)) {
|
|
64
|
+
widths.set(entry.key, normalizeColumnWidth(entry.width))
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
for (const column of sourceColumns) {
|
|
69
|
+
if (consumedKeys.has(column.key)) continue
|
|
70
|
+
|
|
71
|
+
columns.push(column)
|
|
72
|
+
if (column.hidden) hiddenKeys.add(column.key)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return { columns, widths, hiddenKeys }
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function parseColumnState(value: string | null): GridColumnState | null {
|
|
79
|
+
if (!value) return null
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const state: unknown = JSON.parse(value)
|
|
83
|
+
return isGridColumnState(state) ? state : null
|
|
84
|
+
} catch {
|
|
85
|
+
return null
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function isGridColumnState(value: unknown): value is GridColumnState {
|
|
90
|
+
if (!value || typeof value !== 'object') return false
|
|
91
|
+
|
|
92
|
+
const state = value as { version?: unknown; columns?: unknown }
|
|
93
|
+
if (state.version !== 1 || !Array.isArray(state.columns)) return false
|
|
94
|
+
|
|
95
|
+
return state.columns.every((column) => {
|
|
96
|
+
if (!column || typeof column !== 'object') return false
|
|
97
|
+
const entry = column as { key?: unknown; width?: unknown; visible?: unknown }
|
|
98
|
+
return typeof entry.key === 'string' &&
|
|
99
|
+
typeof entry.visible === 'boolean' &&
|
|
100
|
+
(entry.width === undefined || typeof entry.width === 'number')
|
|
101
|
+
})
|
|
102
|
+
}
|