@oscarpalmer/tabela 0.12.0 → 0.14.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/tabela.full.js +146 -18
- package/package.json +45 -37
- package/src/components/body.component.ts +11 -7
- package/src/components/column.component.ts +23 -24
- package/src/components/footer.component.ts +7 -5
- package/src/components/group.component.ts +73 -9
- package/src/components/header.component.ts +6 -4
- package/src/components/row.component.ts +28 -18
- package/src/helpers/dom.helpers.ts +27 -29
- package/src/helpers/misc.helpers.ts +5 -0
- package/src/helpers/style.helper.ts +1 -1
- package/src/managers/column.manager.ts +4 -0
- package/src/managers/data.manager.ts +197 -124
- package/src/managers/event.manager.ts +27 -17
- package/src/managers/filter.manager.ts +49 -25
- package/src/managers/group.manager.ts +73 -12
- package/src/managers/navigation.manager.ts +48 -50
- package/src/managers/render.manager.ts +56 -29
- package/src/managers/row.manager.ts +22 -10
- package/src/managers/selection.manager.ts +40 -31
- package/src/managers/sort.manager.ts +58 -43
- package/src/managers/style.manager.ts +171 -0
- package/src/models/column.model.ts +2 -6
- package/src/models/data.model.ts +12 -10
- package/src/models/dom.model.ts +33 -0
- package/src/models/event.model.ts +7 -0
- package/src/models/filter.model.ts +20 -0
- package/src/models/group.model.ts +10 -2
- package/src/models/sort.model.ts +4 -0
- package/src/models/style.model.ts +51 -0
- package/src/models/tabela.model.ts +11 -8
- package/src/tabela.ts +67 -37
- package/types/components/body.component.d.ts +0 -6
- package/types/components/column.component.d.ts +0 -13
- package/types/components/footer.component.d.ts +0 -8
- package/types/components/group.component.d.ts +0 -14
- package/types/components/header.component.d.ts +0 -8
- package/types/components/row.component.d.ts +0 -11
- package/types/helpers/dom.helpers.d.ts +0 -10
- package/types/helpers/misc.helpers.d.ts +0 -2
- package/types/helpers/style.helper.d.ts +0 -1
- package/types/index.d.ts +0 -4
- package/types/managers/column.manager.d.ts +0 -12
- package/types/managers/data.manager.d.ts +0 -29
- package/types/managers/event.manager.d.ts +0 -7
- package/types/managers/filter.manager.d.ts +0 -19
- package/types/managers/group.manager.d.ts +0 -17
- package/types/managers/navigation.manager.d.ts +0 -10
- package/types/managers/render.manager.d.ts +0 -17
- package/types/managers/row.manager.d.ts +0 -13
- package/types/managers/selection.manager.d.ts +0 -24
- package/types/managers/sort.manager.d.ts +0 -28
- package/types/models/body.model.d.ts +0 -4
- package/types/models/column.model.d.ts +0 -13
- package/types/models/data.model.d.ts +0 -24
- package/types/models/filter.model.d.ts +0 -13
- package/types/models/footer.model.d.ts +0 -5
- package/types/models/group.model.d.ts +0 -4
- package/types/models/header.model.d.ts +0 -4
- package/types/models/render.model.d.ts +0 -13
- package/types/models/selection.model.d.ts +0 -8
- package/types/models/sort.model.d.ts +0 -12
- package/types/models/tabela.model.d.ts +0 -39
- package/types/models/tabela.options.d.ts +0 -10
- package/types/tabela.d.ts +0 -15
|
@@ -1,5 +1,26 @@
|
|
|
1
|
+
import {getString} from '@oscarpalmer/atoms/string';
|
|
1
2
|
import {createElement} from '../helpers/dom.helpers';
|
|
3
|
+
import {GROUP_KEY_PREFIX, type GroupValue} from '../models/group.model';
|
|
4
|
+
import {
|
|
5
|
+
CSS_BUTTON,
|
|
6
|
+
CSS_BUTTON_GROUP,
|
|
7
|
+
CSS_CELL,
|
|
8
|
+
CSS_CELL_GROUP,
|
|
9
|
+
CSS_GROUP_SELECTED,
|
|
10
|
+
CSS_GROUP_TOTAL,
|
|
11
|
+
CSS_ROW,
|
|
12
|
+
CSS_ROW_GROUP,
|
|
13
|
+
} from '../models/style.model';
|
|
2
14
|
import type {State} from '../models/tabela.model';
|
|
15
|
+
import {
|
|
16
|
+
ATTRIBUTE_DATA_EVENT,
|
|
17
|
+
ATTRIBUTE_DATA_KEY,
|
|
18
|
+
ATTRIBUTE_ROLE,
|
|
19
|
+
ELEMENT_DIV,
|
|
20
|
+
ROLE_CELL,
|
|
21
|
+
ROLE_ROW,
|
|
22
|
+
} from '../models/dom.model';
|
|
23
|
+
import {EVENT_GROUP} from '../models/event.model';
|
|
3
24
|
|
|
4
25
|
export class GroupComponent {
|
|
5
26
|
element: HTMLElement | undefined;
|
|
@@ -8,30 +29,54 @@ export class GroupComponent {
|
|
|
8
29
|
|
|
9
30
|
filtered = 0;
|
|
10
31
|
|
|
32
|
+
readonly key: string;
|
|
33
|
+
|
|
11
34
|
selected = 0;
|
|
12
35
|
|
|
13
36
|
total = 0;
|
|
14
37
|
|
|
38
|
+
readonly value: GroupValue;
|
|
39
|
+
|
|
15
40
|
constructor(
|
|
16
|
-
readonly key: string,
|
|
17
41
|
readonly label: string,
|
|
18
|
-
|
|
19
|
-
) {
|
|
42
|
+
value: unknown,
|
|
43
|
+
) {
|
|
44
|
+
const stringified = getString(value);
|
|
45
|
+
|
|
46
|
+
this.key = `${GROUP_KEY_PREFIX}${stringified}`;
|
|
47
|
+
|
|
48
|
+
this.value = {
|
|
49
|
+
stringified,
|
|
50
|
+
original: value,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function removeGroup(group: GroupComponent): void {
|
|
56
|
+
if (group.element == null) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
group.element.innerHTML = '';
|
|
61
|
+
|
|
62
|
+
group.element.remove();
|
|
20
63
|
}
|
|
21
64
|
|
|
22
65
|
export function renderGroup(state: State, component: GroupComponent): void {
|
|
23
66
|
component.element ??= createElement(
|
|
24
|
-
|
|
67
|
+
ELEMENT_DIV,
|
|
25
68
|
{
|
|
26
|
-
className:
|
|
27
|
-
innerHTML: `<div class="
|
|
28
|
-
<button class="
|
|
69
|
+
className: `${CSS_ROW} ${CSS_ROW_GROUP}`,
|
|
70
|
+
innerHTML: `<div class="${CSS_CELL} ${CSS_CELL_GROUP}" role="${ROLE_CELL}">
|
|
71
|
+
<button class="${CSS_BUTTON} ${CSS_BUTTON_GROUP}" ${ATTRIBUTE_DATA_EVENT}="${EVENT_GROUP}" ${ATTRIBUTE_DATA_KEY}="${state.prefix}_${component.key}" type="button">
|
|
29
72
|
<span aria-hidden="true"></span>
|
|
30
73
|
<span>Open/close</span>
|
|
31
74
|
</button>
|
|
32
75
|
<p>${component.label}</p>
|
|
76
|
+
<span class="${CSS_GROUP_TOTAL}">${component.total}</span>
|
|
77
|
+
<span class="${CSS_GROUP_SELECTED}">${component.selected === 0 ? '' : component.selected}</span>
|
|
33
78
|
</div>`,
|
|
34
|
-
|
|
79
|
+
[ATTRIBUTE_ROLE]: ROLE_ROW,
|
|
35
80
|
},
|
|
36
81
|
{},
|
|
37
82
|
{
|
|
@@ -40,4 +85,23 @@ export function renderGroup(state: State, component: GroupComponent): void {
|
|
|
40
85
|
);
|
|
41
86
|
}
|
|
42
87
|
|
|
43
|
-
export function updateGroup(state: State, component: GroupComponent): void {
|
|
88
|
+
export function updateGroup(state: State, component: GroupComponent): void {
|
|
89
|
+
if (component.element == null) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const selected = component.element.querySelector<HTMLSpanElement>(selectedSelector);
|
|
94
|
+
const total = component.element.querySelector<HTMLSpanElement>(totalSelector);
|
|
95
|
+
|
|
96
|
+
if (selected != null) {
|
|
97
|
+
selected.textContent = component.selected === 0 ? '' : String(component.selected);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (total != null) {
|
|
101
|
+
total.textContent = String(component.total);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const selectedSelector = `.${CSS_GROUP_SELECTED}`;
|
|
106
|
+
|
|
107
|
+
const totalSelector = `.${CSS_GROUP_TOTAL}`;
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import {createRowGroup} from '../helpers/dom.helpers';
|
|
2
2
|
import type {HeaderElements} from '../models/header.model';
|
|
3
|
+
import {CSS_ROW_HEADER, CSS_ROWGROUP_HEADER} from '../models/style.model';
|
|
4
|
+
import type {State} from '../models/tabela.model';
|
|
3
5
|
import type {ColumnComponent} from './column.component';
|
|
4
6
|
|
|
5
7
|
export class HeaderComponent {
|
|
6
8
|
readonly elements: HeaderElements;
|
|
7
9
|
|
|
8
|
-
constructor() {
|
|
9
|
-
const {group, row} = createRowGroup();
|
|
10
|
+
constructor(state: State) {
|
|
11
|
+
const {group, row} = createRowGroup(state.options.rowHeight);
|
|
10
12
|
|
|
11
13
|
this.elements = {group, row};
|
|
12
14
|
|
|
13
|
-
group.className +=
|
|
14
|
-
row.className +=
|
|
15
|
+
group.className += ` ${CSS_ROWGROUP_HEADER}`;
|
|
16
|
+
row.className += ` ${CSS_ROW_HEADER}`;
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
destroy(): void {
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import type {Key} from '@oscarpalmer/atoms/models';
|
|
2
|
+
import {getValue} from '@oscarpalmer/atoms/value/handle';
|
|
2
3
|
import {setAttributes} from '@oscarpalmer/toretto/attribute';
|
|
3
4
|
import {createCell, createRow} from '../helpers/dom.helpers';
|
|
4
5
|
import type {RenderElementPool} from '../models/render.model';
|
|
6
|
+
import {CSS_ROW_BODY, CSS_ROW_SELECTED} from '../models/style.model';
|
|
5
7
|
import type {State} from '../models/tabela.model';
|
|
8
|
+
import {
|
|
9
|
+
ARIA_SELECTED,
|
|
10
|
+
ATTRIBUTE_DATA_ACTIVE,
|
|
11
|
+
ATTRIBUTE_DATA_EVENT,
|
|
12
|
+
ATTRIBUTE_DATA_KEY,
|
|
13
|
+
} from '../models/dom.model';
|
|
14
|
+
import {EVENT_ROW} from '../models/event.model';
|
|
6
15
|
|
|
7
16
|
export function removeRow(pool: RenderElementPool, row: RowComponent): void {
|
|
8
17
|
if (row.element != null) {
|
|
@@ -18,36 +27,38 @@ export function removeRow(pool: RenderElementPool, row: RowComponent): void {
|
|
|
18
27
|
}
|
|
19
28
|
|
|
20
29
|
export function renderRow(state: State, row: RowComponent): void {
|
|
21
|
-
const
|
|
30
|
+
const {managers, options, prefix} = state;
|
|
31
|
+
|
|
32
|
+
const element = row.element ?? managers.render.pool.rows.shift() ?? createRow(options.rowHeight);
|
|
22
33
|
|
|
23
34
|
row.element = element;
|
|
24
35
|
|
|
25
36
|
element.innerHTML = '';
|
|
26
37
|
|
|
27
|
-
const selected =
|
|
38
|
+
const selected = managers.selection.items.has(row.key);
|
|
28
39
|
|
|
29
40
|
const key = String(row.key);
|
|
30
41
|
|
|
31
42
|
setAttributes(element, {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
id:
|
|
43
|
+
[ARIA_SELECTED]: String(selected),
|
|
44
|
+
[ATTRIBUTE_DATA_ACTIVE]: String(managers.navigation.active === row.key),
|
|
45
|
+
[ATTRIBUTE_DATA_EVENT]: EVENT_ROW,
|
|
46
|
+
[ATTRIBUTE_DATA_KEY]: key,
|
|
47
|
+
id: `${prefix}${key}`,
|
|
37
48
|
});
|
|
38
49
|
|
|
39
|
-
element.classList.add(
|
|
50
|
+
element.classList.add(CSS_ROW_BODY);
|
|
40
51
|
|
|
41
52
|
if (selected) {
|
|
42
|
-
element.classList.add(
|
|
53
|
+
element.classList.add(CSS_ROW_SELECTED);
|
|
43
54
|
} else {
|
|
44
|
-
element.classList.remove(
|
|
55
|
+
element.classList.remove(CSS_ROW_SELECTED);
|
|
45
56
|
}
|
|
46
57
|
|
|
47
|
-
const columns =
|
|
58
|
+
const columns = managers.column.items;
|
|
48
59
|
const {length} = columns;
|
|
49
60
|
|
|
50
|
-
const data =
|
|
61
|
+
const data = managers.data.state.values.mapped.get(row.key);
|
|
51
62
|
|
|
52
63
|
if (data == null) {
|
|
53
64
|
return;
|
|
@@ -55,16 +66,15 @@ export function renderRow(state: State, row: RowComponent): void {
|
|
|
55
66
|
|
|
56
67
|
for (let index = 0; index < length; index += 1) {
|
|
57
68
|
const {options} = columns[index];
|
|
69
|
+
const {field, width} = options;
|
|
58
70
|
|
|
59
|
-
|
|
71
|
+
managers.render.pool.cells[field] ??= [];
|
|
60
72
|
|
|
61
|
-
const cell =
|
|
62
|
-
state.managers.render.pool.cells[columns[index].options.field].shift() ??
|
|
63
|
-
createCell(options.width);
|
|
73
|
+
const cell = managers.render.pool.cells[field].shift() ?? createCell(width);
|
|
64
74
|
|
|
65
|
-
cell.textContent = String(data
|
|
75
|
+
cell.textContent = String(getValue(data, field));
|
|
66
76
|
|
|
67
|
-
row.cells[
|
|
77
|
+
row.cells[field] = cell;
|
|
68
78
|
|
|
69
79
|
element.append(cell);
|
|
70
80
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {setAttributes} from '@oscarpalmer/toretto/attribute';
|
|
2
2
|
import {setStyles} from '@oscarpalmer/toretto/style';
|
|
3
|
+
import {ELEMENT_DIV, ROLE_CELL, ROLE_ROW, ROLE_ROWGROUP} from '../models/dom.model';
|
|
4
|
+
import {CSS_CELL, CSS_CELL_BODY, CSS_ROW, CSS_ROWGROUP} from '../models/style.model';
|
|
3
5
|
|
|
4
6
|
type RowGroupWithRow = {
|
|
5
7
|
group: HTMLDivElement;
|
|
@@ -8,10 +10,10 @@ type RowGroupWithRow = {
|
|
|
8
10
|
|
|
9
11
|
export function createCell(width: number, body?: boolean): HTMLDivElement {
|
|
10
12
|
const cell = createElement(
|
|
11
|
-
|
|
13
|
+
ELEMENT_DIV,
|
|
12
14
|
{
|
|
13
|
-
className:
|
|
14
|
-
role:
|
|
15
|
+
className: CSS_CELL,
|
|
16
|
+
role: ROLE_CELL,
|
|
15
17
|
},
|
|
16
18
|
{},
|
|
17
19
|
{
|
|
@@ -20,7 +22,7 @@ export function createCell(width: number, body?: boolean): HTMLDivElement {
|
|
|
20
22
|
);
|
|
21
23
|
|
|
22
24
|
if (body ?? true) {
|
|
23
|
-
cell.classList.add(
|
|
25
|
+
cell.classList.add(CSS_CELL_BODY);
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
return cell;
|
|
@@ -28,60 +30,56 @@ export function createCell(width: number, body?: boolean): HTMLDivElement {
|
|
|
28
30
|
|
|
29
31
|
export function createElement<TagName extends keyof HTMLElementTagNameMap>(
|
|
30
32
|
tagName: TagName,
|
|
31
|
-
properties
|
|
32
|
-
attributes
|
|
33
|
-
style
|
|
33
|
+
properties?: Partial<HTMLElementTagNameMap[TagName]>,
|
|
34
|
+
attributes?: Record<string, string>,
|
|
35
|
+
style?: Partial<CSSStyleDeclaration>,
|
|
34
36
|
): HTMLElementTagNameMap[TagName] {
|
|
35
37
|
const element = document.createElement(tagName);
|
|
36
38
|
|
|
37
|
-
const
|
|
39
|
+
const props = properties ?? {};
|
|
40
|
+
const keys = Object.keys(props);
|
|
38
41
|
|
|
39
42
|
for (const key of keys) {
|
|
40
|
-
(element as any)[key] =
|
|
43
|
+
(element as any)[key] = props[key as keyof typeof props];
|
|
41
44
|
}
|
|
42
45
|
|
|
43
|
-
setAttributes(element, attributes);
|
|
44
|
-
setStyles(element, style);
|
|
46
|
+
setAttributes(element, attributes ?? {});
|
|
47
|
+
setStyles(element, style ?? {});
|
|
45
48
|
|
|
46
49
|
return element;
|
|
47
50
|
}
|
|
48
51
|
|
|
49
|
-
export function createRowGroup(): RowGroupWithRow;
|
|
52
|
+
export function createRowGroup(height: number): RowGroupWithRow;
|
|
50
53
|
|
|
51
|
-
export function createRowGroup(withRow: boolean): HTMLDivElement;
|
|
54
|
+
export function createRowGroup(height: number, withRow: boolean): HTMLDivElement;
|
|
52
55
|
|
|
53
|
-
export function createRowGroup(withRow?: boolean) {
|
|
54
|
-
const group = createElement(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
role: 'rowgroup',
|
|
59
|
-
},
|
|
60
|
-
{},
|
|
61
|
-
{},
|
|
62
|
-
);
|
|
56
|
+
export function createRowGroup(height: number, withRow?: boolean) {
|
|
57
|
+
const group = createElement(ELEMENT_DIV, {
|
|
58
|
+
className: CSS_ROWGROUP,
|
|
59
|
+
role: ROLE_ROWGROUP,
|
|
60
|
+
});
|
|
63
61
|
|
|
64
62
|
if (!(withRow ?? true)) {
|
|
65
63
|
return group;
|
|
66
64
|
}
|
|
67
65
|
|
|
68
|
-
const row = createRow();
|
|
66
|
+
const row = createRow(height);
|
|
69
67
|
|
|
70
68
|
group.append(row);
|
|
71
69
|
|
|
72
70
|
return {group, row};
|
|
73
71
|
}
|
|
74
72
|
|
|
75
|
-
export function createRow(): HTMLDivElement {
|
|
73
|
+
export function createRow(height: number): HTMLDivElement {
|
|
76
74
|
const row = createElement(
|
|
77
|
-
|
|
75
|
+
ELEMENT_DIV,
|
|
78
76
|
{
|
|
79
|
-
className:
|
|
80
|
-
role:
|
|
77
|
+
className: CSS_ROW,
|
|
78
|
+
role: ROLE_ROW,
|
|
81
79
|
},
|
|
82
80
|
{},
|
|
83
81
|
{
|
|
84
|
-
height:
|
|
82
|
+
height: `${height}px`,
|
|
85
83
|
},
|
|
86
84
|
);
|
|
87
85
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type {Key} from '@oscarpalmer/atoms/models';
|
|
2
|
+
import {GROUP_KEY_EXPRESSION} from '../models/group.model';
|
|
2
3
|
|
|
3
4
|
export function getKey(value: unknown): Key | undefined {
|
|
4
5
|
if (typeof value === 'number') {
|
|
@@ -12,4 +13,8 @@ export function getKey(value: unknown): Key | undefined {
|
|
|
12
13
|
return integerExpression.test(value) ? Number.parseInt(value, 10) : value;
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
export function isGroupKey(key: unknown): boolean {
|
|
17
|
+
return typeof key === 'string' && GROUP_KEY_EXPRESSION.test(key);
|
|
18
|
+
}
|
|
19
|
+
|
|
15
20
|
const integerExpression = /^\d+$/;
|
|
@@ -20,6 +20,10 @@ export class ColumnManager {
|
|
|
20
20
|
this.state = undefined as never;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
get(field: string): ColumnComponent | undefined {
|
|
24
|
+
return this.items.find(item => item.options.field === field);
|
|
25
|
+
}
|
|
26
|
+
|
|
23
27
|
remove(field: string): void;
|
|
24
28
|
|
|
25
29
|
remove(fields: string[]): void;
|