@table-bro/angular 0.0.0-stage → 1.1.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/LICENSE +21 -0
- package/README.md +169 -2
- package/fesm2022/table-bro-angular.mjs +346 -0
- package/fesm2022/table-bro-angular.mjs.map +1 -0
- package/package.json +42 -3
- package/types/table-bro-angular.d.ts +233 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Table, Bro
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,170 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @table-bro/angular
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The Angular wrapper of [Table, Bro](https://table-bro.com): the `<table-bro-ng>` component with signal inputs and outputs
|
|
4
|
+
over the `<table-bro>` Custom Element.
|
|
5
|
+
|
|
6
|
+
The wrapper does not depend on a skin. It works with any registered skin of Table, Bro: Angular Material
|
|
7
|
+
(`@table-bro/angular-material`), Bootstrap (`@table-bro/bootstrap`) or native (`@table-bro/native`).
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install @table-bro/core @table-bro/angular
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Add a skin: `@table-bro/angular-material` for Angular Material, or `@table-bro/bootstrap` or `@table-bro/native`. The
|
|
16
|
+
README of the skin gives its CSS and its registration, `provideTableBroMatSkin()` for Angular Material.
|
|
17
|
+
|
|
18
|
+
## Use
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import {ChangeDetectionStrategy, Component, signal} from '@angular/core';
|
|
22
|
+
|
|
23
|
+
import {TableBroNg} from '@table-bro/angular';
|
|
24
|
+
import type {BroCol, BroConfig, BroRow} from '@table-bro/core';
|
|
25
|
+
|
|
26
|
+
interface Order extends BroRow {
|
|
27
|
+
description: string;
|
|
28
|
+
price: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@Component({
|
|
32
|
+
selector: 'app-orders',
|
|
33
|
+
template: `<table-bro-ng [cols]="cols()" [rows]="rows()" [conf]="conf()"></table-bro-ng>`,
|
|
34
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
35
|
+
imports: [
|
|
36
|
+
TableBroNg
|
|
37
|
+
]
|
|
38
|
+
})
|
|
39
|
+
export class OrdersComponent {
|
|
40
|
+
cols = signal<BroCol<Order>[]>([
|
|
41
|
+
{title: 'Description', name: 'description'},
|
|
42
|
+
{title: 'Price', name: 'price', dataType: 'number', className: 'bro-col_text-right'}
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
rows = signal<Order[]>([
|
|
46
|
+
{description: 'Modern Cotton Chair', price: 100},
|
|
47
|
+
{description: 'Awesome Concrete Ball', price: 200}
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
conf = signal<BroConfig>({skin: 'mat', toolbarTitle: 'Orders'});
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### The server mode
|
|
55
|
+
|
|
56
|
+
With `server: true` the table sorts, filters and pages nothing itself: it gives every gesture of the user as a
|
|
57
|
+
`query`, and the page answers with the rows and the total. The page loads the first page itself:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import {ChangeDetectionStrategy, Component, signal} from '@angular/core';
|
|
61
|
+
|
|
62
|
+
import {TableBroNg} from '@table-bro/angular';
|
|
63
|
+
import type {BroCol, BroConfig, BroQuery, BroRow} from '@table-bro/core';
|
|
64
|
+
|
|
65
|
+
interface Order extends BroRow {
|
|
66
|
+
description: string;
|
|
67
|
+
price: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@Component({
|
|
71
|
+
selector: 'app-orders',
|
|
72
|
+
template: `
|
|
73
|
+
<table-bro-ng [cols]="cols()" [rows]="rows()" [conf]="conf()"
|
|
74
|
+
[total]="total()" [rowsToAppend]="rowsToAppend()" [failed]="failed()"
|
|
75
|
+
(query)="onQueryTable($event)"></table-bro-ng>`,
|
|
76
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
77
|
+
imports: [
|
|
78
|
+
TableBroNg
|
|
79
|
+
]
|
|
80
|
+
})
|
|
81
|
+
export class OrdersComponent {
|
|
82
|
+
cols = signal<BroCol<Order>[]>([
|
|
83
|
+
{title: 'Description', name: 'description'},
|
|
84
|
+
{title: 'Price', name: 'price', dataType: 'number', className: 'bro-col_text-right'}
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
conf = signal<BroConfig>({skin: 'mat', server: true, pageSize: 10});
|
|
88
|
+
|
|
89
|
+
rows = signal<Order[] | undefined>(undefined);
|
|
90
|
+
rowsToAppend = signal<Order[] | undefined>(undefined);
|
|
91
|
+
total = signal<number>(0);
|
|
92
|
+
failed = signal<boolean>(false);
|
|
93
|
+
|
|
94
|
+
private lastQuery?: BroQuery<Order>;
|
|
95
|
+
private loadedQuery = '';
|
|
96
|
+
|
|
97
|
+
constructor() {
|
|
98
|
+
this.onQueryTable({page: 1, pageSize: 10});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async onQueryTable(query: BroQuery<Order>) {
|
|
102
|
+
const queryKey = JSON.stringify([query.filter, query.sort]);
|
|
103
|
+
|
|
104
|
+
this.lastQuery = query;
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const {rows, total} = await loadOrders(query); // your API
|
|
108
|
+
|
|
109
|
+
if (query !== this.lastQuery) {
|
|
110
|
+
return; // a newer query came while this one loaded
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
this.failed.set(false);
|
|
114
|
+
this.total.set(total);
|
|
115
|
+
|
|
116
|
+
// Other filters or another sort replace the rows, the next pages of the same query add to them
|
|
117
|
+
if (queryKey !== this.loadedQuery) {
|
|
118
|
+
this.loadedQuery = queryKey;
|
|
119
|
+
this.rows.set(rows);
|
|
120
|
+
} else {
|
|
121
|
+
this.rowsToAppend.set(rows);
|
|
122
|
+
}
|
|
123
|
+
} catch {
|
|
124
|
+
if (query === this.lastQuery) {
|
|
125
|
+
this.failed.set(true);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Inputs
|
|
133
|
+
|
|
134
|
+
| Input | Meaning |
|
|
135
|
+
| --- | --- |
|
|
136
|
+
| `cols`, `conf` | Columns and config of the table. The element takes them only at `configure`, so a new value creates a new table. |
|
|
137
|
+
| `rows` | An array replaces the rows, `[]` shows an empty state. Without a value (`undefined` or `null`, as before the first value of an `async` pipe) the table keeps what it shows. |
|
|
138
|
+
| `loading` | `true` shows the loading state of a table without rows, or a refresh over the rows it shows. |
|
|
139
|
+
| `failed` | `true` shows the failed state. |
|
|
140
|
+
| `total` | The total number of rows on the server. It is read together with `rows` or `rowsToAppend`, as one delivery. |
|
|
141
|
+
| `rowsToAppend` | The rows of the next page or of a larger page size, for the last `query`. |
|
|
142
|
+
| `filter` | The filters of the page outside the table, for example of a filter drawer. The table takes a new value as a change of its own filters. |
|
|
143
|
+
| `emptyState` | The state for empty `rows`: `'not-found'` for an empty answer to a query with filters. |
|
|
144
|
+
| `tableId` | The `id` of the `<table-bro>` element. |
|
|
145
|
+
| `theme` | The theme of this table: `'light'`, `'dark'` or `'auto'`. |
|
|
146
|
+
|
|
147
|
+
## Outputs
|
|
148
|
+
|
|
149
|
+
| Output | Meaning |
|
|
150
|
+
| --- | --- |
|
|
151
|
+
| `query` | The load intent of the server mode as a `BroQuery`: page, page size, filters and sort. One gesture gives one query. |
|
|
152
|
+
| `action` | Every other action of the `bro-action` event: custom cells, toolbar, paginator. |
|
|
153
|
+
|
|
154
|
+
## Contracts
|
|
155
|
+
|
|
156
|
+
`BroFacade`, `BroServerFacade` describe the wrapper; `BroContainer`, `BroServerContainer` describe the page
|
|
157
|
+
component that feeds it. `BroService` and `BroServerPage` describe the service of the page that turns a `BroQuery`
|
|
158
|
+
into a request of your API and its answer into rows with a total.
|
|
159
|
+
|
|
160
|
+
## Build
|
|
161
|
+
|
|
162
|
+
```sh
|
|
163
|
+
npm run build:angular
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The root of the repository builds the package into `dist/table-bro.angular`.
|
|
167
|
+
|
|
168
|
+
## License
|
|
169
|
+
|
|
170
|
+
MIT
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { isPlatformBrowser } from "@angular/common";
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
import { ChangeDetectionStrategy, Component, ElementRef, NgZone, PLATFORM_ID, effect, inject, input, output, untracked } from "@angular/core";
|
|
4
|
+
import { dispatchAction, events } from "@table-bro/core";
|
|
5
|
+
var TableBroNg = class TableBroNg {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.cols = input.required(...ngDevMode ? [{ debugName: "cols" }] : /* istanbul ignore next */ []);
|
|
8
|
+
this.rows = input.required(...ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []);
|
|
9
|
+
this.conf = input.required(...ngDevMode ? [{ debugName: "conf" }] : /* istanbul ignore next */ []);
|
|
10
|
+
this.total = input(...ngDevMode ? [void 0, { debugName: "total" }] : /* istanbul ignore next */ []);
|
|
11
|
+
this.rowsToAppend = input(...ngDevMode ? [void 0, { debugName: "rowsToAppend" }] : /* istanbul ignore next */ []);
|
|
12
|
+
this.loading = input(false, ...ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []);
|
|
13
|
+
this.failed = input(false, ...ngDevMode ? [{ debugName: "failed" }] : /* istanbul ignore next */ []);
|
|
14
|
+
this.filter = input(...ngDevMode ? [void 0, { debugName: "filter" }] : /* istanbul ignore next */ []);
|
|
15
|
+
this.emptyState = input(...ngDevMode ? [void 0, { debugName: "emptyState" }] : /* istanbul ignore next */ []);
|
|
16
|
+
this.tableId = input(...ngDevMode ? [void 0, { debugName: "tableId" }] : /* istanbul ignore next */ []);
|
|
17
|
+
this.theme = input(...ngDevMode ? [void 0, { debugName: "theme" }] : /* istanbul ignore next */ []);
|
|
18
|
+
this.action = output();
|
|
19
|
+
this.query = output();
|
|
20
|
+
this.appliedLoading = false;
|
|
21
|
+
this.appliedFailed = false;
|
|
22
|
+
this.elementRef = inject(ElementRef);
|
|
23
|
+
this.ngZone = inject(NgZone);
|
|
24
|
+
if (!isPlatformBrowser(inject(PLATFORM_ID))) return;
|
|
25
|
+
effect(() => {
|
|
26
|
+
const cols = this.cols();
|
|
27
|
+
const conf = this.conf();
|
|
28
|
+
const tableId = this.tableId();
|
|
29
|
+
this.ngZone.runOutsideAngular(() => untracked(() => this.createTableBro(cols, conf, tableId)));
|
|
30
|
+
});
|
|
31
|
+
effect(() => {
|
|
32
|
+
const rows = this.rows();
|
|
33
|
+
this.ngZone.runOutsideAngular(() => untracked(() => this.deliverRows(rows)));
|
|
34
|
+
});
|
|
35
|
+
effect(() => {
|
|
36
|
+
const rowsToAppend = this.rowsToAppend();
|
|
37
|
+
if (!rowsToAppend) return;
|
|
38
|
+
this.ngZone.runOutsideAngular(() => this.tableBro.appendRows(rowsToAppend, { total: untracked(this.total) }));
|
|
39
|
+
});
|
|
40
|
+
effect(() => {
|
|
41
|
+
const failed = this.failed();
|
|
42
|
+
const loading = this.loading();
|
|
43
|
+
this.ngZone.runOutsideAngular(() => untracked(() => this.applyState(failed, loading)));
|
|
44
|
+
});
|
|
45
|
+
effect(() => {
|
|
46
|
+
const filter = this.filter();
|
|
47
|
+
this.ngZone.runOutsideAngular(() => this.applyFilter(filter));
|
|
48
|
+
});
|
|
49
|
+
effect(() => {
|
|
50
|
+
const theme = this.theme();
|
|
51
|
+
if (theme !== void 0) this.ngZone.runOutsideAngular(() => this.tableBro.theme = theme);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
createTableBro(cols, conf, tableId) {
|
|
55
|
+
const rows = this.rows();
|
|
56
|
+
const theme = this.theme();
|
|
57
|
+
this.tableBro = document.createElement("table-bro");
|
|
58
|
+
this.appliedLoading = false;
|
|
59
|
+
this.appliedFailed = false;
|
|
60
|
+
if (tableId) this.tableBro.setAttribute("id", tableId);
|
|
61
|
+
if (theme !== void 0) this.tableBro.theme = theme;
|
|
62
|
+
this.deliveredRows = !conf.server && rows?.length ? rows : void 0;
|
|
63
|
+
this.tableBro.configure({
|
|
64
|
+
cols,
|
|
65
|
+
rows: this.deliveredRows,
|
|
66
|
+
conf
|
|
67
|
+
});
|
|
68
|
+
this.tableBro.addEventListener(events.actionEvent, (event) => {
|
|
69
|
+
if (event.target.closest("table-bro") === this.tableBro) this.tableBroListener(event);
|
|
70
|
+
});
|
|
71
|
+
this.elementRef.nativeElement.replaceChildren(this.tableBro);
|
|
72
|
+
this.appliedFilter = void 0;
|
|
73
|
+
this.applyFilter(this.filter());
|
|
74
|
+
this.deliverRows(rows);
|
|
75
|
+
if (this.failed()) this.fail();
|
|
76
|
+
else this.applyLoading(this.loading());
|
|
77
|
+
}
|
|
78
|
+
applyFilter(filter) {
|
|
79
|
+
if (!filter || filter === this.appliedFilter) return;
|
|
80
|
+
this.appliedFilter = filter;
|
|
81
|
+
dispatchAction(this.tableBro, events.filtersFilterEvent, filter);
|
|
82
|
+
}
|
|
83
|
+
deliverRows(rows) {
|
|
84
|
+
if (!rows || rows === this.deliveredRows) return;
|
|
85
|
+
this.deliveredRows = rows;
|
|
86
|
+
this.tableBro.replaceRows(rows, {
|
|
87
|
+
total: this.total(),
|
|
88
|
+
emptyState: this.emptyState()
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
applyLoading(loading) {
|
|
92
|
+
if (loading && this.rows()?.length) this.tableBro.setState("refreshing");
|
|
93
|
+
else if (loading) {
|
|
94
|
+
this.tableBro.setState("loading");
|
|
95
|
+
this.deliveredRows = void 0;
|
|
96
|
+
} else if (this.appliedLoading) this.tableBro.setState("idle");
|
|
97
|
+
this.appliedLoading = loading;
|
|
98
|
+
}
|
|
99
|
+
fail() {
|
|
100
|
+
this.tableBro.setState("fail");
|
|
101
|
+
this.appliedFailed = true;
|
|
102
|
+
this.deliveredRows = void 0;
|
|
103
|
+
}
|
|
104
|
+
applyState(failed, loading) {
|
|
105
|
+
if (failed) {
|
|
106
|
+
if (!this.appliedFailed) this.fail();
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (this.appliedFailed) {
|
|
110
|
+
this.appliedFailed = false;
|
|
111
|
+
this.deliverRows(this.rows());
|
|
112
|
+
}
|
|
113
|
+
this.applyLoading(loading);
|
|
114
|
+
}
|
|
115
|
+
tableBroListener(event) {
|
|
116
|
+
const detail = event.detail;
|
|
117
|
+
if (detail.action === events.filtersServerLoadedEvent) {
|
|
118
|
+
const query = detail.data;
|
|
119
|
+
this.ngZone.run(() => this.query.emit(query));
|
|
120
|
+
} else this.ngZone.run(() => this.action.emit(detail));
|
|
121
|
+
}
|
|
122
|
+
static {
|
|
123
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
124
|
+
minVersion: "12.0.0",
|
|
125
|
+
version: "22.2.2",
|
|
126
|
+
ngImport: i0,
|
|
127
|
+
type: TableBroNg,
|
|
128
|
+
deps: [],
|
|
129
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
static {
|
|
133
|
+
this.ɵcmp = i0.ɵɵngDeclareComponent({
|
|
134
|
+
minVersion: "17.1.0",
|
|
135
|
+
version: "22.2.2",
|
|
136
|
+
type: TableBroNg,
|
|
137
|
+
isStandalone: true,
|
|
138
|
+
selector: "table-bro-ng",
|
|
139
|
+
inputs: {
|
|
140
|
+
cols: {
|
|
141
|
+
classPropertyName: "cols",
|
|
142
|
+
publicName: "cols",
|
|
143
|
+
isSignal: true,
|
|
144
|
+
isRequired: true,
|
|
145
|
+
transformFunction: null
|
|
146
|
+
},
|
|
147
|
+
rows: {
|
|
148
|
+
classPropertyName: "rows",
|
|
149
|
+
publicName: "rows",
|
|
150
|
+
isSignal: true,
|
|
151
|
+
isRequired: true,
|
|
152
|
+
transformFunction: null
|
|
153
|
+
},
|
|
154
|
+
conf: {
|
|
155
|
+
classPropertyName: "conf",
|
|
156
|
+
publicName: "conf",
|
|
157
|
+
isSignal: true,
|
|
158
|
+
isRequired: true,
|
|
159
|
+
transformFunction: null
|
|
160
|
+
},
|
|
161
|
+
total: {
|
|
162
|
+
classPropertyName: "total",
|
|
163
|
+
publicName: "total",
|
|
164
|
+
isSignal: true,
|
|
165
|
+
isRequired: false,
|
|
166
|
+
transformFunction: null
|
|
167
|
+
},
|
|
168
|
+
rowsToAppend: {
|
|
169
|
+
classPropertyName: "rowsToAppend",
|
|
170
|
+
publicName: "rowsToAppend",
|
|
171
|
+
isSignal: true,
|
|
172
|
+
isRequired: false,
|
|
173
|
+
transformFunction: null
|
|
174
|
+
},
|
|
175
|
+
loading: {
|
|
176
|
+
classPropertyName: "loading",
|
|
177
|
+
publicName: "loading",
|
|
178
|
+
isSignal: true,
|
|
179
|
+
isRequired: false,
|
|
180
|
+
transformFunction: null
|
|
181
|
+
},
|
|
182
|
+
failed: {
|
|
183
|
+
classPropertyName: "failed",
|
|
184
|
+
publicName: "failed",
|
|
185
|
+
isSignal: true,
|
|
186
|
+
isRequired: false,
|
|
187
|
+
transformFunction: null
|
|
188
|
+
},
|
|
189
|
+
filter: {
|
|
190
|
+
classPropertyName: "filter",
|
|
191
|
+
publicName: "filter",
|
|
192
|
+
isSignal: true,
|
|
193
|
+
isRequired: false,
|
|
194
|
+
transformFunction: null
|
|
195
|
+
},
|
|
196
|
+
emptyState: {
|
|
197
|
+
classPropertyName: "emptyState",
|
|
198
|
+
publicName: "emptyState",
|
|
199
|
+
isSignal: true,
|
|
200
|
+
isRequired: false,
|
|
201
|
+
transformFunction: null
|
|
202
|
+
},
|
|
203
|
+
tableId: {
|
|
204
|
+
classPropertyName: "tableId",
|
|
205
|
+
publicName: "tableId",
|
|
206
|
+
isSignal: true,
|
|
207
|
+
isRequired: false,
|
|
208
|
+
transformFunction: null
|
|
209
|
+
},
|
|
210
|
+
theme: {
|
|
211
|
+
classPropertyName: "theme",
|
|
212
|
+
publicName: "theme",
|
|
213
|
+
isSignal: true,
|
|
214
|
+
isRequired: false,
|
|
215
|
+
transformFunction: null
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
outputs: {
|
|
219
|
+
action: "action",
|
|
220
|
+
query: "query"
|
|
221
|
+
},
|
|
222
|
+
ngImport: i0,
|
|
223
|
+
template: "",
|
|
224
|
+
isInline: true,
|
|
225
|
+
styles: [":host{display:block}\n"],
|
|
226
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
231
|
+
minVersion: "12.0.0",
|
|
232
|
+
version: "22.2.2",
|
|
233
|
+
ngImport: i0,
|
|
234
|
+
type: TableBroNg,
|
|
235
|
+
decorators: [{
|
|
236
|
+
type: Component,
|
|
237
|
+
args: [{
|
|
238
|
+
selector: "table-bro-ng",
|
|
239
|
+
template: "",
|
|
240
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
241
|
+
styles: [":host{display:block}\n"]
|
|
242
|
+
}]
|
|
243
|
+
}],
|
|
244
|
+
ctorParameters: () => [],
|
|
245
|
+
propDecorators: {
|
|
246
|
+
cols: [{
|
|
247
|
+
type: i0.Input,
|
|
248
|
+
args: [{
|
|
249
|
+
isSignal: true,
|
|
250
|
+
alias: "cols",
|
|
251
|
+
required: true
|
|
252
|
+
}]
|
|
253
|
+
}],
|
|
254
|
+
rows: [{
|
|
255
|
+
type: i0.Input,
|
|
256
|
+
args: [{
|
|
257
|
+
isSignal: true,
|
|
258
|
+
alias: "rows",
|
|
259
|
+
required: true
|
|
260
|
+
}]
|
|
261
|
+
}],
|
|
262
|
+
conf: [{
|
|
263
|
+
type: i0.Input,
|
|
264
|
+
args: [{
|
|
265
|
+
isSignal: true,
|
|
266
|
+
alias: "conf",
|
|
267
|
+
required: true
|
|
268
|
+
}]
|
|
269
|
+
}],
|
|
270
|
+
total: [{
|
|
271
|
+
type: i0.Input,
|
|
272
|
+
args: [{
|
|
273
|
+
isSignal: true,
|
|
274
|
+
alias: "total",
|
|
275
|
+
required: false
|
|
276
|
+
}]
|
|
277
|
+
}],
|
|
278
|
+
rowsToAppend: [{
|
|
279
|
+
type: i0.Input,
|
|
280
|
+
args: [{
|
|
281
|
+
isSignal: true,
|
|
282
|
+
alias: "rowsToAppend",
|
|
283
|
+
required: false
|
|
284
|
+
}]
|
|
285
|
+
}],
|
|
286
|
+
loading: [{
|
|
287
|
+
type: i0.Input,
|
|
288
|
+
args: [{
|
|
289
|
+
isSignal: true,
|
|
290
|
+
alias: "loading",
|
|
291
|
+
required: false
|
|
292
|
+
}]
|
|
293
|
+
}],
|
|
294
|
+
failed: [{
|
|
295
|
+
type: i0.Input,
|
|
296
|
+
args: [{
|
|
297
|
+
isSignal: true,
|
|
298
|
+
alias: "failed",
|
|
299
|
+
required: false
|
|
300
|
+
}]
|
|
301
|
+
}],
|
|
302
|
+
filter: [{
|
|
303
|
+
type: i0.Input,
|
|
304
|
+
args: [{
|
|
305
|
+
isSignal: true,
|
|
306
|
+
alias: "filter",
|
|
307
|
+
required: false
|
|
308
|
+
}]
|
|
309
|
+
}],
|
|
310
|
+
emptyState: [{
|
|
311
|
+
type: i0.Input,
|
|
312
|
+
args: [{
|
|
313
|
+
isSignal: true,
|
|
314
|
+
alias: "emptyState",
|
|
315
|
+
required: false
|
|
316
|
+
}]
|
|
317
|
+
}],
|
|
318
|
+
tableId: [{
|
|
319
|
+
type: i0.Input,
|
|
320
|
+
args: [{
|
|
321
|
+
isSignal: true,
|
|
322
|
+
alias: "tableId",
|
|
323
|
+
required: false
|
|
324
|
+
}]
|
|
325
|
+
}],
|
|
326
|
+
theme: [{
|
|
327
|
+
type: i0.Input,
|
|
328
|
+
args: [{
|
|
329
|
+
isSignal: true,
|
|
330
|
+
alias: "theme",
|
|
331
|
+
required: false
|
|
332
|
+
}]
|
|
333
|
+
}],
|
|
334
|
+
action: [{
|
|
335
|
+
type: i0.Output,
|
|
336
|
+
args: ["action"]
|
|
337
|
+
}],
|
|
338
|
+
query: [{
|
|
339
|
+
type: i0.Output,
|
|
340
|
+
args: ["query"]
|
|
341
|
+
}]
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
export { TableBroNg };
|
|
345
|
+
|
|
346
|
+
//# sourceMappingURL=table-bro-angular.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table-bro-angular.mjs","names":[],"sources":["../../../packages/angular/src/lib/table-bro-ng.ts"],"sourcesContent":["import {isPlatformBrowser} from '@angular/common';\nimport {ChangeDetectionStrategy, Component, effect, ElementRef, inject, input, NgZone, output, PLATFORM_ID, untracked} from '@angular/core';\n\nimport {type BroActionDetail, type BroCol, type BroConfig, type BroEmptyState, type BroFilters, type BroQuery, type BroUserTheme, dispatchAction, events, type TableBroHTMLElement} from '@table-bro/core';\n\nimport type {BroServerFacade} from './table-bro.facade';\n\n/**\n * The Angular wrapper of <table-bro>: it translates the inputs into the methods of the element and the bro-action event\n * into the outputs. The table stays one: the wrapper renders nothing of its own and keeps no pagination, sort or filters.\n * The table works outside the Angular zone, so its animation frames start no change detection; the outputs emit inside it.\n */\n@Component({\n selector: 'table-bro-ng',\n template: '',\n styles: ':host { display: block; }',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class TableBroNg<MODEL extends object> implements BroServerFacade<MODEL> {\n cols = input.required<BroCol<MODEL>[]>();\n /** The rows of the table; without a value, as before the first value of an async pipe, the table keeps what it shows. */\n rows = input.required<MODEL[] | undefined | null>();\n conf = input.required<BroConfig<MODEL>>();\n\n total = input<number>();\n rowsToAppend = input<MODEL[] | undefined>();\n /** The loading of the rows: the loading state of a table without rows, a refresh over the rows that the table shows. */\n loading = input<boolean>(false);\n /** A failed loading of the rows: the fail state of the table. */\n failed = input<boolean>(false);\n\n /**\n * The filters of the page outside the table, for example of a filter drawer. The table takes a new value as a change\n * of its own filters: it filters its rows in the local mode and sends a query with them in the server mode.\n * A cleared filter comes as undefined, null or an empty string; false and 0 are values of a filter.\n */\n filter = input<BroFilters<MODEL> | undefined>();\n /** The state of the table for empty rows: 'not-found' for an empty answer to a query with filters; 'no-data' without it. */\n emptyState = input<BroEmptyState>();\n /** The id of the <table-bro> element; without it the table gives itself a unique one. */\n tableId = input<string>();\n /** The theme of this table; without it the table takes the theme from its config. */\n theme = input<BroUserTheme | null>();\n\n action = output<BroActionDetail<MODEL>>();\n query = output<BroQuery<MODEL>>();\n\n /* Helpers */\n /** The loading that the table has got from the wrapper: its end without new rows ends the refresh. */\n private appliedLoading = false;\n /** The failure that the table shows: its end shows the rows of the page again. */\n private appliedFailed = false;\n /** The filters of the page the table has got from the wrapper: a new table gets the current ones again. */\n private appliedFilter: BroFilters<MODEL> | undefined;\n /** The rows the table has got from the wrapper: the same array is not delivered twice. */\n private deliveredRows: MODEL[] | undefined | null;\n private tableBro!: TableBroHTMLElement;\n\n private elementRef: ElementRef<HTMLElement> = inject(ElementRef);\n private ngZone = inject(NgZone);\n\n constructor() {\n // The server render of Angular leaves the host empty: the table is created in the browser\n if (!isPlatformBrowser(inject(PLATFORM_ID))) {\n return;\n }\n\n // The element takes the columns and the config only at configure, so their change creates a new table\n effect(() => {\n const cols = this.cols();\n const conf = this.conf();\n const tableId = this.tableId();\n\n this.ngZone.runOutsideAngular(() => untracked(() => this.createTableBro(cols, conf, tableId)));\n });\n\n effect(() => {\n const rows = this.rows();\n\n this.ngZone.runOutsideAngular(() => untracked(() => this.deliverRows(rows)));\n });\n\n effect(() => {\n const rowsToAppend = this.rowsToAppend();\n\n if (!rowsToAppend) {\n return;\n }\n\n // One batch for one delivery: the rows go with the total of the same answer; their page is the one of the last query.\n // The server mode binds the total with the rows it appends\n this.ngZone.runOutsideAngular(() => this.tableBro.appendRows(rowsToAppend, {total: untracked(this.total)!}));\n });\n\n // The loading and the failure in one effect: the end of a failure shows the rows again before a loading goes on\n effect(() => {\n const failed = this.failed();\n const loading = this.loading();\n\n this.ngZone.runOutsideAngular(() => untracked(() => this.applyState(failed, loading)));\n });\n\n effect(() => {\n const filter = this.filter();\n\n this.ngZone.runOutsideAngular(() => this.applyFilter(filter));\n });\n\n effect(() => {\n const theme = this.theme();\n\n if (theme !== undefined) {\n this.ngZone.runOutsideAngular(() => this.tableBro.theme = theme);\n }\n });\n }\n\n private createTableBro(cols: BroCol<MODEL>[], conf: BroConfig<MODEL>, tableId?: string) {\n const rows = this.rows();\n const theme = this.theme();\n\n this.tableBro = document.createElement('table-bro') as TableBroHTMLElement;\n this.appliedLoading = false;\n this.appliedFailed = false;\n\n if (tableId) {\n this.tableBro.setAttribute('id', tableId);\n }\n\n if (theme !== undefined) {\n this.tableBro.theme = theme;\n }\n\n // The rows of the local mode render with the table; the server mode delivers them below, with their total\n this.deliveredRows = (!conf.server && rows?.length) ? rows : undefined;\n\n this.tableBro.configure({cols, rows: this.deliveredRows, conf});\n // The actions of a table in the row details of this one bubble through it: its outputs give only the own ones\n this.tableBro.addEventListener(events.actionEvent, (event: CustomEvent<BroActionDetail<MODEL>>) => {\n if ((<Element>event.target).closest('table-bro') === this.tableBro) {\n this.tableBroListener(event);\n }\n });\n\n this.elementRef.nativeElement.replaceChildren(this.tableBro);\n\n this.appliedFilter = undefined;\n this.applyFilter(this.filter());\n\n this.deliverRows(rows);\n\n // A new table takes the state of the page too\n if (this.failed()) {\n this.fail();\n } else {\n this.applyLoading(this.loading());\n }\n }\n\n private applyFilter(filter: BroFilters<MODEL> | undefined) {\n if (!filter || filter === this.appliedFilter) {\n return;\n }\n\n this.appliedFilter = filter;\n\n dispatchAction(this.tableBro, events.filtersFilterEvent, filter);\n }\n\n private deliverRows(rows: MODEL[] | undefined | null) {\n // Rows without a value change nothing: the loading and the failure come with their own inputs\n if (!rows || rows === this.deliveredRows) {\n return;\n }\n\n this.deliveredRows = rows;\n\n // The rows answer the last query of the table, which gives their page size\n this.tableBro.replaceRows(rows, {total: this.total(), emptyState: this.emptyState()});\n }\n\n /** A loading over the rows that the page still gives is a refresh; without rows it is the loading state. */\n private applyLoading(loading: boolean) {\n if (loading && this.rows()?.length) {\n this.tableBro.setState('refreshing');\n } else if (loading) {\n this.tableBro.setState('loading');\n // The table shows no rows now: the next rows are delivered, even the same array\n this.deliveredRows = undefined;\n } else if (this.appliedLoading) {\n this.tableBro.setState('idle');\n }\n\n this.appliedLoading = loading;\n }\n\n private fail() {\n this.tableBro.setState('fail');\n this.appliedFailed = true;\n // The table shows no rows now: the next rows are delivered, even the same array\n this.deliveredRows = undefined;\n }\n\n /**\n * The failure, else the loading. The end of a failure shows the rows of the page again, also the same array, which no\n * new value of the rows brings; a loading that goes on keeps its refresh over them.\n */\n private applyState(failed: boolean, loading: boolean) {\n if (failed) {\n if (!this.appliedFailed) {\n this.fail();\n }\n\n return;\n }\n\n if (this.appliedFailed) {\n this.appliedFailed = false;\n this.deliverRows(this.rows());\n }\n\n this.applyLoading(loading);\n }\n\n private tableBroListener(event: CustomEvent<BroActionDetail<MODEL>>) {\n const detail = event.detail;\n\n /**\n * Pagination, Sorting or Filters change\n */\n if (detail.action === events.filtersServerLoadedEvent) {\n const query = <BroQuery<MODEL>>detail.data;\n\n this.ngZone.run(() => this.query.emit(query));\n } else {\n this.ngZone.run(() => this.action.emit(detail));\n }\n }\n}\n"],"mappings":";;;;AAkBA,IAAa,aAAb,MAAa,WAAU;CA2CrB,cAAA;EA1CA,KAAA,OAAO,MAAM,SAA2B,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;EAExC,KAAA,OAAO,MAAM,SAAsC,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;EACnD,KAAA,OAAO,MAAM,SAA4B,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;EAEzC,KAAA,QAAQ,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;EACvB,KAAA,eAAe,MAA4B,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;EAE3C,KAAA,UAAU,MAAe,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;EAE/B,KAAA,SAAS,MAAe,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;EAO9B,KAAA,SAAS,MAAsC,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;EAE/C,KAAA,aAAa,MAAsB,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;EAEnC,KAAA,UAAU,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;EAEzB,KAAA,QAAQ,MAA4B,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;EAEpC,KAAA,SAAS,OAAM;EACf,KAAA,QAAQ,OAAM;EAIN,KAAA,iBAAiB;EAEjB,KAAA,gBAAgB;EAOhB,KAAA,aAAsC,OAAO,UAAU;EACvD,KAAA,SAAS,OAAO,MAAM;EAI5B,IAAI,CAAC,kBAAkB,OAAO,WAAW,CAAC,GACxC;EAIF,aAAY;GACV,MAAM,OAAO,KAAK,KAAI;GACtB,MAAM,OAAO,KAAK,KAAI;GACtB,MAAM,UAAU,KAAK,QAAO;GAE5B,KAAK,OAAO,wBAAwB,gBAAgB,KAAK,eAAe,MAAM,MAAM,OAAO,CAAC,CAAC;EAC/F,CAAC;EAED,aAAY;GACV,MAAM,OAAO,KAAK,KAAI;GAEtB,KAAK,OAAO,wBAAwB,gBAAgB,KAAK,YAAY,IAAI,CAAC,CAAC;EAC7E,CAAC;EAED,aAAY;GACV,MAAM,eAAe,KAAK,aAAY;GAEtC,IAAI,CAAC,cACH;GAKF,KAAK,OAAO,wBAAwB,KAAK,SAAS,WAAW,cAAc,EAAC,OAAO,UAAU,KAAK,KAAK,EAAE,CAAC,CAAC;EAC7G,CAAC;EAGD,aAAY;GACV,MAAM,SAAS,KAAK,OAAM;GAC1B,MAAM,UAAU,KAAK,QAAO;GAE5B,KAAK,OAAO,wBAAwB,gBAAgB,KAAK,WAAW,QAAQ,OAAO,CAAC,CAAC;EACvF,CAAC;EAED,aAAY;GACV,MAAM,SAAS,KAAK,OAAM;GAE1B,KAAK,OAAO,wBAAwB,KAAK,YAAY,MAAM,CAAC;EAC9D,CAAC;EAED,aAAY;GACV,MAAM,QAAQ,KAAK,MAAK;GAExB,IAAI,UAAU,QACZ,KAAK,OAAO,wBAAwB,KAAK,SAAS,QAAQ,KAAK;EAEnE,CAAC;CACH;CAEQ,eAAe,MAAuB,MAAwB,SAAgB;EACpF,MAAM,OAAO,KAAK,KAAI;EACtB,MAAM,QAAQ,KAAK,MAAK;EAExB,KAAK,WAAW,SAAS,cAAc,WAAW;EAClD,KAAK,iBAAiB;EACtB,KAAK,gBAAgB;EAErB,IAAI,SACF,KAAK,SAAS,aAAa,MAAM,OAAO;EAG1C,IAAI,UAAU,QACZ,KAAK,SAAS,QAAQ;EAIxB,KAAK,gBAAiB,CAAC,KAAK,UAAU,MAAM,SAAU,OAAO;EAE7D,KAAK,SAAS,UAAU;GAAC;GAAM,MAAM,KAAK;GAAe;EAAI,CAAC;EAE9D,KAAK,SAAS,iBAAiB,OAAO,cAAc,UAA8C;GAChG,IAAc,MAAM,OAAQ,QAAQ,WAAW,MAAM,KAAK,UACxD,KAAK,iBAAiB,KAAK;EAE/B,CAAC;EAED,KAAK,WAAW,cAAc,gBAAgB,KAAK,QAAQ;EAE3D,KAAK,gBAAgB;EACrB,KAAK,YAAY,KAAK,OAAM,CAAE;EAE9B,KAAK,YAAY,IAAI;EAGrB,IAAI,KAAK,OAAM,GACb,KAAK,KAAI;OAET,KAAK,aAAa,KAAK,QAAO,CAAE;CAEpC;CAEQ,YAAY,QAAqC;EACvD,IAAI,CAAC,UAAU,WAAW,KAAK,eAC7B;EAGF,KAAK,gBAAgB;EAErB,eAAe,KAAK,UAAU,OAAO,oBAAoB,MAAM;CACjE;CAEQ,YAAY,MAAgC;EAElD,IAAI,CAAC,QAAQ,SAAS,KAAK,eACzB;EAGF,KAAK,gBAAgB;EAGrB,KAAK,SAAS,YAAY,MAAM;GAAC,OAAO,KAAK,MAAK;GAAI,YAAY,KAAK,WAAU;EAAE,CAAC;CACtF;CAGQ,aAAa,SAAgB;EACnC,IAAI,WAAW,KAAK,KAAI,CAAE,EAAE,QAC1B,KAAK,SAAS,SAAS,YAAY;OAC9B,IAAI,SAAS;GAClB,KAAK,SAAS,SAAS,SAAS;GAEhC,KAAK,gBAAgB;EACvB,OAAO,IAAI,KAAK,gBACd,KAAK,SAAS,SAAS,MAAM;EAG/B,KAAK,iBAAiB;CACxB;CAEQ,OAAI;EACV,KAAK,SAAS,SAAS,MAAM;EAC7B,KAAK,gBAAgB;EAErB,KAAK,gBAAgB;CACvB;CAMQ,WAAW,QAAiB,SAAgB;EAClD,IAAI,QAAQ;GACV,IAAI,CAAC,KAAK,eACR,KAAK,KAAI;GAGX;EACF;EAEA,IAAI,KAAK,eAAe;GACtB,KAAK,gBAAgB;GACrB,KAAK,YAAY,KAAK,KAAI,CAAE;EAC9B;EAEA,KAAK,aAAa,OAAO;CAC3B;CAEQ,iBAAiB,OAA0C;EACjE,MAAM,SAAS,MAAM;EAKrB,IAAI,OAAO,WAAW,OAAO,0BAA0B;GACrD,MAAM,QAAyB,OAAO;GAEtC,KAAK,OAAO,UAAU,KAAK,MAAM,KAAK,KAAK,CAAC;EAC9C,OACE,KAAK,OAAO,UAAU,KAAK,OAAO,KAAK,MAAM,CAAC;CAElD;CA3NW;EAAA,KAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAU,MAAA,CAAA;GAAA,QAAA,GAAA,gBAAA;EAAA,CAAA;CAAA;CAAV;EAAA,KAAA,OAAA,GAAA,qBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,MAAA;GAAU,cAAA;GAAA,UAAA;GAAA,QAAA;IAAA,MAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,MAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,MAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,OAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,cAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,SAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,QAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,QAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,YAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,SAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,OAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;GAAA;GAAA,SAAA;IAAA,QAAA;IAAA,OAAA;GAAA;GAAA,UAAA;GAAA,UAJX;GAAE,UAAA;GAAA,QAAA,CAAA,wBAAA;GAAA,iBAAA,GAAA,wBAAA;EAAA,CAAA;CAAA;;AAID,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAU,YAAA,CAAA;EANtB,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAc,UACd;GAAE,iBAEK,wBAAwB;GAAM,QAAA,CAAA,wBAAA;EAAA,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,45 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@table-bro/angular",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Pixel-perfect Material data tables for Angular, and more. A Web Components table engine on top of existing UI components.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"angular",
|
|
7
|
+
"table",
|
|
8
|
+
"data-table",
|
|
9
|
+
"datatable",
|
|
10
|
+
"data-grid",
|
|
11
|
+
"web-components"
|
|
12
|
+
],
|
|
13
|
+
"author": "table-bro",
|
|
14
|
+
"homepage": "https://table-bro.com",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/table-bro/table-bro.git",
|
|
18
|
+
"directory": "packages/angular"
|
|
19
|
+
},
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/table-bro/table-bro/issues"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"sideEffects": false,
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"@angular/common": ">=20 <23",
|
|
27
|
+
"@angular/core": ">=20 <23",
|
|
28
|
+
"@table-bro/core": "^1.1.0"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"tslib": "^2.3.0"
|
|
32
|
+
},
|
|
33
|
+
"module": "fesm2022/table-bro-angular.mjs",
|
|
34
|
+
"typings": "types/table-bro-angular.d.ts",
|
|
35
|
+
"exports": {
|
|
36
|
+
"./package.json": {
|
|
37
|
+
"default": "./package.json"
|
|
38
|
+
},
|
|
39
|
+
".": {
|
|
40
|
+
"types": "./types/table-bro-angular.d.ts",
|
|
41
|
+
"default": "./fesm2022/table-bro-angular.mjs"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"type": "module"
|
|
6
45
|
}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { BroActionDetail, BroCol, BroConfig, BroEmptyState, BroFilters, BroQuery, BroUserTheme } from "@table-bro/core";
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
import { InputSignal, OutputEmitterRef, Signal } from "@angular/core";
|
|
4
|
+
/**
|
|
5
|
+
* Public facade contract for a table component.
|
|
6
|
+
*
|
|
7
|
+
* Defines the public input surface exposed to consumers
|
|
8
|
+
* (parent components and templates).
|
|
9
|
+
*
|
|
10
|
+
* All properties are Angular input signals managed by the framework and
|
|
11
|
+
* must be treated as immutable from the consumer perspective.
|
|
12
|
+
*
|
|
13
|
+
* @typeParam MODEL Row model displayed by the table
|
|
14
|
+
*/
|
|
15
|
+
export interface BroFacade<MODEL extends object> {
|
|
16
|
+
/** Column definitions and UI configuration */
|
|
17
|
+
cols: InputSignal<BroCol<MODEL>[]>;
|
|
18
|
+
/** Table rows; without a value the table keeps what it shows */
|
|
19
|
+
rows: InputSignal<MODEL[] | undefined | null>;
|
|
20
|
+
/** Table configuration (page size, title, etc.) */
|
|
21
|
+
conf: InputSignal<BroConfig<MODEL>>;
|
|
22
|
+
/** The loading of the rows: the loading state, or a refresh over the shown rows */
|
|
23
|
+
loading?: InputSignal<boolean>;
|
|
24
|
+
/** A failed loading of the rows: the fail state */
|
|
25
|
+
failed?: InputSignal<boolean>;
|
|
26
|
+
action?: OutputEmitterRef<BroActionDetail<MODEL>>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Public facade contract for a server-driven table.
|
|
30
|
+
*
|
|
31
|
+
* Extends BroFacade with server-specific responsibilities such as
|
|
32
|
+
* total row count exposure and query emission.
|
|
33
|
+
*
|
|
34
|
+
* Intended to be injected into page components that handle
|
|
35
|
+
* server-side data fetching.
|
|
36
|
+
*
|
|
37
|
+
* @typeParam MODEL Row model displayed by the table
|
|
38
|
+
*/
|
|
39
|
+
export interface BroServerFacade<MODEL extends object> extends BroFacade<MODEL> {
|
|
40
|
+
/** Total number of rows available on the server */
|
|
41
|
+
total: InputSignal<number | undefined>;
|
|
42
|
+
rowsToAppend?: InputSignal<MODEL[] | undefined>;
|
|
43
|
+
/**
|
|
44
|
+
* Emits table queries whenever pagination, sorting or filtering changes.
|
|
45
|
+
* Handled by a page-level server container.
|
|
46
|
+
*/
|
|
47
|
+
query: OutputEmitterRef<BroQuery<MODEL>>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Page-level table state contract.
|
|
51
|
+
*
|
|
52
|
+
* Describes the local state and behavior of a page component that injects
|
|
53
|
+
* and coordinates a BroFacade.
|
|
54
|
+
*
|
|
55
|
+
* The container:
|
|
56
|
+
* - adapts facade data for the page template
|
|
57
|
+
* - owns page-specific reactive state
|
|
58
|
+
* - orchestrates table initialization and lifecycle
|
|
59
|
+
*
|
|
60
|
+
* All properties are writable signals owned by the page component.
|
|
61
|
+
*
|
|
62
|
+
* @typeParam MODEL Row model displayed by the table
|
|
63
|
+
*/
|
|
64
|
+
export interface BroContainer<MODEL extends object> {
|
|
65
|
+
/** Reactive column definitions bound to the table */
|
|
66
|
+
cols: Signal<BroCol<MODEL>[]>;
|
|
67
|
+
/** Reactive row data consumed by the template */
|
|
68
|
+
rows: Signal<MODEL[] | undefined | null>;
|
|
69
|
+
/** Reactive table configuration for the page */
|
|
70
|
+
conf: Signal<BroConfig<MODEL>>;
|
|
71
|
+
/** Page-level initialization hook coordinating the facade */
|
|
72
|
+
initTable: () => void;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Page-level state contract for a server-driven table.
|
|
76
|
+
*
|
|
77
|
+
* Extends BroContainer with server-specific state and query handling logic.
|
|
78
|
+
*
|
|
79
|
+
* Implementations are responsible for:
|
|
80
|
+
* - handling table queries
|
|
81
|
+
* - calling backend services
|
|
82
|
+
* - updating rows and total count
|
|
83
|
+
*
|
|
84
|
+
* @typeParam MODEL Row model displayed by the table
|
|
85
|
+
* @typeParam EXTRA Additional backend-specific filter fields
|
|
86
|
+
*/
|
|
87
|
+
export interface BroServerContainer<MODEL extends object, EXTRA extends object = object> extends BroContainer<MODEL> {
|
|
88
|
+
/** Reactive total row count provided by the backend */
|
|
89
|
+
total: Signal<number>;
|
|
90
|
+
rowsToAppend?: Signal<MODEL[] | undefined>;
|
|
91
|
+
/**
|
|
92
|
+
* Handles table queries emitted by the facade.
|
|
93
|
+
* Triggers server communication and state updates.
|
|
94
|
+
*/
|
|
95
|
+
onQueryTable: (query: BroQuery<MODEL, EXTRA>) => void;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* The Angular wrapper of <table-bro>: it translates the inputs into the methods of the element and the bro-action event
|
|
99
|
+
* into the outputs. The table stays one: the wrapper renders nothing of its own and keeps no pagination, sort or filters.
|
|
100
|
+
* The table works outside the Angular zone, so its animation frames start no change detection; the outputs emit inside it.
|
|
101
|
+
*/
|
|
102
|
+
export declare class TableBroNg<MODEL extends object> implements BroServerFacade<MODEL> {
|
|
103
|
+
cols: import("@angular/core").InputSignal<BroCol<MODEL>[]>;
|
|
104
|
+
/** The rows of the table; without a value, as before the first value of an async pipe, the table keeps what it shows. */
|
|
105
|
+
rows: import("@angular/core").InputSignal<MODEL[] | null | undefined>;
|
|
106
|
+
conf: import("@angular/core").InputSignal<BroConfig<MODEL>>;
|
|
107
|
+
total: import("@angular/core").InputSignal<number | undefined>;
|
|
108
|
+
rowsToAppend: import("@angular/core").InputSignal<MODEL[] | undefined>;
|
|
109
|
+
/** The loading of the rows: the loading state of a table without rows, a refresh over the rows that the table shows. */
|
|
110
|
+
loading: import("@angular/core").InputSignal<boolean>;
|
|
111
|
+
/** A failed loading of the rows: the fail state of the table. */
|
|
112
|
+
failed: import("@angular/core").InputSignal<boolean>;
|
|
113
|
+
/**
|
|
114
|
+
* The filters of the page outside the table, for example of a filter drawer. The table takes a new value as a change
|
|
115
|
+
* of its own filters: it filters its rows in the local mode and sends a query with them in the server mode.
|
|
116
|
+
* A cleared filter comes as undefined, null or an empty string; false and 0 are values of a filter.
|
|
117
|
+
*/
|
|
118
|
+
filter: import("@angular/core").InputSignal<BroFilters<MODEL> | undefined>;
|
|
119
|
+
/** The state of the table for empty rows: 'not-found' for an empty answer to a query with filters; 'no-data' without it. */
|
|
120
|
+
emptyState: import("@angular/core").InputSignal<BroEmptyState | undefined>;
|
|
121
|
+
/** The id of the <table-bro> element; without it the table gives itself a unique one. */
|
|
122
|
+
tableId: import("@angular/core").InputSignal<string | undefined>;
|
|
123
|
+
/** The theme of this table; without it the table takes the theme from its config. */
|
|
124
|
+
theme: import("@angular/core").InputSignal<BroUserTheme | null | undefined>;
|
|
125
|
+
action: import("@angular/core").OutputEmitterRef<BroActionDetail<MODEL>>;
|
|
126
|
+
query: import("@angular/core").OutputEmitterRef<BroQuery<MODEL, object>>;
|
|
127
|
+
/** The loading that the table has got from the wrapper: its end without new rows ends the refresh. */
|
|
128
|
+
private appliedLoading;
|
|
129
|
+
/** The failure that the table shows: its end shows the rows of the page again. */
|
|
130
|
+
private appliedFailed;
|
|
131
|
+
/** The filters of the page the table has got from the wrapper: a new table gets the current ones again. */
|
|
132
|
+
private appliedFilter;
|
|
133
|
+
/** The rows the table has got from the wrapper: the same array is not delivered twice. */
|
|
134
|
+
private deliveredRows;
|
|
135
|
+
private tableBro;
|
|
136
|
+
private elementRef;
|
|
137
|
+
private ngZone;
|
|
138
|
+
constructor();
|
|
139
|
+
private createTableBro;
|
|
140
|
+
private applyFilter;
|
|
141
|
+
private deliverRows;
|
|
142
|
+
/** A loading over the rows that the page still gives is a refresh; without rows it is the loading state. */
|
|
143
|
+
private applyLoading;
|
|
144
|
+
private fail;
|
|
145
|
+
/**
|
|
146
|
+
* The failure, else the loading. The end of a failure shows the rows of the page again, also the same array, which no
|
|
147
|
+
* new value of the rows brings; a loading that goes on keeps its refresh over them.
|
|
148
|
+
*/
|
|
149
|
+
private applyState;
|
|
150
|
+
private tableBroListener;
|
|
151
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<TableBroNg<any>, never>;
|
|
152
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<TableBroNg<any>, "table-bro-ng", never, {
|
|
153
|
+
"cols": {
|
|
154
|
+
"alias": "cols";
|
|
155
|
+
"required": true;
|
|
156
|
+
"isSignal": true;
|
|
157
|
+
};
|
|
158
|
+
"rows": {
|
|
159
|
+
"alias": "rows";
|
|
160
|
+
"required": true;
|
|
161
|
+
"isSignal": true;
|
|
162
|
+
};
|
|
163
|
+
"conf": {
|
|
164
|
+
"alias": "conf";
|
|
165
|
+
"required": true;
|
|
166
|
+
"isSignal": true;
|
|
167
|
+
};
|
|
168
|
+
"total": {
|
|
169
|
+
"alias": "total";
|
|
170
|
+
"required": false;
|
|
171
|
+
"isSignal": true;
|
|
172
|
+
};
|
|
173
|
+
"rowsToAppend": {
|
|
174
|
+
"alias": "rowsToAppend";
|
|
175
|
+
"required": false;
|
|
176
|
+
"isSignal": true;
|
|
177
|
+
};
|
|
178
|
+
"loading": {
|
|
179
|
+
"alias": "loading";
|
|
180
|
+
"required": false;
|
|
181
|
+
"isSignal": true;
|
|
182
|
+
};
|
|
183
|
+
"failed": {
|
|
184
|
+
"alias": "failed";
|
|
185
|
+
"required": false;
|
|
186
|
+
"isSignal": true;
|
|
187
|
+
};
|
|
188
|
+
"filter": {
|
|
189
|
+
"alias": "filter";
|
|
190
|
+
"required": false;
|
|
191
|
+
"isSignal": true;
|
|
192
|
+
};
|
|
193
|
+
"emptyState": {
|
|
194
|
+
"alias": "emptyState";
|
|
195
|
+
"required": false;
|
|
196
|
+
"isSignal": true;
|
|
197
|
+
};
|
|
198
|
+
"tableId": {
|
|
199
|
+
"alias": "tableId";
|
|
200
|
+
"required": false;
|
|
201
|
+
"isSignal": true;
|
|
202
|
+
};
|
|
203
|
+
"theme": {
|
|
204
|
+
"alias": "theme";
|
|
205
|
+
"required": false;
|
|
206
|
+
"isSignal": true;
|
|
207
|
+
};
|
|
208
|
+
}, {
|
|
209
|
+
"action": "action";
|
|
210
|
+
"query": "query";
|
|
211
|
+
}, never, never, true, never>;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Service contract responsible for translating between the table domain model
|
|
215
|
+
* and a specific backend API.
|
|
216
|
+
*
|
|
217
|
+
* BroService defines how:
|
|
218
|
+
* - a generic BroQuery (pagination, sorting, filtering) is transformed into
|
|
219
|
+
* an API-specific request format
|
|
220
|
+
* - an API-specific response is mapped back into a normalized BroServerPage
|
|
221
|
+
*
|
|
222
|
+
* This abstraction allows the table component and its containers to remain
|
|
223
|
+
* backend-agnostic, while each integration provides its own mapping logic.
|
|
224
|
+
*
|
|
225
|
+
*/
|
|
226
|
+
export interface BroService<MODEL extends object, API_QUERY = unknown, API_PAGE = unknown, EXTRA extends object = object> {
|
|
227
|
+
mapServerQuery: (query: BroQuery<MODEL, EXTRA>) => API_QUERY;
|
|
228
|
+
mapServerResponse: (response: API_PAGE) => BroServerPage<MODEL>;
|
|
229
|
+
}
|
|
230
|
+
export interface BroServerPage<MODEL extends object> {
|
|
231
|
+
rows: MODEL[];
|
|
232
|
+
total: number;
|
|
233
|
+
}
|