@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.
Files changed (47) hide show
  1. package/dist/components/body.component.js +2 -15
  2. package/dist/components/footer.component.js +3 -3
  3. package/dist/components/header.component.js +2 -2
  4. package/dist/components/row.component.js +13 -4
  5. package/dist/helpers/dom.helpers.js +5 -10
  6. package/dist/helpers/misc.helpers.js +7 -0
  7. package/dist/helpers/style.helper.js +6 -0
  8. package/dist/managers/column.manager.js +1 -1
  9. package/dist/managers/data.manager.js +1 -1
  10. package/dist/managers/event.manager.js +5 -1
  11. package/dist/managers/filter.manager.js +1 -1
  12. package/dist/managers/{virtualization.manager.js → render.manager.js} +26 -22
  13. package/dist/managers/row.manager.js +2 -2
  14. package/dist/managers/selection.manager.js +191 -0
  15. package/dist/managers/sort.manager.js +1 -1
  16. package/dist/tabela.full.js +634 -96
  17. package/dist/tabela.js +11 -6
  18. package/package.json +1 -1
  19. package/src/components/body.component.ts +4 -21
  20. package/src/components/footer.component.ts +3 -3
  21. package/src/components/header.component.ts +2 -2
  22. package/src/components/row.component.ts +22 -7
  23. package/src/helpers/dom.helpers.ts +3 -10
  24. package/src/helpers/misc.helpers.ts +15 -0
  25. package/src/helpers/style.helper.ts +6 -0
  26. package/src/managers/column.manager.ts +1 -1
  27. package/src/managers/data.manager.ts +1 -1
  28. package/src/managers/event.manager.ts +8 -1
  29. package/src/managers/filter.manager.ts +1 -1
  30. package/src/managers/{virtualization.manager.ts → render.manager.ts} +34 -32
  31. package/src/managers/row.manager.ts +2 -2
  32. package/src/managers/selection.manager.ts +338 -0
  33. package/src/managers/sort.manager.ts +1 -1
  34. package/src/models/{virtualization.model.ts → render.model.ts} +3 -3
  35. package/src/models/tabela.model.ts +11 -2
  36. package/src/tabela.ts +12 -5
  37. package/types/components/row.component.d.ts +2 -2
  38. package/types/helpers/dom.helpers.d.ts +1 -1
  39. package/types/helpers/misc.helpers.d.ts +2 -0
  40. package/types/helpers/style.helper.d.ts +1 -0
  41. package/types/managers/event.manager.d.ts +1 -1
  42. package/types/managers/{virtualization.manager.d.ts → render.manager.d.ts} +6 -6
  43. package/types/managers/selection.manager.d.ts +19 -0
  44. package/types/models/{virtualization.model.d.ts → render.model.d.ts} +3 -3
  45. package/types/models/tabela.model.d.ts +10 -2
  46. package/types/tabela.d.ts +2 -1
  47. /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 { VirtualizationManager } from "./managers/virtualization.manager.js";
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
- sort: void 0,
26
- virtualization: void 0
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.#managers, this.#element);
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
@@ -46,5 +46,5 @@
46
46
  },
47
47
  "type": "module",
48
48
  "types": "./types/index.d.ts",
49
- "version": "0.9.0"
49
+ "version": "0.10.0"
50
50
  }
@@ -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
- 'div',
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-body';
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-footer';
18
- row.className += ' tabela__row-footer';
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-footer';
38
+ cell.className += ' tabela__cell--footer';
39
39
  cell.innerHTML = '&nbsp;';
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-header';
14
- row.className += ' tabela__row-header';
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: VirtualizationPool, row: RowComponent): void {
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.virtualization.pool.rows.shift() ?? createRow();
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.virtualization.pool.cells[options.field] ??= [];
55
+ managers.render.pool.cells[options.field] ??= [];
40
56
 
41
57
  const cell =
42
- managers.virtualization.pool.cells[columns[index].options.field].shift() ??
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-body');
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(false);
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(withStyle?: boolean): HTMLDivElement {
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+$/;
@@ -0,0 +1,6 @@
1
+ import {toggleStyles} from '@oscarpalmer/toretto/style';
2
+
3
+ export const dragStyling = toggleStyles(document.body, {
4
+ userSelect: 'none',
5
+ webkitUserSelect: 'none',
6
+ });
@@ -55,7 +55,7 @@ export class ColumnManager {
55
55
  components.header.update(items);
56
56
  components.footer.update(items);
57
57
 
58
- managers.virtualization.removeCells(fields);
58
+ managers.render.removeCells(fields);
59
59
  }
60
60
 
61
61
  set(columns: TabelaColumnOptions[]): void {
@@ -117,7 +117,7 @@ export class DataManager {
117
117
  } else if (managers.sort.items.length > 0) {
118
118
  managers.sort.sort();
119
119
  } else {
120
- managers.virtualization.update(true);
120
+ managers.render.update(true);
121
121
  }
122
122
  }
123
123
 
@@ -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
 
@@ -87,7 +87,7 @@ export class FilterManager {
87
87
  if (managers.sort.items.length > 0) {
88
88
  managers.sort.sort();
89
89
  } else {
90
- managers.virtualization.update(true, true);
90
+ managers.render.update(true, true);
91
91
  }
92
92
  }
93
93
 
@@ -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, RowComponent} from '../components/row.component';
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: VirtualizationManager, down: boolean): VirtualizationRange {
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: VirtualizationManager): void {
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 VirtualizationManager {
47
+ export class RenderManager {
51
48
  fragment!: DocumentFragment;
52
49
 
53
50
  listener: RemovableEventListener;
54
51
 
55
- readonly pool: VirtualizationPool = {
52
+ readonly pool: RenderElementPool = {
56
53
  cells: {},
57
54
  rows: [],
58
55
  };
59
56
 
60
- readonly state: VirtualizationState = {
57
+ readonly state: RenderState = {
61
58
  active: false,
62
59
  top: 0,
63
60
  };
64
61
 
65
- visible = new Map<number, RowComponent>();
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.listener();
72
+ const {listener, pool, visible} = this;
76
73
 
77
- for (const [index, row] of this.visible) {
78
- removeRow(this.pool, row);
74
+ listener();
75
+ visible.clear();
79
76
 
80
- this.visible.delete(index);
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 this.pool.cells[fields[index]];
89
+ delete pool.cells[fields[index]];
95
90
  }
96
91
 
97
- for (const [, row] of this.visible) {
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, row] of visible) {
131
- if (!managers.row.has(row.key) || !indices.has(index)) {
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
- removeRow(pool, row);
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 row = managers.row.get(keys[index]);
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, row);
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.virtualization.pool, components[index]);
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.virtualization.pool, row);
49
+ removeRow(this.managers.render.pool, row);
50
50
 
51
51
  this.components.delete(key);
52
52
  }