@coreui/data-grid 0.1.0-rc.0 → 0.3.0-rc.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 +9 -6
- package/dist/css/data-grid.css +156 -38
- package/dist/css/data-grid.css.map +1 -1
- package/dist/css/data-grid.min.css +2 -2
- package/dist/css/data-grid.min.css.map +1 -1
- package/dist/css/data-grid.standalone.css +1066 -0
- package/dist/css/data-grid.standalone.css.map +1 -0
- package/dist/css/data-grid.standalone.min.css +5 -0
- package/dist/css/data-grid.standalone.min.css.map +1 -0
- package/dist/js/clipboard.cjs +56 -0
- package/dist/js/clipboard.cjs.map +1 -0
- package/dist/js/clipboard.mjs +54 -0
- package/dist/js/clipboard.mjs.map +1 -0
- package/dist/js/csv.cjs +36 -59
- package/dist/js/csv.cjs.map +1 -1
- package/dist/js/csv.mjs +35 -55
- package/dist/js/csv.mjs.map +1 -1
- package/dist/js/data-grid.esm.js +14108 -9331
- package/dist/js/data-grid.esm.js.map +1 -1
- package/dist/js/data-grid.esm.min.js +6 -6
- package/dist/js/data-grid.esm.min.js.map +1 -1
- package/dist/js/data-grid.js +14408 -9634
- package/dist/js/data-grid.js.map +1 -1
- package/dist/js/data-grid.lite.esm.js +10507 -0
- package/dist/js/data-grid.lite.esm.js.map +1 -0
- package/dist/js/data-grid.lite.esm.min.js +8 -0
- package/dist/js/data-grid.lite.esm.min.js.map +1 -0
- package/dist/js/data-grid.lite.js +10520 -0
- package/dist/js/data-grid.lite.js.map +1 -0
- package/dist/js/data-grid.lite.min.js +8 -0
- package/dist/js/data-grid.lite.min.js.map +1 -0
- package/dist/js/data-grid.lite.mjs +10507 -0
- package/dist/js/data-grid.lite.mjs.map +1 -0
- package/dist/js/data-grid.min.js +6 -6
- package/dist/js/data-grid.min.js.map +1 -1
- package/dist/js/data-grid.mjs +14108 -9331
- package/dist/js/data-grid.mjs.map +1 -1
- package/dist/js/direction.cjs +26 -0
- package/dist/js/direction.cjs.map +1 -0
- package/dist/js/direction.mjs +24 -0
- package/dist/js/direction.mjs.map +1 -0
- package/dist/js/drag.cjs +467 -0
- package/dist/js/drag.cjs.map +1 -0
- package/dist/js/drag.mjs +464 -0
- package/dist/js/drag.mjs.map +1 -0
- package/dist/js/export-table-BdabEbJG.mjs +26 -0
- package/dist/js/export-table-BdabEbJG.mjs.map +1 -0
- package/dist/js/export-table-D762wrZ1.cjs +55 -0
- package/dist/js/export-table-D762wrZ1.cjs.map +1 -0
- package/dist/js/filters.cjs +89 -132
- package/dist/js/filters.cjs.map +1 -1
- package/dist/js/filters.mjs +88 -128
- package/dist/js/filters.mjs.map +1 -1
- package/dist/js/labels.cjs +65 -70
- package/dist/js/labels.cjs.map +1 -1
- package/dist/js/labels.mjs +64 -66
- package/dist/js/labels.mjs.map +1 -1
- package/dist/js/print.cjs +66 -0
- package/dist/js/print.cjs.map +1 -0
- package/dist/js/print.mjs +64 -0
- package/dist/js/print.mjs.map +1 -0
- package/dist/js/validate.cjs +43 -0
- package/dist/js/validate.cjs.map +1 -0
- package/dist/js/validate.mjs +42 -0
- package/dist/js/validate.mjs.map +1 -0
- package/dist/js/xlsx.cjs +240 -0
- package/dist/js/xlsx.cjs.map +1 -0
- package/dist/js/xlsx.mjs +238 -0
- package/dist/js/xlsx.mjs.map +1 -0
- package/dist/types/base-component.d.ts +28 -18
- package/dist/types/data-grid.d.ts +26 -13
- package/dist/types/dom/data.d.ts +15 -0
- package/dist/types/dom/event-handler.d.ts +21 -10
- package/dist/types/dom/manipulator.d.ts +15 -8
- package/dist/types/engine/active-cell.d.ts +1 -0
- package/dist/types/engine/data-source.d.ts +1 -1
- package/dist/types/engine/features-lite.d.ts +25 -0
- package/dist/types/engine/features.d.ts +35 -0
- package/dist/types/engine/table.d.ts +3 -3
- package/dist/types/engine/validate.d.mts +1 -0
- package/dist/types/engine/validate.d.ts +20 -0
- package/dist/types/engine/virtualizer.d.ts +2 -0
- package/dist/types/icons.d.ts +6 -4
- package/dist/types/index-lite.d.mts +1 -0
- package/dist/types/index-lite.d.ts +19 -0
- package/dist/types/index.d.ts +11 -2
- package/dist/types/types.d.ts +53 -31
- package/dist/types/ui/body.d.ts +6 -3
- package/dist/types/ui/header.d.ts +3 -2
- package/dist/types/ui/loading.d.ts +1 -1
- package/dist/types/ui/pinning.d.ts +1 -1
- package/dist/types/ui/toolbar.d.ts +10 -2
- package/dist/types/util/clipboard.d.mts +1 -0
- package/dist/types/util/clipboard.d.ts +29 -0
- package/dist/types/util/config.d.ts +27 -10
- package/dist/types/util/csv.d.ts +5 -5
- package/dist/types/util/direction.d.mts +1 -0
- package/dist/types/util/direction.d.ts +17 -0
- package/dist/types/util/drag.d.mts +1 -0
- package/dist/types/util/drag.d.ts +48 -0
- package/dist/types/util/export-table.d.ts +47 -0
- package/dist/types/util/index.d.ts +66 -10
- package/dist/types/util/print.d.mts +1 -0
- package/dist/types/util/print.d.ts +32 -0
- package/dist/types/util/sanitizer.d.ts +15 -11
- package/dist/types/util/xlsx.d.mts +1 -0
- package/dist/types/util/xlsx.d.ts +17 -0
- package/dist/types/util/zip.d.ts +11 -0
- package/package.json +101 -10
- package/scss/_base.scss +13 -0
- package/scss/_config.scss +14 -0
- package/scss/_functions.scss +1 -0
- package/scss/_mixins.scss +1 -0
- package/scss/base/_buttons.scss +113 -0
- package/scss/base/_forms.scss +157 -0
- package/scss/base/_helpers.scss +24 -0
- package/scss/base/_pagination.scss +100 -0
- package/scss/base/_reboot.scss +93 -0
- package/scss/base/_root.scss +85 -0
- package/scss/base/_spinner.scss +45 -0
- package/scss/base/_table.scss +78 -0
- package/scss/components/_data-grid.scss +807 -0
- package/scss/data-grid.scss +7 -555
- package/scss/data-grid.standalone.scss +16 -0
- package/scss/functions/_defaults.scss +25 -0
- package/scss/mixins/_tokens.scss +12 -0
- package/src/{base-component.js → base-component.ts} +21 -17
- package/src/data-grid.ts +523 -201
- package/src/dom/{data.js → data.ts} +13 -10
- package/src/dom/event-handler.ts +380 -0
- package/src/dom/{manipulator.js → manipulator.ts} +11 -11
- package/src/engine/active-cell.ts +10 -3
- package/src/engine/data-source.ts +7 -3
- package/src/engine/features-lite.ts +47 -0
- package/src/engine/features.ts +68 -0
- package/src/engine/table.ts +86 -45
- package/src/engine/validate.ts +64 -0
- package/src/engine/virtualizer.ts +17 -1
- package/src/icons.ts +11 -5
- package/src/index-lite.ts +85 -0
- package/src/index.ts +30 -2
- package/src/labels.ts +6 -4
- package/src/types.ts +87 -32
- package/src/ui/body.ts +73 -17
- package/src/ui/header.ts +51 -26
- package/src/ui/loading.ts +2 -2
- package/src/ui/pinning.ts +16 -16
- package/src/ui/toolbar.ts +27 -3
- package/src/util/clipboard.ts +112 -0
- package/src/util/{config.js → config.ts} +25 -11
- package/src/util/csv.ts +11 -30
- package/src/util/direction.ts +37 -0
- package/src/util/drag.ts +832 -0
- package/src/util/export-table.ts +86 -0
- package/src/util/{index.js → index.ts} +55 -35
- package/src/util/print.ts +125 -0
- package/src/util/{sanitizer.js → sanitizer.ts} +17 -13
- package/src/util/xlsx.ts +183 -0
- package/src/util/zip.ts +170 -0
- package/src/base-component.d.ts +0 -19
- package/src/dom/event-handler.d.ts +0 -11
- package/src/dom/event-handler.js +0 -331
- package/src/dom/manipulator.d.ts +0 -9
- package/src/util/config.d.ts +0 -11
- package/src/util/index.d.ts +0 -10
- package/src/util/sanitizer.d.ts +0 -11
package/src/ui/pinning.ts
CHANGED
|
@@ -5,16 +5,16 @@
|
|
|
5
5
|
* --------------------------------------------------------------------------
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
8
|
+
const CLASS_START = 'data-grid-cell-pinned-start'
|
|
9
|
+
const CLASS_END = 'data-grid-cell-pinned-end'
|
|
10
|
+
const CLASS_START_LAST = 'data-grid-cell-pinned-start-last'
|
|
11
|
+
const CLASS_END_FIRST = 'data-grid-cell-pinned-end-first'
|
|
12
12
|
|
|
13
13
|
export interface PinnedCellInfo {
|
|
14
|
-
side: '
|
|
14
|
+
side: 'start' | 'end'
|
|
15
15
|
offset: number
|
|
16
16
|
edge: boolean
|
|
17
|
-
// A
|
|
17
|
+
// A start offset that has to clear the (sticky) selection cell; expressed as a
|
|
18
18
|
// CSS calc so the select-cell width stays a single source of truth in CSS.
|
|
19
19
|
afterSelect: boolean
|
|
20
20
|
}
|
|
@@ -25,29 +25,29 @@ export interface GridPinning {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export const applyPinnedCell = (cell: HTMLTableCellElement, info: PinnedCellInfo | null): void => {
|
|
28
|
-
cell.classList.remove(
|
|
29
|
-
cell.style.
|
|
30
|
-
cell.style.
|
|
28
|
+
cell.classList.remove(CLASS_START, CLASS_END, CLASS_START_LAST, CLASS_END_FIRST)
|
|
29
|
+
cell.style.insetInlineStart = ''
|
|
30
|
+
cell.style.insetInlineEnd = ''
|
|
31
31
|
|
|
32
32
|
if (!info) {
|
|
33
33
|
return
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
if (info.side === '
|
|
37
|
-
cell.classList.add(
|
|
36
|
+
if (info.side === 'start') {
|
|
37
|
+
cell.classList.add(CLASS_START)
|
|
38
38
|
if (info.edge) {
|
|
39
|
-
cell.classList.add(
|
|
39
|
+
cell.classList.add(CLASS_START_LAST)
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
cell.style.
|
|
42
|
+
cell.style.insetInlineStart = info.afterSelect ?
|
|
43
43
|
`calc(var(--cui-data-grid-select-cell-width) + ${info.offset}px)` :
|
|
44
44
|
`${info.offset}px`
|
|
45
45
|
} else {
|
|
46
|
-
cell.classList.add(
|
|
46
|
+
cell.classList.add(CLASS_END)
|
|
47
47
|
if (info.edge) {
|
|
48
|
-
cell.classList.add(
|
|
48
|
+
cell.classList.add(CLASS_END_FIRST)
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
cell.style.
|
|
51
|
+
cell.style.insetInlineEnd = `${info.offset}px`
|
|
52
52
|
}
|
|
53
53
|
}
|
package/src/ui/toolbar.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* --------------------------------------------------------------------------
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { CsvDownloadOptions } from '../util/csv'
|
|
8
|
+
import type { CsvDownloadOptions, CsvTable } from '../util/csv'
|
|
9
9
|
import type { DataGridLabels, DataGridOptions } from '../types'
|
|
10
10
|
|
|
11
11
|
const CLASS_NAME_TOOLBAR = 'data-grid-toolbar'
|
|
@@ -19,10 +19,12 @@ export interface GridToolbarContext {
|
|
|
19
19
|
// Undo/redo of edit commits - both buttons start disabled, the grid
|
|
20
20
|
// toggles them as the history stacks fill.
|
|
21
21
|
history: boolean
|
|
22
|
+
print: boolean
|
|
22
23
|
search: boolean
|
|
23
24
|
icons: {
|
|
24
25
|
columns: string
|
|
25
26
|
export: string
|
|
27
|
+
print: string
|
|
26
28
|
redo: string
|
|
27
29
|
undo: string
|
|
28
30
|
}
|
|
@@ -32,11 +34,24 @@ export interface GridToolbar {
|
|
|
32
34
|
element: HTMLDivElement
|
|
33
35
|
}
|
|
34
36
|
|
|
37
|
+
export type DataGridExporter = (table: CsvTable, options: DataGridExportOptions) => void
|
|
38
|
+
|
|
39
|
+
export interface DataGridExportOptions extends CsvDownloadOptions {
|
|
40
|
+
// Sheet name for spreadsheet writers; the CSV writer ignores it.
|
|
41
|
+
sheetName?: string
|
|
42
|
+
// The writer the toolbar button calls, defaulting to the built-in CSV one.
|
|
43
|
+
// Pass `downloadXlsx` from `@coreui/data-grid/xlsx` for Excel. It is
|
|
44
|
+
// INJECTED, never imported by the grid: a writer only reaches the app
|
|
45
|
+
// bundle when the app asks for it.
|
|
46
|
+
exporter?: DataGridExporter
|
|
47
|
+
}
|
|
48
|
+
|
|
35
49
|
export interface ResolvedToolbar {
|
|
36
50
|
columns: boolean
|
|
37
51
|
export: boolean
|
|
38
|
-
exportOptions:
|
|
52
|
+
exportOptions: DataGridExportOptions
|
|
39
53
|
history: boolean
|
|
54
|
+
print: boolean
|
|
40
55
|
search: boolean
|
|
41
56
|
}
|
|
42
57
|
|
|
@@ -53,6 +68,7 @@ export const resolveToolbar = (options: DataGridOptions): ResolvedToolbar => {
|
|
|
53
68
|
export: true,
|
|
54
69
|
exportOptions: {},
|
|
55
70
|
history: options.history,
|
|
71
|
+
print: true,
|
|
56
72
|
search: true
|
|
57
73
|
}
|
|
58
74
|
}
|
|
@@ -64,6 +80,7 @@ export const resolveToolbar = (options: DataGridOptions): ResolvedToolbar => {
|
|
|
64
80
|
export: Boolean(exportOption),
|
|
65
81
|
exportOptions: typeof exportOption === 'object' ? exportOption : {},
|
|
66
82
|
history: (toolbar.history ?? false) && options.history,
|
|
83
|
+
print: toolbar.print ?? false,
|
|
67
84
|
search: (toolbar.search ?? false) || Boolean(options.globalFilter)
|
|
68
85
|
}
|
|
69
86
|
}
|
|
@@ -73,6 +90,7 @@ export const resolveToolbar = (options: DataGridOptions): ResolvedToolbar => {
|
|
|
73
90
|
export: false,
|
|
74
91
|
exportOptions: {},
|
|
75
92
|
history: false,
|
|
93
|
+
print: false,
|
|
76
94
|
search: Boolean(options.globalFilter)
|
|
77
95
|
}
|
|
78
96
|
}
|
|
@@ -98,7 +116,7 @@ export const createToolbar = (context: GridToolbarContext): GridToolbar => {
|
|
|
98
116
|
const element = document.createElement('div')
|
|
99
117
|
element.classList.add(CLASS_NAME_TOOLBAR)
|
|
100
118
|
|
|
101
|
-
if (context.columns || context.export || context.history) {
|
|
119
|
+
if (context.columns || context.export || context.print || context.history) {
|
|
102
120
|
const actions = document.createElement('div')
|
|
103
121
|
actions.classList.add(CLASS_NAME_ACTIONS)
|
|
104
122
|
|
|
@@ -114,6 +132,12 @@ export const createToolbar = (context: GridToolbarContext): GridToolbar => {
|
|
|
114
132
|
)
|
|
115
133
|
}
|
|
116
134
|
|
|
135
|
+
if (context.print) {
|
|
136
|
+
actions.append(
|
|
137
|
+
createActionButton(context.icons.print, context.labels.toolbarPrint, 'data-coreui-toolbar-print')
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
|
|
117
141
|
if (context.history) {
|
|
118
142
|
const undoButton = createActionButton(context.icons.undo, context.labels.toolbarUndo, 'data-coreui-toolbar-undo')
|
|
119
143
|
const redoButton = createActionButton(context.icons.redo, context.labels.toolbarRedo, 'data-coreui-toolbar-redo')
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* --------------------------------------------------------------------------
|
|
3
|
+
* CoreUI PRO data-grid util/clipboard.ts
|
|
4
|
+
* License (https://coreui.io/pro/license/)
|
|
5
|
+
* --------------------------------------------------------------------------
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { DataGridItem } from '../types'
|
|
9
|
+
|
|
10
|
+
// table-core resolves the selection to index rectangles and leaves the text to
|
|
11
|
+
// userland, "since the delimiter, the null representation, and any quoting
|
|
12
|
+
// rules are application decisions". This is that decision, made once for all
|
|
13
|
+
// four editions: TSV, because that is what spreadsheets paste as columns.
|
|
14
|
+
|
|
15
|
+
const DELIMITER = '\t'
|
|
16
|
+
const ROW_SEPARATOR = '\n'
|
|
17
|
+
// Disjoint regions are separated the way a spreadsheet shows a gap.
|
|
18
|
+
const REGION_SEPARATOR = '\n\n'
|
|
19
|
+
|
|
20
|
+
export interface ClipboardBounds {
|
|
21
|
+
maxColumnIndex: number
|
|
22
|
+
maxRowIndex: number
|
|
23
|
+
minColumnIndex: number
|
|
24
|
+
minRowIndex: number
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ClipboardRow {
|
|
28
|
+
getValue: (columnId: string) => unknown
|
|
29
|
+
original: DataGridItem
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface ClipboardTable {
|
|
33
|
+
getCellSelectionBounds: () => ClipboardBounds[]
|
|
34
|
+
getRowModel: () => { rows: ClipboardRow[] }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// The grid's own visible columns, in display order — the same order the
|
|
38
|
+
// selection's column indexes address.
|
|
39
|
+
export interface ClipboardColumn {
|
|
40
|
+
id: string
|
|
41
|
+
formatter?: (value: unknown, item: DataGridItem) => string
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// A tab or a newline inside a value would break the grid the paste target
|
|
45
|
+
// rebuilds, so a value carrying either is quoted the way TSV consumers expect.
|
|
46
|
+
const escape = (text: string): string =>
|
|
47
|
+
(/[\t\n"]/.test(text) ? `"${text.replace(/"/g, '""')}"` : text)
|
|
48
|
+
|
|
49
|
+
export const serializeCellSelection = (table: ClipboardTable, columns: ClipboardColumn[]): string => {
|
|
50
|
+
const { rows } = table.getRowModel()
|
|
51
|
+
|
|
52
|
+
return table
|
|
53
|
+
.getCellSelectionBounds()
|
|
54
|
+
.map(bounds => {
|
|
55
|
+
const lines: string[] = []
|
|
56
|
+
for (let rowIndex = bounds.minRowIndex; rowIndex <= bounds.maxRowIndex; rowIndex++) {
|
|
57
|
+
const row = rows[rowIndex]
|
|
58
|
+
if (!row) {
|
|
59
|
+
continue
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const cells: string[] = []
|
|
63
|
+
for (let columnIndex = bounds.minColumnIndex; columnIndex <= bounds.maxColumnIndex; columnIndex++) {
|
|
64
|
+
const column = columns[columnIndex]
|
|
65
|
+
if (!column) {
|
|
66
|
+
continue
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const value = row.getValue(column.id)
|
|
70
|
+
// The formatter is what the cell displays; a copied date should
|
|
71
|
+
// paste as the date the user is looking at, not its raw value.
|
|
72
|
+
cells.push(escape(column.formatter ? column.formatter(value, row.original) : String(value ?? '')))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
lines.push(cells.join(DELIMITER))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return lines.join(ROW_SEPARATOR)
|
|
79
|
+
})
|
|
80
|
+
.filter(region => region !== '')
|
|
81
|
+
.join(REGION_SEPARATOR)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export const copyCellSelection = async (table: ClipboardTable, columns: ClipboardColumn[]): Promise<string> => {
|
|
85
|
+
const text = serializeCellSelection(table, columns)
|
|
86
|
+
if (text === '') {
|
|
87
|
+
return text
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
await navigator.clipboard.writeText(text)
|
|
92
|
+
} catch {
|
|
93
|
+
// Denied permission, an insecure context, or a browser without the async
|
|
94
|
+
// clipboard: fall back to the selection-and-execCommand route, which only
|
|
95
|
+
// works inside the user gesture that asked for the copy — which is exactly
|
|
96
|
+
// where this runs.
|
|
97
|
+
const textarea = document.createElement('textarea')
|
|
98
|
+
textarea.value = text
|
|
99
|
+
textarea.setAttribute('aria-hidden', 'true')
|
|
100
|
+
textarea.style.position = 'fixed'
|
|
101
|
+
textarea.style.opacity = '0'
|
|
102
|
+
document.body.append(textarea)
|
|
103
|
+
textarea.select()
|
|
104
|
+
try {
|
|
105
|
+
document.execCommand('copy')
|
|
106
|
+
} finally {
|
|
107
|
+
textarea.remove()
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return text
|
|
112
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
// Vendored from https://github.com/coreui/coreui-pro/blob/
|
|
1
|
+
// Vendored from https://github.com/coreui/coreui-pro/blob/e9355580e/js/src/util/config.ts — sync manually
|
|
2
2
|
/**
|
|
3
3
|
* --------------------------------------------------------------------------
|
|
4
|
-
* CoreUI util/config.
|
|
4
|
+
* CoreUI util/config.ts
|
|
5
5
|
* Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE)
|
|
6
6
|
*
|
|
7
|
-
* This is a modified version of the Bootstrap's util/config.
|
|
7
|
+
* This is a modified version of the Bootstrap's util/config.ts
|
|
8
8
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|
9
9
|
* --------------------------------------------------------------------------
|
|
10
10
|
*/
|
|
@@ -12,47 +12,60 @@
|
|
|
12
12
|
import Manipulator from '../dom/manipulator.js'
|
|
13
13
|
import { isElement, toType } from './index.js'
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Types
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
// Deliberately loose: the config object is assembled from data attributes and
|
|
20
|
+
// user input, and each component narrows it with its own exported config type.
|
|
21
|
+
type ComponentConfig = Record<string, any>
|
|
22
|
+
|
|
15
23
|
/**
|
|
16
24
|
* Class definition
|
|
17
25
|
*/
|
|
18
26
|
|
|
19
27
|
class Config {
|
|
28
|
+
// Type `this.constructor` so the static members (Default, DefaultType, NAME)
|
|
29
|
+
// are reachable from instance methods without a cast. Declaration-only, so it
|
|
30
|
+
// emits no runtime code.
|
|
31
|
+
declare ['constructor']: typeof Config
|
|
32
|
+
|
|
20
33
|
// Getters
|
|
21
|
-
static get Default() {
|
|
34
|
+
static get Default(): ComponentConfig {
|
|
22
35
|
return {}
|
|
23
36
|
}
|
|
24
37
|
|
|
25
|
-
static get DefaultType() {
|
|
38
|
+
static get DefaultType(): ComponentConfig {
|
|
26
39
|
return {}
|
|
27
40
|
}
|
|
28
41
|
|
|
29
|
-
static get NAME() {
|
|
42
|
+
static get NAME(): string {
|
|
30
43
|
throw new Error('You have to implement the static method "NAME", for each component!')
|
|
31
44
|
}
|
|
32
45
|
|
|
33
|
-
_getConfig(config) {
|
|
46
|
+
_getConfig(config?: ComponentConfig | null): ComponentConfig {
|
|
34
47
|
config = this._mergeConfigObj(config)
|
|
35
48
|
config = this._configAfterMerge(config)
|
|
36
49
|
this._typeCheckConfig(config)
|
|
37
50
|
return config
|
|
38
51
|
}
|
|
39
52
|
|
|
40
|
-
_configAfterMerge(config) {
|
|
53
|
+
_configAfterMerge(config: ComponentConfig): ComponentConfig {
|
|
41
54
|
return config
|
|
42
55
|
}
|
|
43
56
|
|
|
44
|
-
_mergeConfigObj(config, element) {
|
|
57
|
+
_mergeConfigObj(config?: ComponentConfig | null, element?: Element): ComponentConfig {
|
|
45
58
|
const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {} // try to parse
|
|
46
59
|
|
|
47
60
|
return {
|
|
48
61
|
...this.constructor.Default,
|
|
49
62
|
...(typeof jsonConfig === 'object' ? jsonConfig : {}),
|
|
50
|
-
...(isElement(element) ? Manipulator.getDataAttributes(element) : {}),
|
|
63
|
+
...(isElement(element) ? Manipulator.getDataAttributes(element as HTMLElement) : {}),
|
|
51
64
|
...(typeof config === 'object' ? config : {})
|
|
52
65
|
}
|
|
53
66
|
}
|
|
54
67
|
|
|
55
|
-
_typeCheckConfig(config, configTypes = this.constructor.DefaultType) {
|
|
68
|
+
_typeCheckConfig(config: ComponentConfig, configTypes: ComponentConfig = this.constructor.DefaultType): void {
|
|
56
69
|
for (const [property, expectedTypes] of Object.entries(configTypes)) {
|
|
57
70
|
const value = config[property]
|
|
58
71
|
const valueType = isElement(value) ? 'element' : toType(value)
|
|
@@ -67,3 +80,4 @@ class Config {
|
|
|
67
80
|
}
|
|
68
81
|
|
|
69
82
|
export default Config
|
|
83
|
+
export type { ComponentConfig }
|
package/src/util/csv.ts
CHANGED
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
* --------------------------------------------------------------------------
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import
|
|
9
|
-
|
|
8
|
+
import {
|
|
9
|
+
columnsFor, formatterFor, headerFor, rowsFor, type ExportScope, type ExportTable
|
|
10
|
+
} from './export-table'
|
|
10
11
|
|
|
11
12
|
export interface CsvOptions {
|
|
12
|
-
scope?:
|
|
13
|
+
scope?: ExportScope
|
|
13
14
|
delimiter?: string
|
|
14
15
|
bom?: boolean
|
|
15
16
|
sanitize?: boolean
|
|
@@ -19,10 +20,7 @@ export interface CsvDownloadOptions extends CsvOptions {
|
|
|
19
20
|
filename?: string
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
label?: string
|
|
24
|
-
formatter?: (value: unknown, item: DataGridItem) => string
|
|
25
|
-
}
|
|
23
|
+
export type CsvTable = ExportTable
|
|
26
24
|
|
|
27
25
|
const escapeField = (value: string, delimiter: string): string =>
|
|
28
26
|
/["\r\n]/.test(value) || value.includes(delimiter) ? `"${value.replace(/"/g, '""')}"` : value
|
|
@@ -32,37 +30,20 @@ const escapeField = (value: string, delimiter: string): string =>
|
|
|
32
30
|
const sanitizeField = (value: string): string =>
|
|
33
31
|
/^[=+\-@\t\r]/.test(value) ? `'${value}` : value
|
|
34
32
|
|
|
35
|
-
const
|
|
36
|
-
if (scope === 'all') {
|
|
37
|
-
return table.getCoreRowModel().rows
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (scope === 'selected') {
|
|
41
|
-
return table.getSelectedRowModel().rows
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return table.getSortedRowModel().rows
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export const exportCsv = (table: Table<DataGridItem>, options: CsvOptions = {}): string => {
|
|
33
|
+
export const exportCsv = (table: CsvTable, options: CsvOptions = {}): string => {
|
|
48
34
|
const delimiter = options.delimiter ?? ','
|
|
49
|
-
|
|
50
|
-
const columns = [
|
|
51
|
-
...table.getLeftVisibleLeafColumns(),
|
|
52
|
-
...table.getCenterVisibleLeafColumns(),
|
|
53
|
-
...table.getRightVisibleLeafColumns()
|
|
54
|
-
]
|
|
35
|
+
const columns = columnsFor(table)
|
|
55
36
|
|
|
56
37
|
const process = (field: string) => escapeField(options.sanitize ? sanitizeField(field) : field, delimiter)
|
|
57
38
|
const line = (fields: string[]) => fields.map(process).join(delimiter)
|
|
58
39
|
|
|
59
|
-
const header = line(columns.map(column =>
|
|
40
|
+
const header = line(columns.map(column => headerFor(column)))
|
|
60
41
|
const body = rowsFor(table, options.scope).map(row =>
|
|
61
42
|
line(columns.map(column => {
|
|
62
43
|
const value = row.getValue(column.id)
|
|
63
|
-
const
|
|
44
|
+
const formatter = formatterFor(column)
|
|
64
45
|
// Coerce: a formatter may return a number/null in plain-JS usage.
|
|
65
|
-
return
|
|
46
|
+
return formatter ? String(formatter(value, row.original) ?? '') : String(value ?? '')
|
|
66
47
|
}))
|
|
67
48
|
)
|
|
68
49
|
|
|
@@ -70,7 +51,7 @@ export const exportCsv = (table: Table<DataGridItem>, options: CsvOptions = {}):
|
|
|
70
51
|
return options.bom ? `\uFEFF${csv}` : csv
|
|
71
52
|
}
|
|
72
53
|
|
|
73
|
-
export const downloadCsv = (table:
|
|
54
|
+
export const downloadCsv = (table: CsvTable, options: CsvDownloadOptions = {}): void => {
|
|
74
55
|
const blob = new Blob([exportCsv(table, options)], { type: 'text/csv;charset=utf-8;' })
|
|
75
56
|
const url = URL.createObjectURL(blob)
|
|
76
57
|
const anchor = document.createElement('a')
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* --------------------------------------------------------------------------
|
|
3
|
+
* CoreUI PRO data-grid util/direction.ts
|
|
4
|
+
* License (https://coreui.io/pro/license/)
|
|
5
|
+
* --------------------------------------------------------------------------
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Read from the element rather than the document: a grid can sit inside an RTL
|
|
9
|
+
// subtree of an LTR page, which is why the vendored isRTL() (it checks
|
|
10
|
+
// documentElement.dir) is not the helper for any of this.
|
|
11
|
+
//
|
|
12
|
+
// Angular prerenders in Node, where there is no getComputedStyle — and no
|
|
13
|
+
// layout to have a direction. LTR is the right answer there: the server-side
|
|
14
|
+
// pass emits logical markup either way, and the client corrects on hydration.
|
|
15
|
+
export const isElementRTL = (element: Element | null | undefined): boolean =>
|
|
16
|
+
typeof getComputedStyle === 'function' && element ?
|
|
17
|
+
getComputedStyle(element).direction === 'rtl' :
|
|
18
|
+
false
|
|
19
|
+
|
|
20
|
+
interface ResizeDirectionTable {
|
|
21
|
+
options: { columnResizeDirection?: 'ltr' | 'rtl' }
|
|
22
|
+
setOptions: (updater: (previous: { columnResizeDirection?: 'ltr' | 'rtl' }) => never) => void
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// table-core copies the options object at construction, so the direction it
|
|
26
|
+
// captured goes stale the moment an app swaps language on a live grid. A
|
|
27
|
+
// resize is the only place the value is read, and starting one is rare enough
|
|
28
|
+
// to re-read the element here.
|
|
29
|
+
export const syncResizeDirection = (
|
|
30
|
+
table: ResizeDirectionTable,
|
|
31
|
+
element: Element | null | undefined
|
|
32
|
+
): void => {
|
|
33
|
+
const direction = isElementRTL(element) ? 'rtl' : 'ltr'
|
|
34
|
+
if (table.options.columnResizeDirection !== direction) {
|
|
35
|
+
table.setOptions(previous => ({ ...previous, columnResizeDirection: direction }) as never)
|
|
36
|
+
}
|
|
37
|
+
}
|