juxscript 1.1.163 → 1.1.166

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 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":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAElD,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAElD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,0CAA0C,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAEtD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;AAGzC,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAG3D,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAGlE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7E,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAG5D,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAG3D;;GAEG;AACH,eAAO,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2Df,CAAC;AAGF,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC"}
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,120 @@
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
+ private _inlineUpload;
33
+ constructor(id: string, options?: DataFrameOptions);
34
+ protected getTriggerEvents(): readonly string[];
35
+ protected getCallbackEvents(): readonly string[];
36
+ /**
37
+ * Load from IndexedDB by storage key
38
+ */
39
+ fromStorage(key: string): this;
40
+ /**
41
+ * Load from a FileUpload component — auto-wires change event
42
+ */
43
+ fromUpload(upload: FileUpload): this;
44
+ /**
45
+ * Load from raw data — array of objects or Record<string, any[]>
46
+ */
47
+ fromData(data: Record<string, any>[] | Record<string, any[]>): this;
48
+ /**
49
+ * Add an inline file upload control above the table.
50
+ * Auto-wires parsing, storage, and display — zero callbacks needed.
51
+ *
52
+ * @param label - Button/label text (default: 'Upload File')
53
+ * @param accept - File types (default: '.csv,.tsv,.txt,.xlsx,.xls')
54
+ */
55
+ withUpload(label?: string, accept?: string): this;
56
+ /**
57
+ * Apply a transform to the current DataFrame and update the table
58
+ */
59
+ apply(fn: (df: DataFrame) => DataFrame): this;
60
+ /**
61
+ * Filter rows
62
+ */
63
+ filter(predicate: (row: Record<string, any>, index: number) => boolean): this;
64
+ /**
65
+ * Select columns
66
+ */
67
+ select(...cols: string[]): this;
68
+ /**
69
+ * Sort by column
70
+ */
71
+ sort(col: string, descending?: boolean): this;
72
+ /**
73
+ * Show first N rows
74
+ */
75
+ head(n?: number): this;
76
+ /**
77
+ * Show last N rows
78
+ */
79
+ tail(n?: number): this;
80
+ /**
81
+ * Add a computed column
82
+ */
83
+ withColumn(name: string, fn: (row: Record<string, any>, index: number) => any): this;
84
+ /**
85
+ * Where clause
86
+ */
87
+ where(col: string, op: '==' | '!=' | '>' | '<' | '>=' | '<=' | 'contains' | 'startsWith' | 'endsWith', value: any): this;
88
+ /** Get the underlying DataFrame */
89
+ get df(): DataFrame | null;
90
+ /** Get the underlying TabularDriver */
91
+ get driver(): TabularDriver;
92
+ /** Get the internal Table component */
93
+ get table(): Table | null;
94
+ /** Get describe() stats */
95
+ describe(): Record<string, any> | null;
96
+ /** Export to CSV string */
97
+ toCSV(delimiter?: string): string;
98
+ /** Export to row objects */
99
+ toRows(): Record<string, any>[];
100
+ /** Get shape */
101
+ get shape(): [number, number];
102
+ /** Get column names */
103
+ get columns(): string[];
104
+ /** Save current DataFrame to IndexedDB */
105
+ save(key?: string): Promise<string | null>;
106
+ striped(v: boolean): this;
107
+ hoverable(v: boolean): this;
108
+ sortable(v: boolean): this;
109
+ filterable(v: boolean): this;
110
+ paginated(v: boolean): this;
111
+ rowsPerPage(v: number): this;
112
+ private _updateStatus;
113
+ private _setDataFrame;
114
+ private _updateTable;
115
+ update(prop: string, value: any): void;
116
+ render(targetId?: string | HTMLElement | BaseComponent<any>): this;
117
+ }
118
+ export declare function dataframe(id: string, options?: DataFrameOptions): DataFrameComponent;
119
+ export {};
120
+ //# 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,330 @@
1
+ import { BaseComponent } 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
+ const TRIGGER_EVENTS = [];
7
+ const CALLBACK_EVENTS = ['load', 'error', 'transform'];
8
+ export class DataFrameComponent extends BaseComponent {
9
+ constructor(id, options = {}) {
10
+ super(id, {
11
+ visible: true,
12
+ disabled: false,
13
+ loading: false,
14
+ style: options.style ?? '',
15
+ class: options.class ?? '',
16
+ loaded: false,
17
+ sourceName: '',
18
+ rowCount: 0,
19
+ colCount: 0
20
+ });
21
+ this._df = null;
22
+ this._table = null;
23
+ this._uploadRef = null;
24
+ this._storageKey = null;
25
+ this._pendingSource = null;
26
+ this._inlineUpload = null;
27
+ this._driver = new TabularDriver(options.dbName ?? 'jux-dataframes', options.storeName ?? 'frames');
28
+ this._tableOptions = {
29
+ striped: options.striped ?? true,
30
+ hoverable: options.hoverable ?? true,
31
+ sortable: options.sortable ?? true,
32
+ filterable: options.filterable ?? true,
33
+ paginated: options.paginated ?? true,
34
+ rowsPerPage: options.rowsPerPage ?? 25
35
+ };
36
+ }
37
+ getTriggerEvents() { return TRIGGER_EVENTS; }
38
+ getCallbackEvents() { return CALLBACK_EVENTS; }
39
+ /* ═══════════════════════════════════════════════════
40
+ * DATA SOURCES
41
+ * ═══════════════════════════════════════════════════ */
42
+ /**
43
+ * Load from IndexedDB by storage key
44
+ */
45
+ fromStorage(key) {
46
+ this._storageKey = key;
47
+ this._pendingSource = async () => {
48
+ this.state.loading = true;
49
+ try {
50
+ let df = await this._driver.loadByName(key);
51
+ if (!df) {
52
+ this._triggerCallback('error', 'No table found with key: ' + key, null, this);
53
+ this.state.loading = false;
54
+ return;
55
+ }
56
+ this._setDataFrame(df, 'storage: ' + key);
57
+ }
58
+ catch (err) {
59
+ this._triggerCallback('error', err.message, null, this);
60
+ this.state.loading = false;
61
+ }
62
+ };
63
+ return this;
64
+ }
65
+ /**
66
+ * Load from a FileUpload component — auto-wires change event
67
+ */
68
+ fromUpload(upload) {
69
+ this._uploadRef = upload;
70
+ this._pendingSource = async () => {
71
+ // Wire upload's change event to parse incoming files
72
+ upload.bind('change', async (files) => {
73
+ if (!files || files.length === 0)
74
+ return;
75
+ const file = files[0];
76
+ this.state.loading = true;
77
+ try {
78
+ const df = await this._driver.streamFile(file);
79
+ // Auto-persist to IndexedDB
80
+ await this._driver.store(file.name, df, { source: file.name });
81
+ this._setDataFrame(df, 'upload: ' + file.name);
82
+ }
83
+ catch (err) {
84
+ this._triggerCallback('error', err.message, null, this);
85
+ this.state.loading = false;
86
+ }
87
+ });
88
+ };
89
+ return this;
90
+ }
91
+ /**
92
+ * Load from raw data — array of objects or Record<string, any[]>
93
+ */
94
+ fromData(data) {
95
+ this._pendingSource = async () => {
96
+ this.state.loading = true;
97
+ try {
98
+ const df = new DataFrame(data);
99
+ this._setDataFrame(df, 'inline data');
100
+ }
101
+ catch (err) {
102
+ this._triggerCallback('error', err.message, null, this);
103
+ this.state.loading = false;
104
+ }
105
+ };
106
+ return this;
107
+ }
108
+ /**
109
+ * Add an inline file upload control above the table.
110
+ * Auto-wires parsing, storage, and display — zero callbacks needed.
111
+ *
112
+ * @param label - Button/label text (default: 'Upload File')
113
+ * @param accept - File types (default: '.csv,.tsv,.txt,.xlsx,.xls')
114
+ */
115
+ withUpload(label = 'Upload File', accept = '.csv,.tsv,.txt,.xlsx,.xls') {
116
+ this._inlineUpload = { label, accept };
117
+ return this;
118
+ }
119
+ /* ═══════════════════════════════════════════════════
120
+ * TRANSFORM API (returns new DataFrameComponent view)
121
+ * ═══════════════════════════════════════════════════ */
122
+ /**
123
+ * Apply a transform to the current DataFrame and update the table
124
+ */
125
+ apply(fn) {
126
+ if (!this._df)
127
+ return this;
128
+ const result = fn(this._df);
129
+ this._setDataFrame(result, this.state.sourceName + ' (transformed)');
130
+ this._triggerCallback('transform', result, null, this);
131
+ return this;
132
+ }
133
+ /**
134
+ * Filter rows
135
+ */
136
+ filter(predicate) {
137
+ return this.apply(df => df.filter(predicate));
138
+ }
139
+ /**
140
+ * Select columns
141
+ */
142
+ select(...cols) {
143
+ return this.apply(df => df.select(...cols));
144
+ }
145
+ /**
146
+ * Sort by column
147
+ */
148
+ sort(col, descending) {
149
+ return this.apply(df => df.sort(col, descending));
150
+ }
151
+ /**
152
+ * Show first N rows
153
+ */
154
+ head(n = 5) {
155
+ return this.apply(df => df.head(n));
156
+ }
157
+ /**
158
+ * Show last N rows
159
+ */
160
+ tail(n = 5) {
161
+ return this.apply(df => df.tail(n));
162
+ }
163
+ /**
164
+ * Add a computed column
165
+ */
166
+ withColumn(name, fn) {
167
+ return this.apply(df => df.withColumn(name, fn));
168
+ }
169
+ /**
170
+ * Where clause
171
+ */
172
+ where(col, op, value) {
173
+ return this.apply(df => df.where(col, op, value));
174
+ }
175
+ /* ═══════════════════════════════════════════════════
176
+ * ACCESSORS
177
+ * ═══════════════════════════════════════════════════ */
178
+ /** Get the underlying DataFrame */
179
+ get df() { return this._df; }
180
+ /** Get the underlying TabularDriver */
181
+ get driver() { return this._driver; }
182
+ /** Get the internal Table component */
183
+ get table() { return this._table; }
184
+ /** Get describe() stats */
185
+ describe() {
186
+ return this._df?.describe() ?? null;
187
+ }
188
+ /** Export to CSV string */
189
+ toCSV(delimiter) {
190
+ return this._df?.toCSV(delimiter) ?? '';
191
+ }
192
+ /** Export to row objects */
193
+ toRows() {
194
+ return this._df?.toRows() ?? [];
195
+ }
196
+ /** Get shape */
197
+ get shape() {
198
+ return this._df?.shape ?? [0, 0];
199
+ }
200
+ /** Get column names */
201
+ get columns() {
202
+ return this._df?.columns ?? [];
203
+ }
204
+ /** Save current DataFrame to IndexedDB */
205
+ async save(key) {
206
+ if (!this._df)
207
+ return null;
208
+ const name = key ?? this._storageKey ?? this._id;
209
+ return this._driver.store(name, this._df);
210
+ }
211
+ /* ═══════════════════════════════════════════════════
212
+ * TABLE OPTIONS (fluent, pre-render)
213
+ * ═══════════════════════════════════════════════════ */
214
+ striped(v) { this._tableOptions.striped = v; return this; }
215
+ hoverable(v) { this._tableOptions.hoverable = v; return this; }
216
+ sortable(v) { this._tableOptions.sortable = v; return this; }
217
+ filterable(v) { this._tableOptions.filterable = v; return this; }
218
+ paginated(v) { this._tableOptions.paginated = v; return this; }
219
+ rowsPerPage(v) { this._tableOptions.rowsPerPage = v; return this; }
220
+ /* ═══════════════════════════════════════════════════
221
+ * INTERNAL
222
+ * ═══════════════════════════════════════════════════ */
223
+ _updateStatus(text) {
224
+ const el = document.getElementById(`${this._id}-status`);
225
+ if (el)
226
+ el.textContent = text;
227
+ }
228
+ _setDataFrame(df, sourceName) {
229
+ this._df = df;
230
+ this.state.loaded = true;
231
+ this.state.loading = false;
232
+ this.state.sourceName = sourceName;
233
+ this.state.rowCount = df.height;
234
+ this.state.colCount = df.width;
235
+ const cleanCols = df.columns.filter(c => !c.startsWith('__EMPTY'));
236
+ if (cleanCols.length < df.columns.length) {
237
+ this._df = df.select(...cleanCols);
238
+ }
239
+ this._updateTable();
240
+ this._updateStatus(`✅ ${sourceName} — ${this._df.height} rows × ${this._df.width} cols`);
241
+ this._triggerCallback('load', this._df, null, this);
242
+ }
243
+ _updateTable() {
244
+ if (!this._table || !this._df)
245
+ return;
246
+ this._table.columns(this._df.columns).rows(this._df.toRows());
247
+ }
248
+ update(prop, value) { }
249
+ /* ═══════════════════════════════════════════════════
250
+ * RENDER
251
+ * ═══════════════════════════════════════════════════ */
252
+ render(targetId) {
253
+ const container = this._setupContainer(targetId);
254
+ const { style, class: className } = this.state;
255
+ const wrapper = document.createElement('div');
256
+ wrapper.className = 'jux-dataframe';
257
+ wrapper.id = this._id;
258
+ if (className)
259
+ wrapper.className += ` ${className}`;
260
+ if (style)
261
+ wrapper.setAttribute('style', style);
262
+ // Inline upload (if withUpload was called)
263
+ if (this._inlineUpload) {
264
+ const upload = new FileUpload(`${this._id}-upload`, {
265
+ label: this._inlineUpload.label,
266
+ accept: this._inlineUpload.accept
267
+ });
268
+ // Wire it as a fromUpload source
269
+ this._uploadRef = upload;
270
+ this._pendingSource = async () => {
271
+ upload.bind('change', async (files) => {
272
+ if (!files || files.length === 0)
273
+ return;
274
+ const file = files[0];
275
+ this.state.loading = true;
276
+ this._updateStatus('⏳ Parsing ' + file.name + '...');
277
+ try {
278
+ const df = await this._driver.streamFile(file);
279
+ await this._driver.store(file.name, df, { source: file.name });
280
+ this._setDataFrame(df, file.name);
281
+ }
282
+ catch (err) {
283
+ this._triggerCallback('error', err.message, null, this);
284
+ this.state.loading = false;
285
+ this._updateStatus('❌ ' + err.message);
286
+ }
287
+ });
288
+ };
289
+ // Render upload into wrapper before status/table
290
+ const uploadContainer = document.createElement('div');
291
+ uploadContainer.className = 'jux-dataframe-upload';
292
+ uploadContainer.id = `${this._id}-upload-container`;
293
+ wrapper.appendChild(uploadContainer);
294
+ container.appendChild(wrapper);
295
+ upload.render(uploadContainer);
296
+ }
297
+ else {
298
+ container.appendChild(wrapper);
299
+ }
300
+ // Status bar
301
+ const statusBar = document.createElement('div');
302
+ statusBar.className = 'jux-dataframe-status';
303
+ statusBar.id = `${this._id}-status`;
304
+ statusBar.style.cssText = 'font-size:13px;color:#888;margin-bottom:8px;';
305
+ statusBar.textContent = 'No data loaded.';
306
+ wrapper.appendChild(statusBar);
307
+ // Create internal table
308
+ const tbl = new Table(`${this._id}-table`, {
309
+ striped: this._tableOptions.striped,
310
+ hoverable: this._tableOptions.hoverable,
311
+ sortable: this._tableOptions.sortable,
312
+ filterable: this._tableOptions.filterable,
313
+ paginated: this._tableOptions.paginated,
314
+ rowsPerPage: this._tableOptions.rowsPerPage
315
+ });
316
+ tbl.render(wrapper);
317
+ this._table = tbl;
318
+ // Execute pending data source
319
+ if (this._pendingSource) {
320
+ const fn = this._pendingSource;
321
+ this._pendingSource = null;
322
+ fn();
323
+ }
324
+ this._wireStandardEvents(wrapper);
325
+ return this;
326
+ }
327
+ }
328
+ export function dataframe(id, options = {}) {
329
+ return new DataFrameComponent(id, options);
330
+ }
@@ -0,0 +1,402 @@
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
+ private _inlineUpload: { label: string; accept: string } | null = null;
46
+
47
+ constructor(id: string, options: DataFrameOptions = {}) {
48
+ super(id, {
49
+ visible: true,
50
+ disabled: false,
51
+ loading: false,
52
+ style: options.style ?? '',
53
+ class: options.class ?? '',
54
+ loaded: false,
55
+ sourceName: '',
56
+ rowCount: 0,
57
+ colCount: 0
58
+ });
59
+
60
+ this._driver = new TabularDriver(
61
+ options.dbName ?? 'jux-dataframes',
62
+ options.storeName ?? 'frames'
63
+ );
64
+
65
+ this._tableOptions = {
66
+ striped: options.striped ?? true,
67
+ hoverable: options.hoverable ?? true,
68
+ sortable: options.sortable ?? true,
69
+ filterable: options.filterable ?? true,
70
+ paginated: options.paginated ?? true,
71
+ rowsPerPage: options.rowsPerPage ?? 25
72
+ };
73
+ }
74
+
75
+ protected getTriggerEvents(): readonly string[] { return TRIGGER_EVENTS; }
76
+ protected getCallbackEvents(): readonly string[] { return CALLBACK_EVENTS; }
77
+
78
+ /* ═══════════════════════════════════════════════════
79
+ * DATA SOURCES
80
+ * ═══════════════════════════════════════════════════ */
81
+
82
+ /**
83
+ * Load from IndexedDB by storage key
84
+ */
85
+ fromStorage(key: string): this {
86
+ this._storageKey = key;
87
+ this._pendingSource = async () => {
88
+ this.state.loading = true;
89
+ try {
90
+ let df = await this._driver.loadByName(key);
91
+ if (!df) {
92
+ this._triggerCallback('error', 'No table found with key: ' + key, null, this);
93
+ this.state.loading = false;
94
+ return;
95
+ }
96
+ this._setDataFrame(df, 'storage: ' + key);
97
+ } catch (err: any) {
98
+ this._triggerCallback('error', err.message, null, this);
99
+ this.state.loading = false;
100
+ }
101
+ };
102
+ return this;
103
+ }
104
+
105
+ /**
106
+ * Load from a FileUpload component — auto-wires change event
107
+ */
108
+ fromUpload(upload: FileUpload): this {
109
+ this._uploadRef = upload;
110
+ this._pendingSource = async () => {
111
+ // Wire upload's change event to parse incoming files
112
+ upload.bind('change', async (files: File[]) => {
113
+ if (!files || files.length === 0) return;
114
+ const file = files[0];
115
+ this.state.loading = true;
116
+
117
+ try {
118
+ const df = await this._driver.streamFile(file);
119
+ // Auto-persist to IndexedDB
120
+ await this._driver.store(file.name, df, { source: file.name });
121
+ this._setDataFrame(df, 'upload: ' + file.name);
122
+ } catch (err: any) {
123
+ this._triggerCallback('error', err.message, null, this);
124
+ this.state.loading = false;
125
+ }
126
+ });
127
+ };
128
+ return this;
129
+ }
130
+
131
+ /**
132
+ * Load from raw data — array of objects or Record<string, any[]>
133
+ */
134
+ fromData(data: Record<string, any>[] | Record<string, any[]>): this {
135
+ this._pendingSource = async () => {
136
+ this.state.loading = true;
137
+ try {
138
+ const df = new DataFrame(data);
139
+ this._setDataFrame(df, 'inline data');
140
+ } catch (err: any) {
141
+ this._triggerCallback('error', err.message, null, this);
142
+ this.state.loading = false;
143
+ }
144
+ };
145
+ return this;
146
+ }
147
+
148
+ /**
149
+ * Add an inline file upload control above the table.
150
+ * Auto-wires parsing, storage, and display — zero callbacks needed.
151
+ *
152
+ * @param label - Button/label text (default: 'Upload File')
153
+ * @param accept - File types (default: '.csv,.tsv,.txt,.xlsx,.xls')
154
+ */
155
+ withUpload(label: string = 'Upload File', accept: string = '.csv,.tsv,.txt,.xlsx,.xls'): this {
156
+ this._inlineUpload = { label, accept };
157
+ return this;
158
+ }
159
+
160
+ /* ═══════════════════════════════════════════════════
161
+ * TRANSFORM API (returns new DataFrameComponent view)
162
+ * ═══════════════════════════════════════════════════ */
163
+
164
+ /**
165
+ * Apply a transform to the current DataFrame and update the table
166
+ */
167
+ apply(fn: (df: DataFrame) => DataFrame): this {
168
+ if (!this._df) return this;
169
+ const result = fn(this._df);
170
+ this._setDataFrame(result, this.state.sourceName + ' (transformed)');
171
+ this._triggerCallback('transform', result, null, this);
172
+ return this;
173
+ }
174
+
175
+ /**
176
+ * Filter rows
177
+ */
178
+ filter(predicate: (row: Record<string, any>, index: number) => boolean): this {
179
+ return this.apply(df => df.filter(predicate));
180
+ }
181
+
182
+ /**
183
+ * Select columns
184
+ */
185
+ select(...cols: string[]): this {
186
+ return this.apply(df => df.select(...cols));
187
+ }
188
+
189
+ /**
190
+ * Sort by column
191
+ */
192
+ sort(col: string, descending?: boolean): this {
193
+ return this.apply(df => df.sort(col, descending));
194
+ }
195
+
196
+ /**
197
+ * Show first N rows
198
+ */
199
+ head(n: number = 5): this {
200
+ return this.apply(df => df.head(n));
201
+ }
202
+
203
+ /**
204
+ * Show last N rows
205
+ */
206
+ tail(n: number = 5): this {
207
+ return this.apply(df => df.tail(n));
208
+ }
209
+
210
+ /**
211
+ * Add a computed column
212
+ */
213
+ withColumn(name: string, fn: (row: Record<string, any>, index: number) => any): this {
214
+ return this.apply(df => df.withColumn(name, fn));
215
+ }
216
+
217
+ /**
218
+ * Where clause
219
+ */
220
+ where(col: string, op: '==' | '!=' | '>' | '<' | '>=' | '<=' | 'contains' | 'startsWith' | 'endsWith', value: any): this {
221
+ return this.apply(df => df.where(col, op, value));
222
+ }
223
+
224
+ /* ═══════════════════════════════════════════════════
225
+ * ACCESSORS
226
+ * ═══════════════════════════════════════════════════ */
227
+
228
+ /** Get the underlying DataFrame */
229
+ get df(): DataFrame | null { return this._df; }
230
+
231
+ /** Get the underlying TabularDriver */
232
+ get driver(): TabularDriver { return this._driver; }
233
+
234
+ /** Get the internal Table component */
235
+ get table(): Table | null { return this._table; }
236
+
237
+ /** Get describe() stats */
238
+ describe(): Record<string, any> | null {
239
+ return this._df?.describe() ?? null;
240
+ }
241
+
242
+ /** Export to CSV string */
243
+ toCSV(delimiter?: string): string {
244
+ return this._df?.toCSV(delimiter) ?? '';
245
+ }
246
+
247
+ /** Export to row objects */
248
+ toRows(): Record<string, any>[] {
249
+ return this._df?.toRows() ?? [];
250
+ }
251
+
252
+ /** Get shape */
253
+ get shape(): [number, number] {
254
+ return this._df?.shape ?? [0, 0];
255
+ }
256
+
257
+ /** Get column names */
258
+ get columns(): string[] {
259
+ return this._df?.columns ?? [];
260
+ }
261
+
262
+ /** Save current DataFrame to IndexedDB */
263
+ async save(key?: string): Promise<string | null> {
264
+ if (!this._df) return null;
265
+ const name = key ?? this._storageKey ?? this._id;
266
+ return this._driver.store(name, this._df);
267
+ }
268
+
269
+ /* ═══════════════════════════════════════════════════
270
+ * TABLE OPTIONS (fluent, pre-render)
271
+ * ═══════════════════════════════════════════════════ */
272
+
273
+ striped(v: boolean): this { this._tableOptions.striped = v; return this; }
274
+ hoverable(v: boolean): this { this._tableOptions.hoverable = v; return this; }
275
+ sortable(v: boolean): this { this._tableOptions.sortable = v; return this; }
276
+ filterable(v: boolean): this { this._tableOptions.filterable = v; return this; }
277
+ paginated(v: boolean): this { this._tableOptions.paginated = v; return this; }
278
+ rowsPerPage(v: number): this { this._tableOptions.rowsPerPage = v; return this; }
279
+
280
+ /* ═══════════════════════════════════════════════════
281
+ * INTERNAL
282
+ * ═══════════════════════════════════════════════════ */
283
+
284
+ private _updateStatus(text: string): void {
285
+ const el = document.getElementById(`${this._id}-status`);
286
+ if (el) el.textContent = text;
287
+ }
288
+
289
+ private _setDataFrame(df: DataFrame, sourceName: string): void {
290
+ this._df = df;
291
+ this.state.loaded = true;
292
+ this.state.loading = false;
293
+ this.state.sourceName = sourceName;
294
+ this.state.rowCount = df.height;
295
+ this.state.colCount = df.width;
296
+
297
+ const cleanCols = df.columns.filter(c => !c.startsWith('__EMPTY'));
298
+ if (cleanCols.length < df.columns.length) {
299
+ this._df = df.select(...cleanCols);
300
+ }
301
+
302
+ this._updateTable();
303
+ this._updateStatus(`✅ ${sourceName} — ${this._df!.height} rows × ${this._df!.width} cols`);
304
+ this._triggerCallback('load', this._df, null, this);
305
+ }
306
+
307
+ private _updateTable(): void {
308
+ if (!this._table || !this._df) return;
309
+ this._table.columns(this._df.columns).rows(this._df.toRows());
310
+ }
311
+
312
+ update(prop: string, value: any): void { }
313
+
314
+ /* ═══════════════════════════════════════════════════
315
+ * RENDER
316
+ * ═══════════════════════════════════════════════════ */
317
+
318
+ render(targetId?: string | HTMLElement | BaseComponent<any>): this {
319
+ const container = this._setupContainer(targetId);
320
+ const { style, class: className } = this.state;
321
+
322
+ const wrapper = document.createElement('div');
323
+ wrapper.className = 'jux-dataframe';
324
+ wrapper.id = this._id;
325
+ if (className) wrapper.className += ` ${className}`;
326
+ if (style) wrapper.setAttribute('style', style);
327
+
328
+ // Inline upload (if withUpload was called)
329
+ if (this._inlineUpload) {
330
+ const upload = new FileUpload(`${this._id}-upload`, {
331
+ label: this._inlineUpload.label,
332
+ accept: this._inlineUpload.accept
333
+ });
334
+
335
+ // Wire it as a fromUpload source
336
+ this._uploadRef = upload;
337
+ this._pendingSource = async () => {
338
+ upload.bind('change', async (files: File[]) => {
339
+ if (!files || files.length === 0) return;
340
+ const file = files[0];
341
+ this.state.loading = true;
342
+ this._updateStatus('⏳ Parsing ' + file.name + '...');
343
+
344
+ try {
345
+ const df = await this._driver.streamFile(file);
346
+ await this._driver.store(file.name, df, { source: file.name });
347
+ this._setDataFrame(df, file.name);
348
+ } catch (err: any) {
349
+ this._triggerCallback('error', err.message, null, this);
350
+ this.state.loading = false;
351
+ this._updateStatus('❌ ' + err.message);
352
+ }
353
+ });
354
+ };
355
+
356
+ // Render upload into wrapper before status/table
357
+ const uploadContainer = document.createElement('div');
358
+ uploadContainer.className = 'jux-dataframe-upload';
359
+ uploadContainer.id = `${this._id}-upload-container`;
360
+ wrapper.appendChild(uploadContainer);
361
+ container.appendChild(wrapper);
362
+ upload.render(uploadContainer);
363
+ } else {
364
+ container.appendChild(wrapper);
365
+ }
366
+
367
+ // Status bar
368
+ const statusBar = document.createElement('div');
369
+ statusBar.className = 'jux-dataframe-status';
370
+ statusBar.id = `${this._id}-status`;
371
+ statusBar.style.cssText = 'font-size:13px;color:#888;margin-bottom:8px;';
372
+ statusBar.textContent = 'No data loaded.';
373
+ wrapper.appendChild(statusBar);
374
+
375
+ // Create internal table
376
+ const tbl = new Table(`${this._id}-table`, {
377
+ striped: this._tableOptions.striped,
378
+ hoverable: this._tableOptions.hoverable,
379
+ sortable: this._tableOptions.sortable,
380
+ filterable: this._tableOptions.filterable,
381
+ paginated: this._tableOptions.paginated,
382
+ rowsPerPage: this._tableOptions.rowsPerPage
383
+ });
384
+ tbl.render(wrapper);
385
+ this._table = tbl;
386
+
387
+ // Execute pending data source
388
+ if (this._pendingSource) {
389
+ const fn = this._pendingSource;
390
+ this._pendingSource = null;
391
+ fn();
392
+ }
393
+
394
+ this._wireStandardEvents(wrapper);
395
+
396
+ return this;
397
+ }
398
+ }
399
+
400
+ export function dataframe(id: string, options: DataFrameOptions = {}): DataFrameComponent {
401
+ return new DataFrameComponent(id, options);
402
+ }
@@ -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[][]): this;
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":"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"}
1
+ {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["table.ts"],"names":[],"mappings":"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"}
@@ -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[][]): this {
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[][]): 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[][]): 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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.1.163",
3
+ "version": "1.1.166",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "index.js",