@oscarpalmer/tabela 0.9.0 → 0.10.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/dist/components/body.component.js +2 -15
- package/dist/components/footer.component.js +3 -3
- package/dist/components/header.component.js +2 -2
- package/dist/components/row.component.js +13 -4
- package/dist/helpers/dom.helpers.js +5 -10
- package/dist/helpers/misc.helpers.js +7 -0
- package/dist/helpers/style.helper.js +6 -0
- package/dist/managers/column.manager.js +1 -1
- package/dist/managers/data.manager.js +1 -1
- package/dist/managers/event.manager.js +5 -1
- package/dist/managers/filter.manager.js +1 -1
- package/dist/managers/{virtualization.manager.js → render.manager.js} +26 -22
- package/dist/managers/row.manager.js +2 -2
- package/dist/managers/selection.manager.js +191 -0
- package/dist/managers/sort.manager.js +1 -1
- package/dist/tabela.full.js +634 -96
- package/dist/tabela.js +11 -6
- package/package.json +1 -1
- package/src/components/body.component.ts +4 -21
- package/src/components/footer.component.ts +3 -3
- package/src/components/header.component.ts +2 -2
- package/src/components/row.component.ts +22 -7
- package/src/helpers/dom.helpers.ts +3 -10
- package/src/helpers/misc.helpers.ts +15 -0
- package/src/helpers/style.helper.ts +6 -0
- package/src/managers/column.manager.ts +1 -1
- package/src/managers/data.manager.ts +1 -1
- package/src/managers/event.manager.ts +8 -1
- package/src/managers/filter.manager.ts +1 -1
- package/src/managers/{virtualization.manager.ts → render.manager.ts} +34 -32
- package/src/managers/row.manager.ts +2 -2
- package/src/managers/selection.manager.ts +338 -0
- package/src/managers/sort.manager.ts +1 -1
- package/src/models/{virtualization.model.ts → render.model.ts} +3 -3
- package/src/models/tabela.model.ts +11 -2
- package/src/tabela.ts +12 -5
- package/types/components/row.component.d.ts +2 -2
- package/types/helpers/dom.helpers.d.ts +1 -1
- package/types/helpers/misc.helpers.d.ts +2 -0
- package/types/helpers/style.helper.d.ts +1 -0
- package/types/managers/event.manager.d.ts +1 -1
- package/types/managers/{virtualization.manager.d.ts → render.manager.d.ts} +6 -6
- package/types/managers/selection.manager.d.ts +19 -0
- package/types/models/{virtualization.model.d.ts → render.model.d.ts} +3 -3
- package/types/models/tabela.model.d.ts +10 -2
- package/types/tabela.d.ts +2 -1
- /package/dist/models/{virtualization.model.js → render.model.js} +0 -0
package/dist/tabela.js
CHANGED
|
@@ -6,8 +6,9 @@ import { DataManager } from "./managers/data.manager.js";
|
|
|
6
6
|
import { EventManager } from "./managers/event.manager.js";
|
|
7
7
|
import { FilterManager } from "./managers/filter.manager.js";
|
|
8
8
|
import { RowManager } from "./managers/row.manager.js";
|
|
9
|
+
import { SelectionManager } from "./managers/selection.manager.js";
|
|
9
10
|
import { SortManager } from "./managers/sort.manager.js";
|
|
10
|
-
import {
|
|
11
|
+
import { RenderManager } from "./managers/render.manager.js";
|
|
11
12
|
var Tabela = class {
|
|
12
13
|
#components = {
|
|
13
14
|
header: void 0,
|
|
@@ -21,12 +22,14 @@ var Tabela = class {
|
|
|
21
22
|
data: void 0,
|
|
22
23
|
event: void 0,
|
|
23
24
|
filter: void 0,
|
|
25
|
+
render: void 0,
|
|
24
26
|
row: void 0,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
selection: void 0,
|
|
28
|
+
sort: void 0
|
|
27
29
|
};
|
|
28
30
|
data;
|
|
29
31
|
filter;
|
|
32
|
+
selection;
|
|
30
33
|
sort;
|
|
31
34
|
get key() {
|
|
32
35
|
return this.#key;
|
|
@@ -43,15 +46,17 @@ var Tabela = class {
|
|
|
43
46
|
this.#components.footer = new FooterComponent();
|
|
44
47
|
this.#managers.column = new ColumnManager(this.#managers, this.#components, options.columns);
|
|
45
48
|
this.#managers.data = new DataManager(this.#managers, this.#components, options.key);
|
|
46
|
-
this.#managers.event = new EventManager(this.#
|
|
49
|
+
this.#managers.event = new EventManager(this.#element, this.#managers);
|
|
47
50
|
this.#managers.filter = new FilterManager(this.#managers);
|
|
51
|
+
this.#managers.render = new RenderManager(this.#managers, this.#components);
|
|
48
52
|
this.#managers.row = new RowManager(this.#managers, options.rowHeight);
|
|
53
|
+
this.#managers.selection = new SelectionManager(this.#element, this.#managers);
|
|
49
54
|
this.#managers.sort = new SortManager(this.#managers);
|
|
50
|
-
this.#managers.virtualization = new VirtualizationManager(this.#managers, this.#components);
|
|
51
55
|
element.append(this.#components.header.elements.group, this.#components.body.elements.group, this.#components.footer.elements.group);
|
|
52
56
|
this.#managers.data.set(options.data);
|
|
53
57
|
this.data = this.#managers.data.handlers;
|
|
54
58
|
this.filter = this.#managers.filter.handlers;
|
|
59
|
+
this.selection = this.#managers.selection.handlers;
|
|
55
60
|
this.sort = this.#managers.sort.handlers;
|
|
56
61
|
}
|
|
57
62
|
destroy() {
|
|
@@ -65,9 +70,9 @@ var Tabela = class {
|
|
|
65
70
|
managers.data.destroy();
|
|
66
71
|
managers.event.destroy();
|
|
67
72
|
managers.filter.destroy();
|
|
73
|
+
managers.render.destroy();
|
|
68
74
|
managers.row.destroy();
|
|
69
75
|
managers.sort.destroy();
|
|
70
|
-
managers.virtualization.destroy();
|
|
71
76
|
element.innerHTML = "";
|
|
72
77
|
element.role = "";
|
|
73
78
|
element.classList.remove("tabela");
|
package/package.json
CHANGED
|
@@ -1,21 +1,10 @@
|
|
|
1
|
-
import {setStyles} from '@oscarpalmer/toretto/style';
|
|
2
1
|
import {createElement, createRowGroup} from '../helpers/dom.helpers';
|
|
3
2
|
import type {BodyElements} from '../models/body.model';
|
|
4
3
|
|
|
5
4
|
function createFaker(): HTMLDivElement {
|
|
6
|
-
return createElement(
|
|
7
|
-
'
|
|
8
|
-
|
|
9
|
-
{},
|
|
10
|
-
{
|
|
11
|
-
height: '0',
|
|
12
|
-
inset: '0 auto auto 0',
|
|
13
|
-
opacity: '0',
|
|
14
|
-
pointerEvents: 'none',
|
|
15
|
-
position: 'absolute',
|
|
16
|
-
width: '1px',
|
|
17
|
-
},
|
|
18
|
-
);
|
|
5
|
+
return createElement('div', {
|
|
6
|
+
className: 'tabela__faker',
|
|
7
|
+
}, {}, {});
|
|
19
8
|
}
|
|
20
9
|
|
|
21
10
|
export class BodyComponent {
|
|
@@ -29,16 +18,10 @@ export class BodyComponent {
|
|
|
29
18
|
|
|
30
19
|
this.elements.group = group;
|
|
31
20
|
|
|
32
|
-
group.className += ' tabela__rowgroup
|
|
21
|
+
group.className += ' tabela__rowgroup--body';
|
|
33
22
|
|
|
34
23
|
group.tabIndex = 0;
|
|
35
24
|
|
|
36
|
-
setStyles(group, {
|
|
37
|
-
height: '100%',
|
|
38
|
-
overflow: 'auto',
|
|
39
|
-
position: 'relative',
|
|
40
|
-
});
|
|
41
|
-
|
|
42
25
|
group.append(this.elements.faker);
|
|
43
26
|
}
|
|
44
27
|
|
|
@@ -14,8 +14,8 @@ export class FooterComponent {
|
|
|
14
14
|
cells: [],
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
group.className += ' tabela__rowgroup
|
|
18
|
-
row.className += ' tabela__row
|
|
17
|
+
group.className += ' tabela__rowgroup--footer';
|
|
18
|
+
row.className += ' tabela__row--footer';
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
destroy(): void {
|
|
@@ -35,7 +35,7 @@ export class FooterComponent {
|
|
|
35
35
|
for (let index = 0; index < length; index += 1) {
|
|
36
36
|
const cell = createCell(columns[index].options.width ?? 4, false);
|
|
37
37
|
|
|
38
|
-
cell.className += ' tabela__cell
|
|
38
|
+
cell.className += ' tabela__cell--footer';
|
|
39
39
|
cell.innerHTML = ' ';
|
|
40
40
|
|
|
41
41
|
elements.cells.push(cell);
|
|
@@ -10,8 +10,8 @@ export class HeaderComponent {
|
|
|
10
10
|
|
|
11
11
|
this.elements = {group, row};
|
|
12
12
|
|
|
13
|
-
group.className += ' tabela__rowgroup
|
|
14
|
-
row.className += ' tabela__row
|
|
13
|
+
group.className += ' tabela__rowgroup--header';
|
|
14
|
+
row.className += ' tabela__row--header';
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
destroy(): void {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type {Key} from '@oscarpalmer/atoms/models';
|
|
2
|
+
import {setAttributes} from '@oscarpalmer/toretto/attribute';
|
|
2
3
|
import {createCell, createRow} from '../helpers/dom.helpers';
|
|
4
|
+
import type {RenderElementPool} from '../models/render.model';
|
|
3
5
|
import type {TabelaManagers} from '../models/tabela.model';
|
|
4
|
-
import type {VirtualizationPool} from '../models/virtualization.model';
|
|
5
6
|
|
|
6
|
-
export function removeRow(pool:
|
|
7
|
+
export function removeRow(pool: RenderElementPool, row: RowComponent): void {
|
|
7
8
|
if (row.element != null) {
|
|
8
9
|
row.element.innerHTML = '';
|
|
9
10
|
|
|
@@ -17,13 +18,28 @@ export function removeRow(pool: VirtualizationPool, row: RowComponent): void {
|
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
export function renderRow(managers: TabelaManagers, row: RowComponent): void {
|
|
20
|
-
const element = row.element ?? managers.
|
|
21
|
+
const element = row.element ?? managers.render.pool.rows.shift() ?? createRow();
|
|
21
22
|
|
|
22
23
|
row.element = element;
|
|
23
24
|
|
|
24
|
-
element.dataset.key = String(row.key);
|
|
25
25
|
element.innerHTML = '';
|
|
26
26
|
|
|
27
|
+
const selected = managers.selection.items.has(row.key);
|
|
28
|
+
|
|
29
|
+
setAttributes(element, {
|
|
30
|
+
'aria-selected': String(selected),
|
|
31
|
+
'data-event': 'row',
|
|
32
|
+
'data-key': String(row.key),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
element.classList.add('tabela__row--body');
|
|
36
|
+
|
|
37
|
+
if (selected) {
|
|
38
|
+
element.classList.add('tabela__row--selected');
|
|
39
|
+
} else {
|
|
40
|
+
element.classList.remove('tabela__row--selected');
|
|
41
|
+
}
|
|
42
|
+
|
|
27
43
|
const columns = managers.column.items;
|
|
28
44
|
const {length} = columns;
|
|
29
45
|
|
|
@@ -36,11 +52,10 @@ export function renderRow(managers: TabelaManagers, row: RowComponent): void {
|
|
|
36
52
|
for (let index = 0; index < length; index += 1) {
|
|
37
53
|
const {options} = columns[index];
|
|
38
54
|
|
|
39
|
-
managers.
|
|
55
|
+
managers.render.pool.cells[options.field] ??= [];
|
|
40
56
|
|
|
41
57
|
const cell =
|
|
42
|
-
managers.
|
|
43
|
-
createCell(options.width);
|
|
58
|
+
managers.render.pool.cells[columns[index].options.field].shift() ?? createCell(options.width);
|
|
44
59
|
|
|
45
60
|
cell.textContent = String(data[options.field]);
|
|
46
61
|
|
|
@@ -20,7 +20,7 @@ export function createCell(width: number, body?: boolean): HTMLDivElement {
|
|
|
20
20
|
);
|
|
21
21
|
|
|
22
22
|
if (body ?? true) {
|
|
23
|
-
cell.classList.add('tabela__cell
|
|
23
|
+
cell.classList.add('tabela__cell--body');
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
return cell;
|
|
@@ -65,14 +65,14 @@ export function createRowGroup(withRow?: boolean) {
|
|
|
65
65
|
return group;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
const row = createRow(
|
|
68
|
+
const row = createRow();
|
|
69
69
|
|
|
70
70
|
group.append(row);
|
|
71
71
|
|
|
72
72
|
return {group, row};
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
export function createRow(
|
|
75
|
+
export function createRow(): HTMLDivElement {
|
|
76
76
|
const row = createElement(
|
|
77
77
|
'div',
|
|
78
78
|
{
|
|
@@ -83,12 +83,5 @@ export function createRow(withStyle?: boolean): HTMLDivElement {
|
|
|
83
83
|
{},
|
|
84
84
|
);
|
|
85
85
|
|
|
86
|
-
if (withStyle ?? true) {
|
|
87
|
-
setStyles(row, {
|
|
88
|
-
inset: '0 auto auto 0',
|
|
89
|
-
position: 'absolute',
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
86
|
return row;
|
|
94
87
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type {Key} from '@oscarpalmer/atoms/models';
|
|
2
|
+
|
|
3
|
+
export function getKey(value: unknown): Key | undefined {
|
|
4
|
+
if (typeof value === 'number') {
|
|
5
|
+
return value;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (typeof value !== 'string') {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return integerExpression.test(value) ? Number.parseInt(value, 10) : value;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const integerExpression = /^\d+$/;
|
|
@@ -7,8 +7,8 @@ export class EventManager {
|
|
|
7
7
|
listener: RemovableEventListener;
|
|
8
8
|
|
|
9
9
|
constructor(
|
|
10
|
-
readonly managers: TabelaManagers,
|
|
11
10
|
element: HTMLElement,
|
|
11
|
+
readonly managers: TabelaManagers,
|
|
12
12
|
) {
|
|
13
13
|
this.listener = on(
|
|
14
14
|
element,
|
|
@@ -39,6 +39,13 @@ export class EventManager {
|
|
|
39
39
|
case 'heading':
|
|
40
40
|
this.onSort(event, target);
|
|
41
41
|
break;
|
|
42
|
+
|
|
43
|
+
case 'row':
|
|
44
|
+
this.managers.selection.handle(event, target);
|
|
45
|
+
break;
|
|
46
|
+
|
|
47
|
+
default:
|
|
48
|
+
break;
|
|
42
49
|
}
|
|
43
50
|
}
|
|
44
51
|
|
|
@@ -1,21 +1,18 @@
|
|
|
1
|
+
import type {Key} from '@oscarpalmer/atoms/models';
|
|
1
2
|
import {on} from '@oscarpalmer/toretto/event';
|
|
2
3
|
import type {RemovableEventListener} from '@oscarpalmer/toretto/models';
|
|
3
|
-
import {removeRow, renderRow
|
|
4
|
+
import {removeRow, renderRow} from '../components/row.component';
|
|
5
|
+
import type {RenderElementPool, RenderRange, RenderState} from '../models/render.model';
|
|
4
6
|
import type {TabelaComponents, TabelaManagers} from '../models/tabela.model';
|
|
5
|
-
import type {
|
|
6
|
-
VirtualizationPool,
|
|
7
|
-
VirtualizationRange,
|
|
8
|
-
VirtualizationState,
|
|
9
|
-
} from '../models/virtualization.model';
|
|
10
7
|
|
|
11
|
-
function getRange(this:
|
|
8
|
+
function getRange(this: RenderManager, down: boolean): RenderRange {
|
|
12
9
|
const {components, managers} = this;
|
|
13
10
|
const {clientHeight, scrollTop} = components.body.elements.group;
|
|
14
11
|
|
|
15
12
|
const first = Math.floor(scrollTop / managers.row.height);
|
|
16
13
|
|
|
17
14
|
const last = Math.min(
|
|
18
|
-
managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length - 1,
|
|
15
|
+
(managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length) - 1,
|
|
19
16
|
Math.ceil((scrollTop + clientHeight) / managers.row.height) - 1,
|
|
20
17
|
);
|
|
21
18
|
|
|
@@ -25,14 +22,14 @@ function getRange(this: VirtualizationManager, down: boolean): VirtualizationRan
|
|
|
25
22
|
const start = Math.max(0, first - before);
|
|
26
23
|
|
|
27
24
|
const end = Math.min(
|
|
28
|
-
managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length - 1,
|
|
25
|
+
(managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length) - 1,
|
|
29
26
|
last + after,
|
|
30
27
|
);
|
|
31
28
|
|
|
32
29
|
return {end, start};
|
|
33
30
|
}
|
|
34
31
|
|
|
35
|
-
function onScroll(this:
|
|
32
|
+
function onScroll(this: RenderManager): void {
|
|
36
33
|
if (!this.state.active) {
|
|
37
34
|
requestAnimationFrame(() => {
|
|
38
35
|
const top = this.components.body.elements.group.scrollTop;
|
|
@@ -47,22 +44,22 @@ function onScroll(this: VirtualizationManager): void {
|
|
|
47
44
|
}
|
|
48
45
|
}
|
|
49
46
|
|
|
50
|
-
export class
|
|
47
|
+
export class RenderManager {
|
|
51
48
|
fragment!: DocumentFragment;
|
|
52
49
|
|
|
53
50
|
listener: RemovableEventListener;
|
|
54
51
|
|
|
55
|
-
readonly pool:
|
|
52
|
+
readonly pool: RenderElementPool = {
|
|
56
53
|
cells: {},
|
|
57
54
|
rows: [],
|
|
58
55
|
};
|
|
59
56
|
|
|
60
|
-
readonly state:
|
|
57
|
+
readonly state: RenderState = {
|
|
61
58
|
active: false,
|
|
62
59
|
top: 0,
|
|
63
60
|
};
|
|
64
61
|
|
|
65
|
-
visible = new Map<number,
|
|
62
|
+
visible = new Map<number, Key>();
|
|
66
63
|
|
|
67
64
|
constructor(
|
|
68
65
|
public managers: TabelaManagers,
|
|
@@ -72,29 +69,33 @@ export class VirtualizationManager {
|
|
|
72
69
|
}
|
|
73
70
|
|
|
74
71
|
destroy(): void {
|
|
75
|
-
this
|
|
72
|
+
const {listener, pool, visible} = this;
|
|
76
73
|
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
listener();
|
|
75
|
+
visible.clear();
|
|
79
76
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
this.pool.cells = {};
|
|
84
|
-
this.pool.rows = [];
|
|
77
|
+
pool.cells = {};
|
|
78
|
+
pool.rows = [];
|
|
85
79
|
|
|
86
80
|
this.listener = undefined as never;
|
|
87
81
|
this.visible = undefined as never;
|
|
88
82
|
}
|
|
89
83
|
|
|
90
84
|
removeCells(fields: string[]): void {
|
|
85
|
+
const {managers, pool, visible} = this;
|
|
91
86
|
const {length} = fields;
|
|
92
87
|
|
|
93
88
|
for (let index = 0; index < length; index += 1) {
|
|
94
|
-
delete
|
|
89
|
+
delete pool.cells[fields[index]];
|
|
95
90
|
}
|
|
96
91
|
|
|
97
|
-
for (const [,
|
|
92
|
+
for (const [, key] of visible) {
|
|
93
|
+
const row = managers.row.get(key);
|
|
94
|
+
|
|
95
|
+
if (row == null || row.element == null) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
|
|
98
99
|
for (let index = 0; index < length; index += 1) {
|
|
99
100
|
row.cells[fields[index]].innerHTML = '';
|
|
100
101
|
|
|
@@ -127,15 +128,15 @@ export class VirtualizationManager {
|
|
|
127
128
|
|
|
128
129
|
let remove = rerender ?? false;
|
|
129
130
|
|
|
130
|
-
for (const [index,
|
|
131
|
-
|
|
132
|
-
remove = true;
|
|
133
|
-
}
|
|
131
|
+
for (const [index, key] of visible) {
|
|
132
|
+
const row = managers.row.get(key);
|
|
134
133
|
|
|
135
|
-
if (remove) {
|
|
134
|
+
if (remove || row == null || !indices.has(index)) {
|
|
136
135
|
visible.delete(index);
|
|
137
136
|
|
|
138
|
-
|
|
137
|
+
if (row != null) {
|
|
138
|
+
removeRow(pool, row);
|
|
139
|
+
}
|
|
139
140
|
}
|
|
140
141
|
}
|
|
141
142
|
|
|
@@ -150,7 +151,8 @@ export class VirtualizationManager {
|
|
|
150
151
|
continue;
|
|
151
152
|
}
|
|
152
153
|
|
|
153
|
-
const
|
|
154
|
+
const key = keys[index];
|
|
155
|
+
const row = managers.row.get(key);
|
|
154
156
|
|
|
155
157
|
if (row == null) {
|
|
156
158
|
continue;
|
|
@@ -160,7 +162,7 @@ export class VirtualizationManager {
|
|
|
160
162
|
|
|
161
163
|
renderRow(managers, row);
|
|
162
164
|
|
|
163
|
-
visible.set(index,
|
|
165
|
+
visible.set(index, key);
|
|
164
166
|
|
|
165
167
|
if (row.element != null) {
|
|
166
168
|
row.element.style.transform = `translateY(${index * managers.row.height}px)`;
|
|
@@ -20,7 +20,7 @@ export class RowManager {
|
|
|
20
20
|
const {length} = components;
|
|
21
21
|
|
|
22
22
|
for (let index = 0; index < length; index += 1) {
|
|
23
|
-
removeRow(this.managers.
|
|
23
|
+
removeRow(this.managers.render.pool, components[index]);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
this.components.clear();
|
|
@@ -46,7 +46,7 @@ export class RowManager {
|
|
|
46
46
|
const row = this.components.get(key);
|
|
47
47
|
|
|
48
48
|
if (row != null) {
|
|
49
|
-
removeRow(this.managers.
|
|
49
|
+
removeRow(this.managers.render.pool, row);
|
|
50
50
|
|
|
51
51
|
this.components.delete(key);
|
|
52
52
|
}
|