@oscarpalmer/tabela 0.9.0 → 0.11.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 (60) hide show
  1. package/dist/components/body.component.js +3 -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 +19 -7
  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 +10 -9
  9. package/dist/managers/data.manager.js +26 -22
  10. package/dist/managers/event.manager.js +39 -19
  11. package/dist/managers/filter.manager.js +11 -10
  12. package/dist/managers/navigation.manager.js +73 -0
  13. package/dist/managers/render.manager.js +110 -0
  14. package/dist/managers/row.manager.js +7 -7
  15. package/dist/managers/selection.manager.js +189 -0
  16. package/dist/managers/sort.manager.js +9 -8
  17. package/dist/tabela.full.js +1096 -433
  18. package/dist/tabela.js +34 -11
  19. package/package.json +1 -1
  20. package/src/components/body.component.ts +5 -20
  21. package/src/components/footer.component.ts +3 -3
  22. package/src/components/header.component.ts +2 -2
  23. package/src/components/row.component.ts +30 -10
  24. package/src/helpers/dom.helpers.ts +3 -10
  25. package/src/helpers/misc.helpers.ts +15 -0
  26. package/src/helpers/style.helper.ts +6 -0
  27. package/src/managers/column.manager.ts +12 -14
  28. package/src/managers/data.manager.ts +31 -27
  29. package/src/managers/event.manager.ts +67 -37
  30. package/src/managers/filter.manager.ts +12 -11
  31. package/src/managers/navigation.manager.ts +145 -0
  32. package/src/managers/render.manager.ts +184 -0
  33. package/src/managers/row.manager.ts +9 -14
  34. package/src/managers/selection.manager.ts +332 -0
  35. package/src/managers/sort.manager.ts +14 -14
  36. package/src/models/render.model.ts +16 -0
  37. package/src/models/tabela.model.ts +23 -2
  38. package/src/tabela.ts +42 -10
  39. package/types/components/row.component.d.ts +4 -4
  40. package/types/helpers/dom.helpers.d.ts +1 -1
  41. package/types/helpers/misc.helpers.d.ts +2 -0
  42. package/types/helpers/style.helper.d.ts +1 -0
  43. package/types/managers/column.manager.d.ts +4 -5
  44. package/types/managers/data.manager.d.ts +5 -6
  45. package/types/managers/event.manager.d.ts +3 -6
  46. package/types/managers/filter.manager.d.ts +3 -3
  47. package/types/managers/navigation.manager.d.ts +10 -0
  48. package/types/managers/render.manager.d.ts +16 -0
  49. package/types/managers/row.manager.d.ts +4 -5
  50. package/types/managers/selection.manager.d.ts +18 -0
  51. package/types/managers/sort.manager.d.ts +4 -4
  52. package/types/models/render.model.d.ts +13 -0
  53. package/types/models/tabela.model.d.ts +21 -2
  54. package/types/tabela.d.ts +2 -1
  55. package/dist/managers/virtualization.manager.js +0 -101
  56. package/src/managers/virtualization.manager.ts +0 -176
  57. package/src/models/virtualization.model.ts +0 -14
  58. package/types/managers/virtualization.manager.d.ts +0 -18
  59. package/types/models/virtualization.model.d.ts +0 -12
  60. /package/dist/models/{virtualization.model.js → render.model.js} +0 -0
@@ -0,0 +1,10 @@
1
+ import type { Key } from '@oscarpalmer/atoms/models';
2
+ import type { TabelaState } from '../models/tabela.model';
3
+ export declare class NavigationManager {
4
+ state: TabelaState;
5
+ active: Key | undefined;
6
+ constructor(state: TabelaState);
7
+ destroy(): void;
8
+ handle(event: KeyboardEvent): void;
9
+ setActive(key: Key | undefined, scroll?: boolean): void;
10
+ }
@@ -0,0 +1,16 @@
1
+ import type { Key } from '@oscarpalmer/atoms/models';
2
+ import type { RemovableEventListener } from '@oscarpalmer/toretto/models';
3
+ import type { RenderElementPool, RenderState } from '../models/render.model';
4
+ import type { TabelaState } from '../models/tabela.model';
5
+ export declare class RenderManager {
6
+ fragment: DocumentFragment;
7
+ listener: RemovableEventListener;
8
+ pool: RenderElementPool;
9
+ state: RenderState;
10
+ visible: Map<number, Key>;
11
+ constructor(state: TabelaState);
12
+ destroy(): void;
13
+ removeCells(fields: string[]): void;
14
+ getFragment(): DocumentFragment;
15
+ update(down: boolean, rerender?: boolean): void;
16
+ }
@@ -1,11 +1,10 @@
1
1
  import type { Key } from '@oscarpalmer/atoms/models';
2
2
  import { RowComponent } from '../components/row.component';
3
- import type { TabelaManagers } from '../models/tabela.model';
3
+ import type { TabelaState } from '../models/tabela.model';
4
4
  export declare class RowManager {
5
- readonly managers: TabelaManagers;
6
- readonly components: Map<Key, RowComponent>;
7
- readonly height: number;
8
- constructor(managers: TabelaManagers, rowHeight: number);
5
+ state: TabelaState;
6
+ components: Map<Key, RowComponent>;
7
+ constructor(state: TabelaState);
9
8
  destroy(): void;
10
9
  get(key: Key): RowComponent | undefined;
11
10
  has(key: Key): boolean;
@@ -0,0 +1,18 @@
1
+ import type { Key } from '@oscarpalmer/atoms/models';
2
+ import type { TabelaSelection, TabelaState } from '../models/tabela.model';
3
+ export declare class SelectionManager {
4
+ state: TabelaState;
5
+ handlers: Readonly<TabelaSelection>;
6
+ items: Set<Key>;
7
+ last: Key | undefined;
8
+ constructor(state: TabelaState);
9
+ clear(): void;
10
+ deselect(keys: Key[]): void;
11
+ destroy(): void;
12
+ handle(event: MouseEvent, target: HTMLElement): void;
13
+ range(from: Key | HTMLElement, to: Key | HTMLElement): void;
14
+ select(keys: Key[]): void;
15
+ set(keys: Key[]): void;
16
+ toggle(): void;
17
+ update(removed: Key[]): void;
18
+ }
@@ -1,9 +1,9 @@
1
1
  import { type ArrayKeySorter } from '@oscarpalmer/atoms/array';
2
2
  import type { PlainObject } from '@oscarpalmer/atoms/models';
3
3
  import type { SortDirection, SortItem } from '../models/sort.model';
4
- import type { TabelaManagers } from '../models/tabela.model';
4
+ import type { TabelaState } from '../models/tabela.model';
5
5
  export declare class SortManager {
6
- readonly managers: TabelaManagers;
6
+ state: TabelaState;
7
7
  handlers: Readonly<{
8
8
  add: (field: string, direction: SortDirection | undefined) => void;
9
9
  flip: (field: string) => void;
@@ -11,8 +11,8 @@ export declare class SortManager {
11
11
  remove: (field: string) => void;
12
12
  set: (items: SortItem[]) => void;
13
13
  }>;
14
- readonly items: ArrayKeySorter<PlainObject>[];
15
- constructor(managers: TabelaManagers);
14
+ items: ArrayKeySorter<PlainObject>[];
15
+ constructor(state: TabelaState);
16
16
  add(field: string, direction?: SortDirection): void;
17
17
  addOrSet(event: MouseEvent, field: string): void;
18
18
  clear(): void;
@@ -0,0 +1,13 @@
1
+ import type { TabelaState } from './tabela.model';
2
+ export type RenderElementPool = {
3
+ cells: Record<string, HTMLDivElement[]>;
4
+ rows: HTMLDivElement[];
5
+ };
6
+ export type RenderRange = {
7
+ end: number;
8
+ start: number;
9
+ };
10
+ export type RenderState = {
11
+ active: boolean;
12
+ top: number;
13
+ } & TabelaState;
@@ -6,11 +6,14 @@ import type { ColumnManager } from '../managers/column.manager';
6
6
  import type { DataManager } from '../managers/data.manager';
7
7
  import type { EventManager } from '../managers/event.manager';
8
8
  import type { FilterManager } from '../managers/filter.manager';
9
+ import type { NavigationManager } from '../managers/navigation.manager';
10
+ import type { RenderManager } from '../managers/render.manager';
9
11
  import type { RowManager } from '../managers/row.manager';
12
+ import type { SelectionManager } from '../managers/selection.manager';
10
13
  import type { SortManager } from '../managers/sort.manager';
11
- import type { VirtualizationManager } from '../managers/virtualization.manager';
12
14
  import type { FilterItem } from './filter.model';
13
15
  import type { SortDirection, SortItem } from './sort.model';
16
+ import type { TabelaOptions } from './tabela.options';
14
17
  export type TabelaComponents = {
15
18
  body: BodyComponent;
16
19
  footer: FooterComponent;
@@ -37,9 +40,17 @@ export type TabelaManagers = {
37
40
  data: DataManager;
38
41
  event: EventManager;
39
42
  filter: FilterManager;
43
+ navigation: NavigationManager;
40
44
  row: RowManager;
45
+ selection: SelectionManager;
41
46
  sort: SortManager;
42
- virtualization: VirtualizationManager;
47
+ render: RenderManager;
48
+ };
49
+ export type TabelaSelection = {
50
+ clear(): void;
51
+ deselect(keys: Key[]): void;
52
+ select(keys: Key[]): void;
53
+ toggle(): void;
43
54
  };
44
55
  export type TabelaSort = {
45
56
  add(field: string, direction?: SortDirection): void;
@@ -48,3 +59,11 @@ export type TabelaSort = {
48
59
  remove(field: string): void;
49
60
  set(items: SortItem[]): void;
50
61
  };
62
+ export type TabelaState = {
63
+ readonly components: TabelaComponents;
64
+ readonly element: HTMLElement;
65
+ readonly id: number;
66
+ readonly key: string;
67
+ readonly managers: TabelaManagers;
68
+ readonly options: TabelaOptions;
69
+ };
package/types/tabela.d.ts CHANGED
@@ -1,9 +1,10 @@
1
- import type { TabelaData, TabelaFilter, TabelaSort } from './models/tabela.model';
1
+ import type { TabelaData, TabelaFilter, TabelaSelection, TabelaSort } from './models/tabela.model';
2
2
  import type { TabelaOptions } from './models/tabela.options';
3
3
  export declare class Tabela {
4
4
  #private;
5
5
  readonly data: TabelaData;
6
6
  readonly filter: TabelaFilter;
7
+ readonly selection: TabelaSelection;
7
8
  readonly sort: TabelaSort;
8
9
  get key(): string;
9
10
  constructor(element: HTMLElement, options: TabelaOptions);
@@ -1,101 +0,0 @@
1
- import { removeRow, renderRow } from "../components/row.component.js";
2
- import { on } from "@oscarpalmer/toretto/event";
3
- function getRange(down) {
4
- const { components, managers } = this;
5
- const { clientHeight, scrollTop } = components.body.elements.group;
6
- const first = Math.floor(scrollTop / managers.row.height);
7
- const last = Math.min(managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length - 1, Math.ceil((scrollTop + clientHeight) / managers.row.height) - 1);
8
- const before = Math.ceil(clientHeight / managers.row.height) * (down ? 1 : 2);
9
- const after = Math.ceil(clientHeight / managers.row.height) * (down ? 2 : 1);
10
- const start = Math.max(0, first - before);
11
- return {
12
- end: Math.min(managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length - 1, last + after),
13
- start
14
- };
15
- }
16
- function onScroll() {
17
- if (!this.state.active) {
18
- requestAnimationFrame(() => {
19
- const top = this.components.body.elements.group.scrollTop;
20
- this.update(top > this.state.top);
21
- this.state.active = false;
22
- this.state.top = top;
23
- });
24
- this.state.active = true;
25
- }
26
- }
27
- var VirtualizationManager = class {
28
- fragment;
29
- listener;
30
- pool = {
31
- cells: {},
32
- rows: []
33
- };
34
- state = {
35
- active: false,
36
- top: 0
37
- };
38
- visible = /* @__PURE__ */ new Map();
39
- constructor(managers, components) {
40
- this.managers = managers;
41
- this.components = components;
42
- this.listener = on(components.body.elements.group, "scroll", onScroll.bind(this));
43
- }
44
- destroy() {
45
- this.listener();
46
- for (const [index, row] of this.visible) {
47
- removeRow(this.pool, row);
48
- this.visible.delete(index);
49
- }
50
- this.pool.cells = {};
51
- this.pool.rows = [];
52
- this.listener = void 0;
53
- this.visible = void 0;
54
- }
55
- removeCells(fields) {
56
- const { length } = fields;
57
- for (let index = 0; index < length; index += 1) delete this.pool.cells[fields[index]];
58
- for (const [, row] of this.visible) for (let index = 0; index < length; index += 1) {
59
- row.cells[fields[index]].innerHTML = "";
60
- row.cells[fields[index]].remove();
61
- delete row.cells[fields[index]];
62
- }
63
- }
64
- getFragment() {
65
- this.fragment ??= document.createDocumentFragment();
66
- this.fragment.replaceChildren();
67
- return this.fragment;
68
- }
69
- update(down, rerender) {
70
- const { components, managers, pool, visible } = this;
71
- components.body.elements.faker.style.height = `${managers.data.size * managers.row.height}px`;
72
- const indices = /* @__PURE__ */ new Set();
73
- const range = getRange.call(this, down);
74
- for (let index = range.start; index <= range.end; index += 1) indices.add(index);
75
- let remove = rerender ?? false;
76
- for (const [index, row] of visible) {
77
- if (!managers.row.has(row.key) || !indices.has(index)) remove = true;
78
- if (remove) {
79
- visible.delete(index);
80
- removeRow(pool, row);
81
- }
82
- }
83
- const fragment = this.getFragment();
84
- const keys = managers.data.values.keys.active ?? managers.data.values.keys.original;
85
- let count = 0;
86
- for (let index = range.start; index <= range.end; index += 1) {
87
- if (visible.has(index)) continue;
88
- const row = managers.row.get(keys[index]);
89
- if (row == null) continue;
90
- count += 1;
91
- renderRow(managers, row);
92
- visible.set(index, row);
93
- if (row.element != null) {
94
- row.element.style.transform = `translateY(${index * managers.row.height}px)`;
95
- fragment.append(row.element);
96
- }
97
- }
98
- if (count > 0) components.body.elements.group[down ? "append" : "prepend"](fragment);
99
- }
100
- };
101
- export { VirtualizationManager };
@@ -1,176 +0,0 @@
1
- import {on} from '@oscarpalmer/toretto/event';
2
- import type {RemovableEventListener} from '@oscarpalmer/toretto/models';
3
- import {removeRow, renderRow, RowComponent} from '../components/row.component';
4
- import type {TabelaComponents, TabelaManagers} from '../models/tabela.model';
5
- import type {
6
- VirtualizationPool,
7
- VirtualizationRange,
8
- VirtualizationState,
9
- } from '../models/virtualization.model';
10
-
11
- function getRange(this: VirtualizationManager, down: boolean): VirtualizationRange {
12
- const {components, managers} = this;
13
- const {clientHeight, scrollTop} = components.body.elements.group;
14
-
15
- const first = Math.floor(scrollTop / managers.row.height);
16
-
17
- const last = Math.min(
18
- managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length - 1,
19
- Math.ceil((scrollTop + clientHeight) / managers.row.height) - 1,
20
- );
21
-
22
- const before = Math.ceil(clientHeight / managers.row.height) * (down ? 1 : 2);
23
- const after = Math.ceil(clientHeight / managers.row.height) * (down ? 2 : 1);
24
-
25
- const start = Math.max(0, first - before);
26
-
27
- const end = Math.min(
28
- managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length - 1,
29
- last + after,
30
- );
31
-
32
- return {end, start};
33
- }
34
-
35
- function onScroll(this: VirtualizationManager): void {
36
- if (!this.state.active) {
37
- requestAnimationFrame(() => {
38
- const top = this.components.body.elements.group.scrollTop;
39
-
40
- this.update(top > this.state.top);
41
-
42
- this.state.active = false;
43
- this.state.top = top;
44
- });
45
-
46
- this.state.active = true;
47
- }
48
- }
49
-
50
- export class VirtualizationManager {
51
- fragment!: DocumentFragment;
52
-
53
- listener: RemovableEventListener;
54
-
55
- readonly pool: VirtualizationPool = {
56
- cells: {},
57
- rows: [],
58
- };
59
-
60
- readonly state: VirtualizationState = {
61
- active: false,
62
- top: 0,
63
- };
64
-
65
- visible = new Map<number, RowComponent>();
66
-
67
- constructor(
68
- public managers: TabelaManagers,
69
- public components: TabelaComponents,
70
- ) {
71
- this.listener = on(components.body.elements.group, 'scroll', onScroll.bind(this));
72
- }
73
-
74
- destroy(): void {
75
- this.listener();
76
-
77
- for (const [index, row] of this.visible) {
78
- removeRow(this.pool, row);
79
-
80
- this.visible.delete(index);
81
- }
82
-
83
- this.pool.cells = {};
84
- this.pool.rows = [];
85
-
86
- this.listener = undefined as never;
87
- this.visible = undefined as never;
88
- }
89
-
90
- removeCells(fields: string[]): void {
91
- const {length} = fields;
92
-
93
- for (let index = 0; index < length; index += 1) {
94
- delete this.pool.cells[fields[index]];
95
- }
96
-
97
- for (const [, row] of this.visible) {
98
- for (let index = 0; index < length; index += 1) {
99
- row.cells[fields[index]].innerHTML = '';
100
-
101
- row.cells[fields[index]].remove();
102
-
103
- delete row.cells[fields[index]];
104
- }
105
- }
106
- }
107
-
108
- getFragment(): DocumentFragment {
109
- this.fragment ??= document.createDocumentFragment();
110
-
111
- this.fragment.replaceChildren();
112
-
113
- return this.fragment;
114
- }
115
-
116
- update(down: boolean, rerender?: boolean): void {
117
- const {components, managers, pool, visible} = this;
118
-
119
- components.body.elements.faker.style.height = `${managers.data.size * managers.row.height}px`;
120
-
121
- const indices = new Set<number>();
122
- const range = getRange.call(this, down);
123
-
124
- for (let index = range.start; index <= range.end; index += 1) {
125
- indices.add(index);
126
- }
127
-
128
- let remove = rerender ?? false;
129
-
130
- for (const [index, row] of visible) {
131
- if (!managers.row.has(row.key) || !indices.has(index)) {
132
- remove = true;
133
- }
134
-
135
- if (remove) {
136
- visible.delete(index);
137
-
138
- removeRow(pool, row);
139
- }
140
- }
141
-
142
- const fragment = this.getFragment();
143
-
144
- const keys = managers.data.values.keys.active ?? managers.data.values.keys.original;
145
-
146
- let count = 0;
147
-
148
- for (let index = range.start; index <= range.end; index += 1) {
149
- if (visible.has(index)) {
150
- continue;
151
- }
152
-
153
- const row = managers.row.get(keys[index]);
154
-
155
- if (row == null) {
156
- continue;
157
- }
158
-
159
- count += 1;
160
-
161
- renderRow(managers, row);
162
-
163
- visible.set(index, row);
164
-
165
- if (row.element != null) {
166
- row.element.style.transform = `translateY(${index * managers.row.height}px)`;
167
-
168
- fragment.append(row.element);
169
- }
170
- }
171
-
172
- if (count > 0) {
173
- components.body.elements.group[down ? 'append' : 'prepend'](fragment);
174
- }
175
- }
176
- }
@@ -1,14 +0,0 @@
1
- export type VirtualizationPool = {
2
- cells: Record<string, HTMLDivElement[]>;
3
- rows: HTMLDivElement[];
4
- };
5
-
6
- export type VirtualizationRange = {
7
- end: number;
8
- start: number;
9
- };
10
-
11
- export type VirtualizationState = {
12
- active: boolean;
13
- top: number;
14
- };
@@ -1,18 +0,0 @@
1
- import type { RemovableEventListener } from '@oscarpalmer/toretto/models';
2
- import { RowComponent } from '../components/row.component';
3
- import type { TabelaComponents, TabelaManagers } from '../models/tabela.model';
4
- import type { VirtualizationPool, VirtualizationState } from '../models/virtualization.model';
5
- export declare class VirtualizationManager {
6
- managers: TabelaManagers;
7
- components: TabelaComponents;
8
- fragment: DocumentFragment;
9
- listener: RemovableEventListener;
10
- readonly pool: VirtualizationPool;
11
- readonly state: VirtualizationState;
12
- visible: Map<number, RowComponent>;
13
- constructor(managers: TabelaManagers, components: TabelaComponents);
14
- destroy(): void;
15
- removeCells(fields: string[]): void;
16
- getFragment(): DocumentFragment;
17
- update(down: boolean, rerender?: boolean): void;
18
- }
@@ -1,12 +0,0 @@
1
- export type VirtualizationPool = {
2
- cells: Record<string, HTMLDivElement[]>;
3
- rows: HTMLDivElement[];
4
- };
5
- export type VirtualizationRange = {
6
- end: number;
7
- start: number;
8
- };
9
- export type VirtualizationState = {
10
- active: boolean;
11
- top: number;
12
- };