juxscript 1.1.163 → 1.1.165
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/index.d.ts +3 -0
- package/index.d.ts.map +1 -1
- package/index.js +3 -0
- package/lib/components/dataframe.d.ts +110 -0
- package/lib/components/dataframe.d.ts.map +1 -0
- package/lib/components/dataframe.js +292 -0
- package/lib/components/dataframe.ts +363 -0
- package/lib/components/table.d.ts +2 -2
- package/lib/components/table.d.ts.map +1 -1
- package/lib/components/table.ts +5 -6
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { dialog } from './lib/components/dialog.js';
|
|
|
13
13
|
import { divider } from './lib/components/divider.js';
|
|
14
14
|
import { dropdown } from './lib/components/dropdown.js';
|
|
15
15
|
import { dropdownMenu } from './lib/components/dropdown-menu.js';
|
|
16
|
+
import { dataframe } from './lib/components/dataframe.js';
|
|
16
17
|
import { element } from './lib/components/element.js';
|
|
17
18
|
import { fileupload } from './lib/components/fileupload.js';
|
|
18
19
|
import { grid } from './lib/components/grid.js';
|
|
@@ -53,6 +54,7 @@ export { tabularDriver } from './lib/storage/TabularDriver.js';
|
|
|
53
54
|
export { DataFrame } from './lib/storage/DataFrame.js';
|
|
54
55
|
export { indexedDBDriver } from './lib/storage/IndexedDBDriver.js';
|
|
55
56
|
export { fileStorage } from './lib/storage/FileStorage.js';
|
|
57
|
+
export { dataframe } from './lib/components/dataframe.js';
|
|
56
58
|
import { VStack, vstack } from './lib/components/stack/VStack.js';
|
|
57
59
|
import { HStack, hstack } from './lib/components/stack/HStack.js';
|
|
58
60
|
import { ZStack, zstack } from './lib/components/stack/ZStack.js';
|
|
@@ -73,6 +75,7 @@ export declare const jux: {
|
|
|
73
75
|
code: typeof code;
|
|
74
76
|
container: typeof container;
|
|
75
77
|
data: typeof data;
|
|
78
|
+
dataframe: typeof dataframe;
|
|
76
79
|
datepicker: typeof datepicker;
|
|
77
80
|
dialog: typeof dialog;
|
|
78
81
|
divider: typeof divider;
|
package/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}
|
package/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import { dialog } from './lib/components/dialog.js';
|
|
|
13
13
|
import { divider } from './lib/components/divider.js';
|
|
14
14
|
import { dropdown } from './lib/components/dropdown.js';
|
|
15
15
|
import { dropdownMenu } from './lib/components/dropdown-menu.js';
|
|
16
|
+
import { dataframe } from './lib/components/dataframe.js';
|
|
16
17
|
import { element } from './lib/components/element.js';
|
|
17
18
|
import { fileupload } from './lib/components/fileupload.js';
|
|
18
19
|
import { grid } from './lib/components/grid.js';
|
|
@@ -56,6 +57,7 @@ export { tabularDriver } from './lib/storage/TabularDriver.js';
|
|
|
56
57
|
export { DataFrame } from './lib/storage/DataFrame.js';
|
|
57
58
|
export { indexedDBDriver } from './lib/storage/IndexedDBDriver.js';
|
|
58
59
|
export { fileStorage } from './lib/storage/FileStorage.js';
|
|
60
|
+
export { dataframe } from './lib/components/dataframe.js';
|
|
59
61
|
// Import Stack components (already added earlier)
|
|
60
62
|
import { VStack, vstack } from './lib/components/stack/VStack.js';
|
|
61
63
|
import { HStack, hstack } from './lib/components/stack/HStack.js';
|
|
@@ -79,6 +81,7 @@ export const jux = {
|
|
|
79
81
|
code,
|
|
80
82
|
container,
|
|
81
83
|
data,
|
|
84
|
+
dataframe,
|
|
82
85
|
datepicker,
|
|
83
86
|
dialog,
|
|
84
87
|
divider,
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { BaseComponent, BaseState } from './base/BaseComponent.js';
|
|
2
|
+
import { DataFrame } from '../storage/DataFrame.js';
|
|
3
|
+
import { TabularDriver } from '../storage/TabularDriver.js';
|
|
4
|
+
import { FileUpload } from './fileupload.js';
|
|
5
|
+
import { Table } from './table.js';
|
|
6
|
+
export interface DataFrameOptions {
|
|
7
|
+
dbName?: string;
|
|
8
|
+
storeName?: string;
|
|
9
|
+
striped?: boolean;
|
|
10
|
+
hoverable?: boolean;
|
|
11
|
+
sortable?: boolean;
|
|
12
|
+
filterable?: boolean;
|
|
13
|
+
paginated?: boolean;
|
|
14
|
+
rowsPerPage?: number;
|
|
15
|
+
style?: string;
|
|
16
|
+
class?: string;
|
|
17
|
+
}
|
|
18
|
+
type DataFrameState = BaseState & {
|
|
19
|
+
loaded: boolean;
|
|
20
|
+
sourceName: string;
|
|
21
|
+
rowCount: number;
|
|
22
|
+
colCount: number;
|
|
23
|
+
};
|
|
24
|
+
export declare class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
25
|
+
private _df;
|
|
26
|
+
private _driver;
|
|
27
|
+
private _table;
|
|
28
|
+
private _tableOptions;
|
|
29
|
+
private _uploadRef;
|
|
30
|
+
private _storageKey;
|
|
31
|
+
private _pendingSource;
|
|
32
|
+
constructor(id: string, options?: DataFrameOptions);
|
|
33
|
+
protected getTriggerEvents(): readonly string[];
|
|
34
|
+
protected getCallbackEvents(): readonly string[];
|
|
35
|
+
/**
|
|
36
|
+
* Load from IndexedDB by storage key
|
|
37
|
+
*/
|
|
38
|
+
fromStorage(key: string): this;
|
|
39
|
+
/**
|
|
40
|
+
* Load from a FileUpload component — auto-wires change event
|
|
41
|
+
*/
|
|
42
|
+
fromUpload(upload: FileUpload): this;
|
|
43
|
+
/**
|
|
44
|
+
* Load from raw data — array of objects or Record<string, any[]>
|
|
45
|
+
*/
|
|
46
|
+
fromData(data: Record<string, any>[] | Record<string, any[]>): this;
|
|
47
|
+
/**
|
|
48
|
+
* Apply a transform to the current DataFrame and update the table
|
|
49
|
+
*/
|
|
50
|
+
apply(fn: (df: DataFrame) => DataFrame): this;
|
|
51
|
+
/**
|
|
52
|
+
* Filter rows
|
|
53
|
+
*/
|
|
54
|
+
filter(predicate: (row: Record<string, any>, index: number) => boolean): this;
|
|
55
|
+
/**
|
|
56
|
+
* Select columns
|
|
57
|
+
*/
|
|
58
|
+
select(...cols: string[]): this;
|
|
59
|
+
/**
|
|
60
|
+
* Sort by column
|
|
61
|
+
*/
|
|
62
|
+
sort(col: string, descending?: boolean): this;
|
|
63
|
+
/**
|
|
64
|
+
* Show first N rows
|
|
65
|
+
*/
|
|
66
|
+
head(n?: number): this;
|
|
67
|
+
/**
|
|
68
|
+
* Show last N rows
|
|
69
|
+
*/
|
|
70
|
+
tail(n?: number): this;
|
|
71
|
+
/**
|
|
72
|
+
* Add a computed column
|
|
73
|
+
*/
|
|
74
|
+
withColumn(name: string, fn: (row: Record<string, any>, index: number) => any): this;
|
|
75
|
+
/**
|
|
76
|
+
* Where clause
|
|
77
|
+
*/
|
|
78
|
+
where(col: string, op: '==' | '!=' | '>' | '<' | '>=' | '<=' | 'contains' | 'startsWith' | 'endsWith', value: any): this;
|
|
79
|
+
/** Get the underlying DataFrame */
|
|
80
|
+
get df(): DataFrame | null;
|
|
81
|
+
/** Get the underlying TabularDriver */
|
|
82
|
+
get driver(): TabularDriver;
|
|
83
|
+
/** Get the internal Table component */
|
|
84
|
+
get table(): Table | null;
|
|
85
|
+
/** Get describe() stats */
|
|
86
|
+
describe(): Record<string, any> | null;
|
|
87
|
+
/** Export to CSV string */
|
|
88
|
+
toCSV(delimiter?: string): string;
|
|
89
|
+
/** Export to row objects */
|
|
90
|
+
toRows(): Record<string, any>[];
|
|
91
|
+
/** Get shape */
|
|
92
|
+
get shape(): [number, number];
|
|
93
|
+
/** Get column names */
|
|
94
|
+
get columns(): string[];
|
|
95
|
+
/** Save current DataFrame to IndexedDB */
|
|
96
|
+
save(key?: string): Promise<string | null>;
|
|
97
|
+
striped(v: boolean): this;
|
|
98
|
+
hoverable(v: boolean): this;
|
|
99
|
+
sortable(v: boolean): this;
|
|
100
|
+
filterable(v: boolean): this;
|
|
101
|
+
paginated(v: boolean): this;
|
|
102
|
+
rowsPerPage(v: number): this;
|
|
103
|
+
private _setDataFrame;
|
|
104
|
+
private _updateTable;
|
|
105
|
+
update(prop: string, value: any): void;
|
|
106
|
+
render(targetId?: string | HTMLElement | BaseComponent<any>): this;
|
|
107
|
+
}
|
|
108
|
+
export declare function dataframe(id: string, options?: DataFrameOptions): DataFrameComponent;
|
|
109
|
+
export {};
|
|
110
|
+
//# sourceMappingURL=dataframe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataframe.d.ts","sourceRoot":"","sources":["dataframe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { BaseComponent } from './base/BaseComponent.js';
|
|
2
|
+
import { DataFrame } from '../storage/DataFrame.js';
|
|
3
|
+
import { TabularDriver } from '../storage/TabularDriver.js';
|
|
4
|
+
import { Table } from './table.js';
|
|
5
|
+
const TRIGGER_EVENTS = [];
|
|
6
|
+
const CALLBACK_EVENTS = ['load', 'error', 'transform'];
|
|
7
|
+
export class DataFrameComponent extends BaseComponent {
|
|
8
|
+
constructor(id, options = {}) {
|
|
9
|
+
super(id, {
|
|
10
|
+
visible: true,
|
|
11
|
+
disabled: false,
|
|
12
|
+
loading: false,
|
|
13
|
+
style: options.style ?? '',
|
|
14
|
+
class: options.class ?? '',
|
|
15
|
+
loaded: false,
|
|
16
|
+
sourceName: '',
|
|
17
|
+
rowCount: 0,
|
|
18
|
+
colCount: 0
|
|
19
|
+
});
|
|
20
|
+
this._df = null;
|
|
21
|
+
this._table = null;
|
|
22
|
+
this._uploadRef = null;
|
|
23
|
+
this._storageKey = null;
|
|
24
|
+
this._pendingSource = null;
|
|
25
|
+
this._driver = new TabularDriver(options.dbName ?? 'jux-dataframes', options.storeName ?? 'frames');
|
|
26
|
+
this._tableOptions = {
|
|
27
|
+
striped: options.striped ?? true,
|
|
28
|
+
hoverable: options.hoverable ?? true,
|
|
29
|
+
sortable: options.sortable ?? true,
|
|
30
|
+
filterable: options.filterable ?? true,
|
|
31
|
+
paginated: options.paginated ?? true,
|
|
32
|
+
rowsPerPage: options.rowsPerPage ?? 25
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
getTriggerEvents() { return TRIGGER_EVENTS; }
|
|
36
|
+
getCallbackEvents() { return CALLBACK_EVENTS; }
|
|
37
|
+
/* ═══════════════════════════════════════════════════
|
|
38
|
+
* DATA SOURCES
|
|
39
|
+
* ═══════════════════════════════════════════════════ */
|
|
40
|
+
/**
|
|
41
|
+
* Load from IndexedDB by storage key
|
|
42
|
+
*/
|
|
43
|
+
fromStorage(key) {
|
|
44
|
+
this._storageKey = key;
|
|
45
|
+
this._pendingSource = async () => {
|
|
46
|
+
this.state.loading = true;
|
|
47
|
+
try {
|
|
48
|
+
let df = await this._driver.loadByName(key);
|
|
49
|
+
if (!df) {
|
|
50
|
+
this._triggerCallback('error', 'No table found with key: ' + key, null, this);
|
|
51
|
+
this.state.loading = false;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
this._setDataFrame(df, 'storage: ' + key);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
this._triggerCallback('error', err.message, null, this);
|
|
58
|
+
this.state.loading = false;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
return this;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Load from a FileUpload component — auto-wires change event
|
|
65
|
+
*/
|
|
66
|
+
fromUpload(upload) {
|
|
67
|
+
this._uploadRef = upload;
|
|
68
|
+
this._pendingSource = async () => {
|
|
69
|
+
// Wire upload's change event to parse incoming files
|
|
70
|
+
upload.bind('change', async (files) => {
|
|
71
|
+
if (!files || files.length === 0)
|
|
72
|
+
return;
|
|
73
|
+
const file = files[0];
|
|
74
|
+
this.state.loading = true;
|
|
75
|
+
try {
|
|
76
|
+
const df = await this._driver.streamFile(file);
|
|
77
|
+
// Auto-persist to IndexedDB
|
|
78
|
+
await this._driver.store(file.name, df, { source: file.name });
|
|
79
|
+
this._setDataFrame(df, 'upload: ' + file.name);
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
this._triggerCallback('error', err.message, null, this);
|
|
83
|
+
this.state.loading = false;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Load from raw data — array of objects or Record<string, any[]>
|
|
91
|
+
*/
|
|
92
|
+
fromData(data) {
|
|
93
|
+
this._pendingSource = async () => {
|
|
94
|
+
this.state.loading = true;
|
|
95
|
+
try {
|
|
96
|
+
const df = new DataFrame(data);
|
|
97
|
+
this._setDataFrame(df, 'inline data');
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
this._triggerCallback('error', err.message, null, this);
|
|
101
|
+
this.state.loading = false;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
return this;
|
|
105
|
+
}
|
|
106
|
+
/* ═══════════════════════════════════════════════════
|
|
107
|
+
* TRANSFORM API (returns new DataFrameComponent view)
|
|
108
|
+
* ═══════════════════════════════════════════════════ */
|
|
109
|
+
/**
|
|
110
|
+
* Apply a transform to the current DataFrame and update the table
|
|
111
|
+
*/
|
|
112
|
+
apply(fn) {
|
|
113
|
+
if (!this._df)
|
|
114
|
+
return this;
|
|
115
|
+
const result = fn(this._df);
|
|
116
|
+
this._setDataFrame(result, this.state.sourceName + ' (transformed)');
|
|
117
|
+
this._triggerCallback('transform', result, null, this);
|
|
118
|
+
return this;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Filter rows
|
|
122
|
+
*/
|
|
123
|
+
filter(predicate) {
|
|
124
|
+
return this.apply(df => df.filter(predicate));
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Select columns
|
|
128
|
+
*/
|
|
129
|
+
select(...cols) {
|
|
130
|
+
return this.apply(df => df.select(...cols));
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Sort by column
|
|
134
|
+
*/
|
|
135
|
+
sort(col, descending) {
|
|
136
|
+
return this.apply(df => df.sort(col, descending));
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Show first N rows
|
|
140
|
+
*/
|
|
141
|
+
head(n = 5) {
|
|
142
|
+
return this.apply(df => df.head(n));
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Show last N rows
|
|
146
|
+
*/
|
|
147
|
+
tail(n = 5) {
|
|
148
|
+
return this.apply(df => df.tail(n));
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Add a computed column
|
|
152
|
+
*/
|
|
153
|
+
withColumn(name, fn) {
|
|
154
|
+
return this.apply(df => df.withColumn(name, fn));
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Where clause
|
|
158
|
+
*/
|
|
159
|
+
where(col, op, value) {
|
|
160
|
+
return this.apply(df => df.where(col, op, value));
|
|
161
|
+
}
|
|
162
|
+
/* ═══════════════════════════════════════════════════
|
|
163
|
+
* ACCESSORS
|
|
164
|
+
* ═══════════════════════════════════════════════════ */
|
|
165
|
+
/** Get the underlying DataFrame */
|
|
166
|
+
get df() { return this._df; }
|
|
167
|
+
/** Get the underlying TabularDriver */
|
|
168
|
+
get driver() { return this._driver; }
|
|
169
|
+
/** Get the internal Table component */
|
|
170
|
+
get table() { return this._table; }
|
|
171
|
+
/** Get describe() stats */
|
|
172
|
+
describe() {
|
|
173
|
+
return this._df?.describe() ?? null;
|
|
174
|
+
}
|
|
175
|
+
/** Export to CSV string */
|
|
176
|
+
toCSV(delimiter) {
|
|
177
|
+
return this._df?.toCSV(delimiter) ?? '';
|
|
178
|
+
}
|
|
179
|
+
/** Export to row objects */
|
|
180
|
+
toRows() {
|
|
181
|
+
return this._df?.toRows() ?? [];
|
|
182
|
+
}
|
|
183
|
+
/** Get shape */
|
|
184
|
+
get shape() {
|
|
185
|
+
return this._df?.shape ?? [0, 0];
|
|
186
|
+
}
|
|
187
|
+
/** Get column names */
|
|
188
|
+
get columns() {
|
|
189
|
+
return this._df?.columns ?? [];
|
|
190
|
+
}
|
|
191
|
+
/** Save current DataFrame to IndexedDB */
|
|
192
|
+
async save(key) {
|
|
193
|
+
if (!this._df)
|
|
194
|
+
return null;
|
|
195
|
+
const name = key ?? this._storageKey ?? this._id;
|
|
196
|
+
return this._driver.store(name, this._df);
|
|
197
|
+
}
|
|
198
|
+
/* ═══════════════════════════════════════════════════
|
|
199
|
+
* TABLE OPTIONS (fluent, pre-render)
|
|
200
|
+
* ═══════════════════════════════════════════════════ */
|
|
201
|
+
striped(v) { this._tableOptions.striped = v; return this; }
|
|
202
|
+
hoverable(v) { this._tableOptions.hoverable = v; return this; }
|
|
203
|
+
sortable(v) { this._tableOptions.sortable = v; return this; }
|
|
204
|
+
filterable(v) { this._tableOptions.filterable = v; return this; }
|
|
205
|
+
paginated(v) { this._tableOptions.paginated = v; return this; }
|
|
206
|
+
rowsPerPage(v) { this._tableOptions.rowsPerPage = v; return this; }
|
|
207
|
+
/* ═══════════════════════════════════════════════════
|
|
208
|
+
* INTERNAL
|
|
209
|
+
* ═══════════════════════════════════════════════════ */
|
|
210
|
+
_setDataFrame(df, sourceName) {
|
|
211
|
+
this._df = df;
|
|
212
|
+
this.state.loaded = true;
|
|
213
|
+
this.state.loading = false;
|
|
214
|
+
this.state.sourceName = sourceName;
|
|
215
|
+
this.state.rowCount = df.height;
|
|
216
|
+
this.state.colCount = df.width;
|
|
217
|
+
// Clean __EMPTY columns from xlsx artifacts
|
|
218
|
+
const cleanCols = df.columns.filter(c => !c.startsWith('__EMPTY'));
|
|
219
|
+
if (cleanCols.length < df.columns.length) {
|
|
220
|
+
this._df = df.select(...cleanCols);
|
|
221
|
+
}
|
|
222
|
+
this._updateTable();
|
|
223
|
+
this._triggerCallback('load', this._df, null, this);
|
|
224
|
+
}
|
|
225
|
+
_updateTable() {
|
|
226
|
+
if (!this._table || !this._df)
|
|
227
|
+
return;
|
|
228
|
+
this._table.columns(this._df.columns).rows(this._df.toRows());
|
|
229
|
+
}
|
|
230
|
+
update(prop, value) { }
|
|
231
|
+
/* ═══════════════════════════════════════════════════
|
|
232
|
+
* RENDER
|
|
233
|
+
* ═══════════════════════════════════════════════════ */
|
|
234
|
+
render(targetId) {
|
|
235
|
+
const container = this._setupContainer(targetId);
|
|
236
|
+
const { style, class: className } = this.state;
|
|
237
|
+
const wrapper = document.createElement('div');
|
|
238
|
+
wrapper.className = 'jux-dataframe';
|
|
239
|
+
wrapper.id = this._id;
|
|
240
|
+
if (className)
|
|
241
|
+
wrapper.className += ` ${className}`;
|
|
242
|
+
if (style)
|
|
243
|
+
wrapper.setAttribute('style', style);
|
|
244
|
+
// Status bar
|
|
245
|
+
const statusBar = document.createElement('div');
|
|
246
|
+
statusBar.className = 'jux-dataframe-status';
|
|
247
|
+
statusBar.id = `${this._id}-status`;
|
|
248
|
+
statusBar.style.cssText = 'font-size:13px;color:#888;margin-bottom:8px;';
|
|
249
|
+
statusBar.textContent = 'No data loaded.';
|
|
250
|
+
wrapper.appendChild(statusBar);
|
|
251
|
+
container.appendChild(wrapper);
|
|
252
|
+
// Create internal table
|
|
253
|
+
this._table = new Table(`${this._id}-table`, {
|
|
254
|
+
striped: this._tableOptions.striped,
|
|
255
|
+
hoverable: this._tableOptions.hoverable,
|
|
256
|
+
sortable: this._tableOptions.sortable,
|
|
257
|
+
filterable: this._tableOptions.filterable,
|
|
258
|
+
paginated: this._tableOptions.paginated,
|
|
259
|
+
rowsPerPage: this._tableOptions.rowsPerPage
|
|
260
|
+
});
|
|
261
|
+
this._table.render(wrapper);
|
|
262
|
+
// Watch state for status updates
|
|
263
|
+
const origUpdate = this.update.bind(this);
|
|
264
|
+
this.update = (prop, value) => {
|
|
265
|
+
origUpdate(prop, value);
|
|
266
|
+
if (prop === 'loaded' || prop === 'loading' || prop === 'rowCount' || prop === 'colCount' || prop === 'sourceName') {
|
|
267
|
+
const el = document.getElementById(`${this._id}-status`);
|
|
268
|
+
if (el) {
|
|
269
|
+
if (this.state.loading) {
|
|
270
|
+
el.textContent = '⏳ Loading...';
|
|
271
|
+
}
|
|
272
|
+
else if (this.state.loaded) {
|
|
273
|
+
el.textContent = `✅ ${this.state.sourceName} — ${this.state.rowCount} rows × ${this.state.colCount} cols`;
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
el.textContent = 'No data loaded.';
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
// Execute pending data source
|
|
282
|
+
if (this._pendingSource) {
|
|
283
|
+
this._pendingSource();
|
|
284
|
+
this._pendingSource = null;
|
|
285
|
+
}
|
|
286
|
+
this._wireStandardEvents(wrapper);
|
|
287
|
+
return this;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
export function dataframe(id, options = {}) {
|
|
291
|
+
return new DataFrameComponent(id, options);
|
|
292
|
+
}
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import { BaseComponent, BaseState } from './base/BaseComponent.js';
|
|
2
|
+
import { DataFrame } from '../storage/DataFrame.js';
|
|
3
|
+
import { TabularDriver } from '../storage/TabularDriver.js';
|
|
4
|
+
import { FileUpload } from './fileupload.js';
|
|
5
|
+
import { Table } from './table.js';
|
|
6
|
+
|
|
7
|
+
const TRIGGER_EVENTS = [] as const;
|
|
8
|
+
const CALLBACK_EVENTS = ['load', 'error', 'transform'] as const;
|
|
9
|
+
|
|
10
|
+
export interface DataFrameOptions {
|
|
11
|
+
dbName?: string;
|
|
12
|
+
storeName?: string;
|
|
13
|
+
striped?: boolean;
|
|
14
|
+
hoverable?: boolean;
|
|
15
|
+
sortable?: boolean;
|
|
16
|
+
filterable?: boolean;
|
|
17
|
+
paginated?: boolean;
|
|
18
|
+
rowsPerPage?: number;
|
|
19
|
+
style?: string;
|
|
20
|
+
class?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type DataFrameState = BaseState & {
|
|
24
|
+
loaded: boolean;
|
|
25
|
+
sourceName: string;
|
|
26
|
+
rowCount: number;
|
|
27
|
+
colCount: number;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
31
|
+
private _df: DataFrame | null = null;
|
|
32
|
+
private _driver: TabularDriver;
|
|
33
|
+
private _table: Table | null = null;
|
|
34
|
+
private _tableOptions: {
|
|
35
|
+
striped: boolean;
|
|
36
|
+
hoverable: boolean;
|
|
37
|
+
sortable: boolean;
|
|
38
|
+
filterable: boolean;
|
|
39
|
+
paginated: boolean;
|
|
40
|
+
rowsPerPage: number;
|
|
41
|
+
};
|
|
42
|
+
private _uploadRef: FileUpload | null = null;
|
|
43
|
+
private _storageKey: string | null = null;
|
|
44
|
+
private _pendingSource: (() => Promise<void>) | null = null;
|
|
45
|
+
|
|
46
|
+
constructor(id: string, options: DataFrameOptions = {}) {
|
|
47
|
+
super(id, {
|
|
48
|
+
visible: true,
|
|
49
|
+
disabled: false,
|
|
50
|
+
loading: false,
|
|
51
|
+
style: options.style ?? '',
|
|
52
|
+
class: options.class ?? '',
|
|
53
|
+
loaded: false,
|
|
54
|
+
sourceName: '',
|
|
55
|
+
rowCount: 0,
|
|
56
|
+
colCount: 0
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
this._driver = new TabularDriver(
|
|
60
|
+
options.dbName ?? 'jux-dataframes',
|
|
61
|
+
options.storeName ?? 'frames'
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
this._tableOptions = {
|
|
65
|
+
striped: options.striped ?? true,
|
|
66
|
+
hoverable: options.hoverable ?? true,
|
|
67
|
+
sortable: options.sortable ?? true,
|
|
68
|
+
filterable: options.filterable ?? true,
|
|
69
|
+
paginated: options.paginated ?? true,
|
|
70
|
+
rowsPerPage: options.rowsPerPage ?? 25
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
protected getTriggerEvents(): readonly string[] { return TRIGGER_EVENTS; }
|
|
75
|
+
protected getCallbackEvents(): readonly string[] { return CALLBACK_EVENTS; }
|
|
76
|
+
|
|
77
|
+
/* ═══════════════════════════════════════════════════
|
|
78
|
+
* DATA SOURCES
|
|
79
|
+
* ═══════════════════════════════════════════════════ */
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Load from IndexedDB by storage key
|
|
83
|
+
*/
|
|
84
|
+
fromStorage(key: string): this {
|
|
85
|
+
this._storageKey = key;
|
|
86
|
+
this._pendingSource = async () => {
|
|
87
|
+
this.state.loading = true;
|
|
88
|
+
try {
|
|
89
|
+
let df = await this._driver.loadByName(key);
|
|
90
|
+
if (!df) {
|
|
91
|
+
this._triggerCallback('error', 'No table found with key: ' + key, null, this);
|
|
92
|
+
this.state.loading = false;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
this._setDataFrame(df, 'storage: ' + key);
|
|
96
|
+
} catch (err: any) {
|
|
97
|
+
this._triggerCallback('error', err.message, null, this);
|
|
98
|
+
this.state.loading = false;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
return this;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Load from a FileUpload component — auto-wires change event
|
|
106
|
+
*/
|
|
107
|
+
fromUpload(upload: FileUpload): this {
|
|
108
|
+
this._uploadRef = upload;
|
|
109
|
+
this._pendingSource = async () => {
|
|
110
|
+
// Wire upload's change event to parse incoming files
|
|
111
|
+
upload.bind('change', async (files: File[]) => {
|
|
112
|
+
if (!files || files.length === 0) return;
|
|
113
|
+
const file = files[0];
|
|
114
|
+
this.state.loading = true;
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
const df = await this._driver.streamFile(file);
|
|
118
|
+
// Auto-persist to IndexedDB
|
|
119
|
+
await this._driver.store(file.name, df, { source: file.name });
|
|
120
|
+
this._setDataFrame(df, 'upload: ' + file.name);
|
|
121
|
+
} catch (err: any) {
|
|
122
|
+
this._triggerCallback('error', err.message, null, this);
|
|
123
|
+
this.state.loading = false;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
return this;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Load from raw data — array of objects or Record<string, any[]>
|
|
132
|
+
*/
|
|
133
|
+
fromData(data: Record<string, any>[] | Record<string, any[]>): this {
|
|
134
|
+
this._pendingSource = async () => {
|
|
135
|
+
this.state.loading = true;
|
|
136
|
+
try {
|
|
137
|
+
const df = new DataFrame(data);
|
|
138
|
+
this._setDataFrame(df, 'inline data');
|
|
139
|
+
} catch (err: any) {
|
|
140
|
+
this._triggerCallback('error', err.message, null, this);
|
|
141
|
+
this.state.loading = false;
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
return this;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/* ═══════════════════════════════════════════════════
|
|
148
|
+
* TRANSFORM API (returns new DataFrameComponent view)
|
|
149
|
+
* ═══════════════════════════════════════════════════ */
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Apply a transform to the current DataFrame and update the table
|
|
153
|
+
*/
|
|
154
|
+
apply(fn: (df: DataFrame) => DataFrame): this {
|
|
155
|
+
if (!this._df) return this;
|
|
156
|
+
const result = fn(this._df);
|
|
157
|
+
this._setDataFrame(result, this.state.sourceName + ' (transformed)');
|
|
158
|
+
this._triggerCallback('transform', result, null, this);
|
|
159
|
+
return this;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Filter rows
|
|
164
|
+
*/
|
|
165
|
+
filter(predicate: (row: Record<string, any>, index: number) => boolean): this {
|
|
166
|
+
return this.apply(df => df.filter(predicate));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Select columns
|
|
171
|
+
*/
|
|
172
|
+
select(...cols: string[]): this {
|
|
173
|
+
return this.apply(df => df.select(...cols));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Sort by column
|
|
178
|
+
*/
|
|
179
|
+
sort(col: string, descending?: boolean): this {
|
|
180
|
+
return this.apply(df => df.sort(col, descending));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Show first N rows
|
|
185
|
+
*/
|
|
186
|
+
head(n: number = 5): this {
|
|
187
|
+
return this.apply(df => df.head(n));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Show last N rows
|
|
192
|
+
*/
|
|
193
|
+
tail(n: number = 5): this {
|
|
194
|
+
return this.apply(df => df.tail(n));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Add a computed column
|
|
199
|
+
*/
|
|
200
|
+
withColumn(name: string, fn: (row: Record<string, any>, index: number) => any): this {
|
|
201
|
+
return this.apply(df => df.withColumn(name, fn));
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Where clause
|
|
206
|
+
*/
|
|
207
|
+
where(col: string, op: '==' | '!=' | '>' | '<' | '>=' | '<=' | 'contains' | 'startsWith' | 'endsWith', value: any): this {
|
|
208
|
+
return this.apply(df => df.where(col, op, value));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/* ═══════════════════════════════════════════════════
|
|
212
|
+
* ACCESSORS
|
|
213
|
+
* ═══════════════════════════════════════════════════ */
|
|
214
|
+
|
|
215
|
+
/** Get the underlying DataFrame */
|
|
216
|
+
get df(): DataFrame | null { return this._df; }
|
|
217
|
+
|
|
218
|
+
/** Get the underlying TabularDriver */
|
|
219
|
+
get driver(): TabularDriver { return this._driver; }
|
|
220
|
+
|
|
221
|
+
/** Get the internal Table component */
|
|
222
|
+
get table(): Table | null { return this._table; }
|
|
223
|
+
|
|
224
|
+
/** Get describe() stats */
|
|
225
|
+
describe(): Record<string, any> | null {
|
|
226
|
+
return this._df?.describe() ?? null;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Export to CSV string */
|
|
230
|
+
toCSV(delimiter?: string): string {
|
|
231
|
+
return this._df?.toCSV(delimiter) ?? '';
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** Export to row objects */
|
|
235
|
+
toRows(): Record<string, any>[] {
|
|
236
|
+
return this._df?.toRows() ?? [];
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** Get shape */
|
|
240
|
+
get shape(): [number, number] {
|
|
241
|
+
return this._df?.shape ?? [0, 0];
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** Get column names */
|
|
245
|
+
get columns(): string[] {
|
|
246
|
+
return this._df?.columns ?? [];
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/** Save current DataFrame to IndexedDB */
|
|
250
|
+
async save(key?: string): Promise<string | null> {
|
|
251
|
+
if (!this._df) return null;
|
|
252
|
+
const name = key ?? this._storageKey ?? this._id;
|
|
253
|
+
return this._driver.store(name, this._df);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/* ═══════════════════════════════════════════════════
|
|
257
|
+
* TABLE OPTIONS (fluent, pre-render)
|
|
258
|
+
* ═══════════════════════════════════════════════════ */
|
|
259
|
+
|
|
260
|
+
striped(v: boolean): this { this._tableOptions.striped = v; return this; }
|
|
261
|
+
hoverable(v: boolean): this { this._tableOptions.hoverable = v; return this; }
|
|
262
|
+
sortable(v: boolean): this { this._tableOptions.sortable = v; return this; }
|
|
263
|
+
filterable(v: boolean): this { this._tableOptions.filterable = v; return this; }
|
|
264
|
+
paginated(v: boolean): this { this._tableOptions.paginated = v; return this; }
|
|
265
|
+
rowsPerPage(v: number): this { this._tableOptions.rowsPerPage = v; return this; }
|
|
266
|
+
|
|
267
|
+
/* ═══════════════════════════════════════════════════
|
|
268
|
+
* INTERNAL
|
|
269
|
+
* ═══════════════════════════════════════════════════ */
|
|
270
|
+
|
|
271
|
+
private _setDataFrame(df: DataFrame, sourceName: string): void {
|
|
272
|
+
this._df = df;
|
|
273
|
+
this.state.loaded = true;
|
|
274
|
+
this.state.loading = false;
|
|
275
|
+
this.state.sourceName = sourceName;
|
|
276
|
+
this.state.rowCount = df.height;
|
|
277
|
+
this.state.colCount = df.width;
|
|
278
|
+
|
|
279
|
+
// Clean __EMPTY columns from xlsx artifacts
|
|
280
|
+
const cleanCols = df.columns.filter(c => !c.startsWith('__EMPTY'));
|
|
281
|
+
if (cleanCols.length < df.columns.length) {
|
|
282
|
+
this._df = df.select(...cleanCols);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
this._updateTable();
|
|
286
|
+
this._triggerCallback('load', this._df, null, this);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
private _updateTable(): void {
|
|
290
|
+
if (!this._table || !this._df) return;
|
|
291
|
+
this._table.columns(this._df.columns).rows(this._df.toRows());
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
update(prop: string, value: any): void { }
|
|
295
|
+
|
|
296
|
+
/* ═══════════════════════════════════════════════════
|
|
297
|
+
* RENDER
|
|
298
|
+
* ═══════════════════════════════════════════════════ */
|
|
299
|
+
|
|
300
|
+
render(targetId?: string | HTMLElement | BaseComponent<any>): this {
|
|
301
|
+
const container = this._setupContainer(targetId);
|
|
302
|
+
const { style, class: className } = this.state;
|
|
303
|
+
|
|
304
|
+
const wrapper = document.createElement('div');
|
|
305
|
+
wrapper.className = 'jux-dataframe';
|
|
306
|
+
wrapper.id = this._id;
|
|
307
|
+
if (className) wrapper.className += ` ${className}`;
|
|
308
|
+
if (style) wrapper.setAttribute('style', style);
|
|
309
|
+
|
|
310
|
+
// Status bar
|
|
311
|
+
const statusBar = document.createElement('div');
|
|
312
|
+
statusBar.className = 'jux-dataframe-status';
|
|
313
|
+
statusBar.id = `${this._id}-status`;
|
|
314
|
+
statusBar.style.cssText = 'font-size:13px;color:#888;margin-bottom:8px;';
|
|
315
|
+
statusBar.textContent = 'No data loaded.';
|
|
316
|
+
wrapper.appendChild(statusBar);
|
|
317
|
+
|
|
318
|
+
container.appendChild(wrapper);
|
|
319
|
+
|
|
320
|
+
// Create internal table
|
|
321
|
+
this._table = new Table(`${this._id}-table`, {
|
|
322
|
+
striped: this._tableOptions.striped,
|
|
323
|
+
hoverable: this._tableOptions.hoverable,
|
|
324
|
+
sortable: this._tableOptions.sortable,
|
|
325
|
+
filterable: this._tableOptions.filterable,
|
|
326
|
+
paginated: this._tableOptions.paginated,
|
|
327
|
+
rowsPerPage: this._tableOptions.rowsPerPage
|
|
328
|
+
});
|
|
329
|
+
this._table.render(wrapper);
|
|
330
|
+
|
|
331
|
+
// Watch state for status updates
|
|
332
|
+
const origUpdate = this.update.bind(this);
|
|
333
|
+
this.update = (prop: string, value: any) => {
|
|
334
|
+
origUpdate(prop, value);
|
|
335
|
+
if (prop === 'loaded' || prop === 'loading' || prop === 'rowCount' || prop === 'colCount' || prop === 'sourceName') {
|
|
336
|
+
const el = document.getElementById(`${this._id}-status`);
|
|
337
|
+
if (el) {
|
|
338
|
+
if (this.state.loading) {
|
|
339
|
+
el.textContent = '⏳ Loading...';
|
|
340
|
+
} else if (this.state.loaded) {
|
|
341
|
+
el.textContent = `✅ ${this.state.sourceName} — ${this.state.rowCount} rows × ${this.state.colCount} cols`;
|
|
342
|
+
} else {
|
|
343
|
+
el.textContent = 'No data loaded.';
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
// Execute pending data source
|
|
350
|
+
if (this._pendingSource) {
|
|
351
|
+
this._pendingSource();
|
|
352
|
+
this._pendingSource = null;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
this._wireStandardEvents(wrapper);
|
|
356
|
+
|
|
357
|
+
return this;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export function dataframe(id: string, options: DataFrameOptions = {}): DataFrameComponent {
|
|
362
|
+
return new DataFrameComponent(id, options);
|
|
363
|
+
}
|
|
@@ -39,7 +39,7 @@ export interface TableOptions {
|
|
|
39
39
|
}
|
|
40
40
|
type TableState = {
|
|
41
41
|
columns: ColumnDef[];
|
|
42
|
-
rows: any[]
|
|
42
|
+
rows: any[];
|
|
43
43
|
computedColumns: Map<string, ComputedColumnDef>;
|
|
44
44
|
headers: boolean;
|
|
45
45
|
striped: boolean;
|
|
@@ -71,7 +71,7 @@ export declare class Table extends BaseComponent<TableState> {
|
|
|
71
71
|
protected getTriggerEvents(): readonly string[];
|
|
72
72
|
protected getCallbackEvents(): readonly string[];
|
|
73
73
|
columns(value: (string | ColumnDef)[]): this;
|
|
74
|
-
rows(value: any[]
|
|
74
|
+
rows(value: any[]): this;
|
|
75
75
|
/**
|
|
76
76
|
* Add a computed column that evaluates dynamically at render time
|
|
77
77
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.d.ts","sourceRoot":"","sources":["table.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAiBxD,MAAM,MAAM,6BAA6B,GAAG,OAAO,GAAG,UAAU,CAAC;AACjE,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,UAAU,CAAC;AAElD,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK,MAAM,GAAG,WAAW,CAAC;IAExD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAGD,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,KAAK,GAAG,CAAC;IAC7C,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,GAAG,WAAW,CAAC;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,CAAC;IACjC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,6BAA6B,CAAC;CACnD;AAED,KAAK,UAAU,GAAG;IAChB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,IAAI,EAAE,GAAG,EAAE,
|
|
1
|
+
{"version":3,"file":"table.d.ts","sourceRoot":"","sources":["table.ts"],"names":[],"mappings":"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"}
|
package/lib/components/table.ts
CHANGED
|
@@ -66,8 +66,7 @@ export interface TableOptions {
|
|
|
66
66
|
|
|
67
67
|
type TableState = {
|
|
68
68
|
columns: ColumnDef[];
|
|
69
|
-
rows: any[]
|
|
70
|
-
// ✨ NEW: Store computed column definitions
|
|
69
|
+
rows: any[];
|
|
71
70
|
computedColumns: Map<string, ComputedColumnDef>;
|
|
72
71
|
headers: boolean;
|
|
73
72
|
striped: boolean;
|
|
@@ -164,7 +163,7 @@ export class Table extends BaseComponent<TableState> {
|
|
|
164
163
|
return this;
|
|
165
164
|
}
|
|
166
165
|
|
|
167
|
-
rows(value: any[]
|
|
166
|
+
rows(value: any[]): this {
|
|
168
167
|
const previousRows = this.state.rows;
|
|
169
168
|
const hadSelections = this.state.selectedIndexes.size > 0;
|
|
170
169
|
|
|
@@ -949,7 +948,7 @@ export class Table extends BaseComponent<TableState> {
|
|
|
949
948
|
* ═════════════════════════════════════════════════════════════════ */
|
|
950
949
|
|
|
951
950
|
// Data processing
|
|
952
|
-
private _getFilteredRows(): any[]
|
|
951
|
+
private _getFilteredRows(): any[] {
|
|
953
952
|
if (!this.state.filterText) return this.state.rows;
|
|
954
953
|
const searchText = this.state.filterText.toLowerCase();
|
|
955
954
|
return this.state.rows.filter(row => {
|
|
@@ -960,7 +959,7 @@ export class Table extends BaseComponent<TableState> {
|
|
|
960
959
|
});
|
|
961
960
|
}
|
|
962
961
|
|
|
963
|
-
private _getSortedRows(rows: any[]
|
|
962
|
+
private _getSortedRows(rows: any[]): any[] {
|
|
964
963
|
if (!this.state.sortColumn) return rows;
|
|
965
964
|
|
|
966
965
|
// ✨ Check if sorting by computed column
|
|
@@ -994,7 +993,7 @@ export class Table extends BaseComponent<TableState> {
|
|
|
994
993
|
return sorted;
|
|
995
994
|
}
|
|
996
995
|
|
|
997
|
-
private _getPaginatedRows(rows: any[]
|
|
996
|
+
private _getPaginatedRows(rows: any[]): any[] {
|
|
998
997
|
if (!this.state.paginated) return rows;
|
|
999
998
|
const start = (this.state.currentPage - 1) * this.state.rowsPerPage;
|
|
1000
999
|
const end = start + this.state.rowsPerPage;
|