juxscript 1.1.225 → 1.1.227

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.
@@ -64,6 +64,7 @@ export declare class DataFrameComponent extends BaseComponent<DataFrameState> {
64
64
  private _collapsed;
65
65
  private _summaryTemplate;
66
66
  private _detailsElement;
67
+ private _settingsModal;
67
68
  constructor(id: string, options?: DataFrameOptions);
68
69
  protected getTriggerEvents(): readonly string[];
69
70
  protected getCallbackEvents(): readonly string[];
@@ -172,7 +173,23 @@ export declare class DataFrameComponent extends BaseComponent<DataFrameState> {
172
173
  private _updateStatus;
173
174
  private _setDataFrame;
174
175
  /**
175
- * Update the collapsible summary text and add settings button
176
+ * Show the data view (table + settings gear), hide upload area
177
+ */
178
+ private _showDataView;
179
+ /**
180
+ * Hide data view, show upload area
181
+ */
182
+ private _hideDataView;
183
+ /**
184
+ * Update the settings gear tooltip/info
185
+ */
186
+ private _updateSettingsGear;
187
+ /**
188
+ * Show the unified settings modal
189
+ */
190
+ private _showSettingsModal;
191
+ /**
192
+ * Update the collapsible summary text
176
193
  */
177
194
  private _updateSummary;
178
195
  private _appendSettingsButton;
@@ -1 +1 @@
1
- {"version":3,"file":"dataframe.d.ts","sourceRoot":"","sources":["dataframe.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dataframe.d.ts","sourceRoot":"","sources":["dataframe.ts"],"names":[],"mappings":"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"}
@@ -52,6 +52,7 @@ export class DataFrameComponent extends BaseComponent {
52
52
  this._collapsed = false;
53
53
  this._summaryTemplate = null;
54
54
  this._detailsElement = null;
55
+ this._settingsModal = null;
55
56
  this._driver = new TabularDriver(options.dbName ?? 'jux-dataframes', options.storeName ?? 'frames');
56
57
  this._showStatus = options.showStatus ?? true;
57
58
  this._icon = options.icon ?? '';
@@ -253,17 +254,15 @@ export class DataFrameComponent extends BaseComponent {
253
254
  if (existingTabs)
254
255
  existingTabs.remove();
255
256
  }
256
- // ✅ Hide details element when cleared
257
+ // ✅ Hide data view, show upload
258
+ this._hideDataView();
259
+ // ✅ Hide collapsible details
257
260
  if (this._collapsible && this._detailsElement) {
258
261
  this._detailsElement.style.display = 'none';
259
262
  }
260
- // ✅ Hide status when cleared (for inline upload mode)
261
- const statusEl = document.getElementById(`${this._id}-status`);
262
- if (statusEl && this._inlineUpload) {
263
- statusEl.style.display = 'none';
264
- }
265
- else if (statusEl) {
266
- this._updateStatus('No data loaded.', 'empty');
263
+ // ✅ Clear file from upload component
264
+ if (this._uploadRef) {
265
+ this._uploadRef.clear();
267
266
  }
268
267
  return this;
269
268
  }
@@ -543,23 +542,28 @@ export class DataFrameComponent extends BaseComponent {
543
542
  const el = document.getElementById(`${this._id}-status`);
544
543
  if (!el)
545
544
  return;
546
- // Always show status (inline with upload button)
547
- el.style.display = '';
548
- el.className = 'jux-dataframe-status';
549
- if (type)
545
+ // Only show status during loading/error states
546
+ if (type === 'loading' || type === 'error') {
547
+ el.style.display = '';
548
+ el.className = 'jux-dataframe-status';
550
549
  el.classList.add(`jux-dataframe-status-${type}`);
551
- el.innerHTML = '';
552
- if (this._icon && (type === 'success' || type === 'warning')) {
553
- const iconEl = renderIcon(this._icon);
554
- iconEl.style.width = '16px';
555
- iconEl.style.height = '16px';
556
- iconEl.style.marginRight = '6px';
557
- iconEl.style.verticalAlign = 'middle';
558
- el.appendChild(iconEl);
550
+ el.innerHTML = '';
551
+ if (this._icon && type === 'error') {
552
+ const iconEl = renderIcon(this._icon);
553
+ iconEl.style.width = '16px';
554
+ iconEl.style.height = '16px';
555
+ iconEl.style.marginRight = '6px';
556
+ iconEl.style.verticalAlign = 'middle';
557
+ el.appendChild(iconEl);
558
+ }
559
+ const span = document.createElement('span');
560
+ span.textContent = text;
561
+ el.appendChild(span);
562
+ }
563
+ else {
564
+ // ✅ Hide status after successful load - table speaks for itself
565
+ el.style.display = 'none';
559
566
  }
560
- const span = document.createElement('span');
561
- span.textContent = text;
562
- el.appendChild(span);
563
567
  }
564
568
  _setDataFrame(df, sourceName) {
565
569
  this._df = df;
@@ -589,36 +593,155 @@ export class DataFrameComponent extends BaseComponent {
589
593
  const columnDefs = this._df.columns.map(col => ({ key: col, label: col }));
590
594
  this._table.columns(columnDefs).rows(this._df.toRows());
591
595
  }
592
- const isMalformed = this._detectMalformedData(this._df);
593
- // ✅ Show the details element now that data is loaded
596
+ // Show the table container, hide upload area
597
+ this._showDataView();
598
+ // ✅ Update collapsible summary if enabled
594
599
  if (this._collapsible && this._detailsElement) {
595
600
  this._detailsElement.style.display = '';
596
- this._updateSummary(isMalformed);
601
+ this._updateSummary();
597
602
  }
598
- // ✅ Update status (for non-collapsible mode)
599
- if (!this._collapsible) {
600
- if (isMalformed && this._rawFileData) {
601
- this._updateStatus(`${sourceName} — ${this._df.height} rows × ${this._df.width} cols`, 'warning');
602
- this._appendSettingsButton('Fix Import Settings', 'warning');
603
- }
604
- else {
605
- this._updateStatus(`${sourceName} — ${this._df.height} rows × ${this._df.width} cols`, 'success');
606
- if (this._rawFileData) {
607
- this._appendSettingsButton('Import Settings', 'ghost');
608
- }
609
- }
603
+ // ✅ Hide status - data is loaded
604
+ this._updateStatus('', 'success');
605
+ this._triggerCallback('load', this._df, null, this);
606
+ }
607
+ /**
608
+ * Show the data view (table + settings gear), hide upload area
609
+ */
610
+ _showDataView() {
611
+ const wrapper = document.getElementById(this._id);
612
+ if (!wrapper)
613
+ return;
614
+ // Hide upload area
615
+ const uploadArea = wrapper.querySelector('.jux-dataframe-upload-area');
616
+ if (uploadArea) {
617
+ uploadArea.style.display = 'none';
618
+ }
619
+ // Show data container (table + toolbar)
620
+ const dataContainer = wrapper.querySelector('.jux-dataframe-data');
621
+ if (dataContainer) {
622
+ dataContainer.style.display = '';
623
+ }
624
+ // Update settings gear with file info
625
+ this._updateSettingsGear();
626
+ }
627
+ /**
628
+ * Hide data view, show upload area
629
+ */
630
+ _hideDataView() {
631
+ const wrapper = document.getElementById(this._id);
632
+ if (!wrapper)
633
+ return;
634
+ // Show upload area
635
+ const uploadArea = wrapper.querySelector('.jux-dataframe-upload-area');
636
+ if (uploadArea) {
637
+ uploadArea.style.display = '';
638
+ }
639
+ // Hide data container
640
+ const dataContainer = wrapper.querySelector('.jux-dataframe-data');
641
+ if (dataContainer) {
642
+ dataContainer.style.display = 'none';
643
+ }
644
+ }
645
+ /**
646
+ * Update the settings gear tooltip/info
647
+ */
648
+ _updateSettingsGear() {
649
+ const gear = document.getElementById(`${this._id}-settings-gear`);
650
+ if (!gear || !this._df)
651
+ return;
652
+ const isMalformed = this._detectMalformedData(this._df);
653
+ if (isMalformed) {
654
+ gear.classList.add('jux-dataframe-gear-warning');
655
+ gear.title = `${this.state.sourceName} — May need reformatting`;
610
656
  }
611
657
  else {
612
- // ✅ For collapsible mode, hide the status bar
613
- const statusEl = document.getElementById(`${this._id}-status`);
614
- if (statusEl) {
615
- statusEl.style.display = 'none';
616
- }
658
+ gear.classList.remove('jux-dataframe-gear-warning');
659
+ gear.title = `${this.state.sourceName} — ${this._df.height} rows × ${this._df.width} cols`;
617
660
  }
618
- this._triggerCallback('load', this._df, null, this);
619
661
  }
620
662
  /**
621
- * Update the collapsible summary text and add settings button
663
+ * Show the unified settings modal
664
+ */
665
+ _showSettingsModal() {
666
+ this._cleanupReshapeModal();
667
+ const fileInfo = this._rawFileData?.file;
668
+ const isMalformed = this._df ? this._detectMalformedData(this._df) : false;
669
+ this._settingsModal = new Modal(`${this._id}-settings-modal`, {
670
+ title: 'Data Settings',
671
+ size: 'medium',
672
+ close: true,
673
+ backdropClose: true
674
+ });
675
+ const fileSizeKB = fileInfo ? (fileInfo.size / 1024).toFixed(1) : '0';
676
+ const fileName = fileInfo?.name || this.state.sourceName || 'Unknown';
677
+ let contentHTML = `
678
+ <div class="jux-dataframe-settings-content">
679
+ <!-- File Info Section -->
680
+ <div class="jux-dataframe-settings-section">
681
+ <div class="jux-dataframe-settings-label">Source</div>
682
+ <div class="jux-dataframe-settings-value">
683
+ <strong>${this._escapeHtml(fileName)}</strong>
684
+ ${fileInfo ? `<span class="jux-muted" style="margin-left: 8px;">${fileSizeKB} KB</span>` : ''}
685
+ </div>
686
+ </div>
687
+
688
+ <!-- Data Info Section -->
689
+ <div class="jux-dataframe-settings-section">
690
+ <div class="jux-dataframe-settings-label">Data</div>
691
+ <div class="jux-dataframe-settings-value">
692
+ ${this._df ? `${this._df.height} rows × ${this._df.width} columns` : 'No data loaded'}
693
+ ${isMalformed ? '<span style="color: hsl(var(--warning)); margin-left: 8px;">⚠️ May need reformatting</span>' : ''}
694
+ </div>
695
+ </div>
696
+ `;
697
+ // Import Settings button (only if we have raw file data)
698
+ if (this._rawFileData) {
699
+ contentHTML += `
700
+ <div class="jux-dataframe-settings-section">
701
+ <div class="jux-dataframe-settings-label">Import</div>
702
+ <div class="jux-dataframe-settings-value">
703
+ <button id="${this._id}-adjust-import" class="jux-button jux-button-outline jux-button-sm">
704
+ ⚙️ Adjust Header Row / Delimiter
705
+ </button>
706
+ </div>
707
+ </div>
708
+ `;
709
+ }
710
+ contentHTML += `
711
+ </div>
712
+ `;
713
+ this._settingsModal
714
+ .content(contentHTML)
715
+ .actions([
716
+ {
717
+ label: 'Remove Data',
718
+ variant: 'secondary',
719
+ click: async () => {
720
+ await this.clear();
721
+ this._settingsModal.closeModal();
722
+ }
723
+ },
724
+ {
725
+ label: 'Done',
726
+ variant: 'primary',
727
+ click: () => this._settingsModal.closeModal()
728
+ }
729
+ ]);
730
+ this._settingsModal.render(document.body);
731
+ this._settingsModal.open();
732
+ // Wire up import settings button
733
+ requestAnimationFrame(() => {
734
+ const adjustBtn = document.getElementById(`${this._id}-adjust-import`);
735
+ if (adjustBtn) {
736
+ adjustBtn.addEventListener('click', () => {
737
+ this._settingsModal.closeModal();
738
+ this._showReshapeModal();
739
+ });
740
+ }
741
+ });
742
+ }
743
+ /**
744
+ * Update the collapsible summary text
622
745
  */
623
746
  _updateSummary(isMalformed) {
624
747
  if (!this._collapsible || !this._detailsElement)
@@ -626,9 +749,7 @@ export class DataFrameComponent extends BaseComponent {
626
749
  const summaryEl = this._detailsElement.querySelector('.jux-dataframe-summary');
627
750
  if (!summaryEl)
628
751
  return;
629
- // Get or detect malformed status
630
752
  const malformed = isMalformed ?? (this._df ? this._detectMalformedData(this._df) : false);
631
- // Update text
632
753
  const summaryTextEl = summaryEl.querySelector('.jux-dataframe-summary-text');
633
754
  if (summaryTextEl) {
634
755
  if (!this._df) {
@@ -642,32 +763,29 @@ export class DataFrameComponent extends BaseComponent {
642
763
  summaryTextEl.textContent = `${this.state.sourceName || 'Data'} — ${this._df.height} rows × ${this._df.width} cols${suffix}`;
643
764
  }
644
765
  }
645
- // ✅ Add settings button to summary if we have raw file data
646
- let settingsBtn = summaryEl.querySelector('.jux-dataframe-summary-settings');
647
- if (this._rawFileData && this._df) {
648
- if (!settingsBtn) {
649
- settingsBtn = document.createElement('button');
650
- settingsBtn.className = 'jux-dataframe-summary-settings';
651
- settingsBtn.type = 'button';
652
- settingsBtn.addEventListener('click', (e) => {
653
- e.stopPropagation(); // Don't toggle the details
654
- this._showReshapeModal();
766
+ // ✅ Add/update settings gear in summary
767
+ let gearBtn = summaryEl.querySelector('.jux-dataframe-summary-gear');
768
+ if (this._df) {
769
+ if (!gearBtn) {
770
+ gearBtn = document.createElement('button');
771
+ gearBtn.className = 'jux-dataframe-summary-gear';
772
+ gearBtn.type = 'button';
773
+ gearBtn.innerHTML = '⚙️';
774
+ gearBtn.addEventListener('click', (e) => {
775
+ e.stopPropagation();
776
+ this._showSettingsModal();
655
777
  });
656
- summaryEl.appendChild(settingsBtn);
778
+ summaryEl.appendChild(gearBtn);
657
779
  }
658
- // Update button text/style based on malformed status
659
780
  if (malformed) {
660
- settingsBtn.textContent = '⚙️ Fix Settings';
661
- settingsBtn.className = 'jux-dataframe-summary-settings jux-dataframe-summary-settings-warning';
781
+ gearBtn.classList.add('jux-dataframe-gear-warning');
662
782
  }
663
783
  else {
664
- settingsBtn.textContent = '⚙️ Settings';
665
- settingsBtn.className = 'jux-dataframe-summary-settings';
784
+ gearBtn.classList.remove('jux-dataframe-gear-warning');
666
785
  }
667
786
  }
668
- else if (settingsBtn) {
669
- // Remove settings button if no raw file data
670
- settingsBtn.remove();
787
+ else if (gearBtn) {
788
+ gearBtn.remove();
671
789
  }
672
790
  }
673
791
  /* ═══════════════════════════════════════════════════
@@ -817,8 +935,8 @@ export class DataFrameComponent extends BaseComponent {
817
935
  if (nonEmpty.length < values.length * 0.5)
818
936
  continue;
819
937
  const nonNumeric = nonEmpty.filter(v => {
820
- const str = String(v).trim();
821
- return isNaN(Number(str)) && str !== '';
938
+ const trimmed = v.trim();
939
+ return isNaN(Number(trimmed)) && trimmed !== '';
822
940
  }).length;
823
941
  if (nonNumeric >= nonEmpty.length * 0.7) {
824
942
  selectedSheetRow = sheetRow;
@@ -1091,8 +1209,10 @@ export class DataFrameComponent extends BaseComponent {
1091
1209
  wrapper.className += ` ${className}`;
1092
1210
  if (style)
1093
1211
  wrapper.setAttribute('style', style);
1212
+ // ═══════════════════════════════════════════════════
1213
+ // UPLOAD AREA (shown initially, hidden after data loads)
1214
+ // ═══════════════════════════════════════════════════
1094
1215
  if (this._inlineUpload) {
1095
- // ✅ NEW: Enhanced upload area with better styling
1096
1216
  const uploadArea = document.createElement('div');
1097
1217
  uploadArea.className = 'jux-dataframe-upload-area';
1098
1218
  uploadArea.id = `${this._id}-upload-area`;
@@ -1106,32 +1226,27 @@ export class DataFrameComponent extends BaseComponent {
1106
1226
  }
1107
1227
  const upload = new FileUpload(`${this._id}-upload`, uploadOpts);
1108
1228
  this._uploadRef = upload;
1109
- // ✅ Handle file change AND file clear
1110
1229
  this._pendingSource = async () => {
1111
1230
  upload.bind('change', async (files) => {
1112
1231
  if (!files || files.length === 0) {
1113
- // File was cleared - reset the table
1114
1232
  await this.clear();
1115
1233
  return;
1116
1234
  }
1117
1235
  await this._handleFile(files[0]);
1118
1236
  });
1119
1237
  };
1120
- const uploadRow = document.createElement('div');
1121
- uploadRow.className = 'jux-dataframe-upload-row';
1122
1238
  const uploadContainer = document.createElement('div');
1123
1239
  uploadContainer.className = 'jux-dataframe-upload';
1124
1240
  uploadContainer.id = `${this._id}-upload-container`;
1125
- uploadRow.appendChild(uploadContainer);
1126
- // Status bar INLINE in the same row
1241
+ uploadArea.appendChild(uploadContainer);
1242
+ // Status bar (for loading/error states only)
1127
1243
  if (this._showStatus) {
1128
1244
  const statusBar = document.createElement('div');
1129
- statusBar.className = 'jux-dataframe-status jux-dataframe-status-inline';
1245
+ statusBar.className = 'jux-dataframe-status';
1130
1246
  statusBar.id = `${this._id}-status`;
1131
- statusBar.style.display = 'none'; // Hidden until needed
1132
- uploadRow.appendChild(statusBar);
1247
+ statusBar.style.display = 'none';
1248
+ uploadArea.appendChild(statusBar);
1133
1249
  }
1134
- uploadArea.appendChild(uploadRow);
1135
1250
  if (this._uploadDescription) {
1136
1251
  const descEl = document.createElement('div');
1137
1252
  descEl.className = 'jux-dataframe-upload-description';
@@ -1144,16 +1259,28 @@ export class DataFrameComponent extends BaseComponent {
1144
1259
  }
1145
1260
  else {
1146
1261
  container.appendChild(wrapper);
1147
- // Status bar for non-upload mode
1148
- if (this._showStatus) {
1149
- const statusBar = document.createElement('div');
1150
- statusBar.className = 'jux-dataframe-status jux-dataframe-status-empty';
1151
- statusBar.id = `${this._id}-status`;
1152
- statusBar.textContent = 'No data loaded.';
1153
- wrapper.appendChild(statusBar);
1154
- }
1155
1262
  }
1156
- // ✅ Collapsible details wrapper - HIDDEN until data loads
1263
+ // ═══════════════════════════════════════════════════
1264
+ // DATA CONTAINER (hidden initially, shown after data loads)
1265
+ // ═══════════════════════════════════════════════════
1266
+ const dataContainer = document.createElement('div');
1267
+ dataContainer.className = 'jux-dataframe-data';
1268
+ dataContainer.style.display = 'none'; // Hidden until data loads
1269
+ // ✅ Toolbar with settings gear
1270
+ const toolbar = document.createElement('div');
1271
+ toolbar.className = 'jux-dataframe-toolbar';
1272
+ const settingsGear = document.createElement('button');
1273
+ settingsGear.className = 'jux-dataframe-gear';
1274
+ settingsGear.id = `${this._id}-settings-gear`;
1275
+ settingsGear.type = 'button';
1276
+ settingsGear.innerHTML = '⚙️';
1277
+ settingsGear.title = 'Data Settings';
1278
+ settingsGear.addEventListener('click', () => this._showSettingsModal());
1279
+ toolbar.appendChild(settingsGear);
1280
+ dataContainer.appendChild(toolbar);
1281
+ // ═══════════════════════════════════════════════════
1282
+ // TABLE CONTAINER (inside data container or collapsible)
1283
+ // ═══════════════════════════════════════════════════
1157
1284
  let tableContainer;
1158
1285
  if (this._collapsible) {
1159
1286
  const details = document.createElement('details');
@@ -1174,15 +1301,19 @@ export class DataFrameComponent extends BaseComponent {
1174
1301
  const content = document.createElement('div');
1175
1302
  content.className = 'jux-dataframe-details-content';
1176
1303
  details.appendChild(content);
1177
- wrapper.appendChild(details);
1304
+ dataContainer.appendChild(details);
1178
1305
  tableContainer = content;
1179
1306
  details.addEventListener('toggle', () => {
1180
1307
  this._collapsed = !details.open;
1181
1308
  });
1182
1309
  }
1183
1310
  else {
1184
- tableContainer = wrapper;
1311
+ tableContainer = dataContainer;
1185
1312
  }
1313
+ wrapper.appendChild(dataContainer);
1314
+ // ═══════════════════════════════════════════════════
1315
+ // TABLE
1316
+ // ═══════════════════════════════════════════════════
1186
1317
  const tbl = new Table(`${this._id}-table`, {
1187
1318
  striped: this._tableOptions.striped,
1188
1319
  hoverable: this._tableOptions.hoverable,
@@ -83,6 +83,7 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
83
83
  private _collapsed: boolean = false;
84
84
  private _summaryTemplate: ((df: DataFrame) => string) | null = null;
85
85
  private _detailsElement: HTMLDetailsElement | null = null;
86
+ private _settingsModal: Modal | null = null;
86
87
 
87
88
  constructor(id: string, options: DataFrameOptions = {}) {
88
89
  super(id, {
@@ -310,17 +311,17 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
310
311
  if (existingTabs) existingTabs.remove();
311
312
  }
312
313
 
313
- // ✅ Hide details element when cleared
314
+ // ✅ Hide data view, show upload
315
+ this._hideDataView();
316
+
317
+ // ✅ Hide collapsible details
314
318
  if (this._collapsible && this._detailsElement) {
315
319
  this._detailsElement.style.display = 'none';
316
320
  }
317
321
 
318
- // ✅ Hide status when cleared (for inline upload mode)
319
- const statusEl = document.getElementById(`${this._id}-status`);
320
- if (statusEl && this._inlineUpload) {
321
- statusEl.style.display = 'none';
322
- } else if (statusEl) {
323
- this._updateStatus('No data loaded.', 'empty');
322
+ // ✅ Clear file from upload component
323
+ if (this._uploadRef) {
324
+ this._uploadRef.clear();
324
325
  }
325
326
 
326
327
  return this;
@@ -658,25 +659,29 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
658
659
  const el = document.getElementById(`${this._id}-status`);
659
660
  if (!el) return;
660
661
 
661
- // Always show status (inline with upload button)
662
- el.style.display = '';
663
- el.className = 'jux-dataframe-status';
664
- if (type) el.classList.add(`jux-dataframe-status-${type}`);
665
-
666
- el.innerHTML = '';
662
+ // Only show status during loading/error states
663
+ if (type === 'loading' || type === 'error') {
664
+ el.style.display = '';
665
+ el.className = 'jux-dataframe-status';
666
+ el.classList.add(`jux-dataframe-status-${type}`);
667
+ el.innerHTML = '';
668
+
669
+ if (this._icon && type === 'error') {
670
+ const iconEl = renderIcon(this._icon);
671
+ iconEl.style.width = '16px';
672
+ iconEl.style.height = '16px';
673
+ iconEl.style.marginRight = '6px';
674
+ iconEl.style.verticalAlign = 'middle';
675
+ el.appendChild(iconEl);
676
+ }
667
677
 
668
- if (this._icon && (type === 'success' || type === 'warning')) {
669
- const iconEl = renderIcon(this._icon);
670
- iconEl.style.width = '16px';
671
- iconEl.style.height = '16px';
672
- iconEl.style.marginRight = '6px';
673
- iconEl.style.verticalAlign = 'middle';
674
- el.appendChild(iconEl);
678
+ const span = document.createElement('span');
679
+ span.textContent = text;
680
+ el.appendChild(span);
681
+ } else {
682
+ // Hide status after successful load - table speaks for itself
683
+ el.style.display = 'none';
675
684
  }
676
-
677
- const span = document.createElement('span');
678
- span.textContent = text;
679
- el.appendChild(span);
680
685
  }
681
686
 
682
687
  private _setDataFrame(df: DataFrame, sourceName: string): void {
@@ -710,44 +715,175 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
710
715
  this._table.columns(columnDefs).rows(this._df.toRows());
711
716
  }
712
717
 
713
- const isMalformed = this._detectMalformedData(this._df!);
718
+ // Show the table container, hide upload area
719
+ this._showDataView();
714
720
 
715
- // ✅ Show the details element now that data is loaded
721
+ // ✅ Update collapsible summary if enabled
716
722
  if (this._collapsible && this._detailsElement) {
717
723
  this._detailsElement.style.display = '';
718
- this._updateSummary(isMalformed);
724
+ this._updateSummary();
719
725
  }
720
726
 
721
- // ✅ Update status (for non-collapsible mode)
722
- if (!this._collapsible) {
723
- if (isMalformed && this._rawFileData) {
724
- this._updateStatus(
725
- `${sourceName} — ${this._df!.height} rows × ${this._df!.width} cols`,
726
- 'warning'
727
- );
728
- this._appendSettingsButton('Fix Import Settings', 'warning');
729
- } else {
730
- this._updateStatus(
731
- `${sourceName} ${this._df!.height} rows × ${this._df!.width} cols`,
732
- 'success'
733
- );
734
- if (this._rawFileData) {
735
- this._appendSettingsButton('Import Settings', 'ghost');
736
- }
737
- }
727
+ // ✅ Hide status - data is loaded
728
+ this._updateStatus('', 'success');
729
+
730
+ this._triggerCallback('load', this._df, null, this);
731
+ }
732
+
733
+ /**
734
+ * Show the data view (table + settings gear), hide upload area
735
+ */
736
+ private _showDataView(): void {
737
+ const wrapper = document.getElementById(this._id);
738
+ if (!wrapper) return;
739
+
740
+ // Hide upload area
741
+ const uploadArea = wrapper.querySelector('.jux-dataframe-upload-area') as HTMLElement;
742
+ if (uploadArea) {
743
+ uploadArea.style.display = 'none';
744
+ }
745
+
746
+ // Show data container (table + toolbar)
747
+ const dataContainer = wrapper.querySelector('.jux-dataframe-data') as HTMLElement;
748
+ if (dataContainer) {
749
+ dataContainer.style.display = '';
750
+ }
751
+
752
+ // Update settings gear with file info
753
+ this._updateSettingsGear();
754
+ }
755
+
756
+ /**
757
+ * Hide data view, show upload area
758
+ */
759
+ private _hideDataView(): void {
760
+ const wrapper = document.getElementById(this._id);
761
+ if (!wrapper) return;
762
+
763
+ // Show upload area
764
+ const uploadArea = wrapper.querySelector('.jux-dataframe-upload-area') as HTMLElement;
765
+ if (uploadArea) {
766
+ uploadArea.style.display = '';
767
+ }
768
+
769
+ // Hide data container
770
+ const dataContainer = wrapper.querySelector('.jux-dataframe-data') as HTMLElement;
771
+ if (dataContainer) {
772
+ dataContainer.style.display = 'none';
773
+ }
774
+ }
775
+
776
+ /**
777
+ * Update the settings gear tooltip/info
778
+ */
779
+ private _updateSettingsGear(): void {
780
+ const gear = document.getElementById(`${this._id}-settings-gear`);
781
+ if (!gear || !this._df) return;
782
+
783
+ const isMalformed = this._detectMalformedData(this._df);
784
+
785
+ if (isMalformed) {
786
+ gear.classList.add('jux-dataframe-gear-warning');
787
+ gear.title = `${this.state.sourceName} — May need reformatting`;
738
788
  } else {
739
- // ✅ For collapsible mode, hide the status bar
740
- const statusEl = document.getElementById(`${this._id}-status`);
741
- if (statusEl) {
742
- statusEl.style.display = 'none';
743
- }
789
+ gear.classList.remove('jux-dataframe-gear-warning');
790
+ gear.title = `${this.state.sourceName} — ${this._df.height} rows × ${this._df.width} cols`;
744
791
  }
792
+ }
745
793
 
746
- this._triggerCallback('load', this._df, null, this);
794
+ /**
795
+ * Show the unified settings modal
796
+ */
797
+ private _showSettingsModal(): void {
798
+ this._cleanupReshapeModal();
799
+
800
+ const fileInfo = this._rawFileData?.file;
801
+ const isMalformed = this._df ? this._detectMalformedData(this._df) : false;
802
+
803
+ this._settingsModal = new Modal(`${this._id}-settings-modal`, {
804
+ title: 'Data Settings',
805
+ size: 'medium',
806
+ close: true,
807
+ backdropClose: true
808
+ });
809
+
810
+ const fileSizeKB = fileInfo ? (fileInfo.size / 1024).toFixed(1) : '0';
811
+ const fileName = fileInfo?.name || this.state.sourceName || 'Unknown';
812
+
813
+ let contentHTML = `
814
+ <div class="jux-dataframe-settings-content">
815
+ <!-- File Info Section -->
816
+ <div class="jux-dataframe-settings-section">
817
+ <div class="jux-dataframe-settings-label">Source</div>
818
+ <div class="jux-dataframe-settings-value">
819
+ <strong>${this._escapeHtml(fileName)}</strong>
820
+ ${fileInfo ? `<span class="jux-muted" style="margin-left: 8px;">${fileSizeKB} KB</span>` : ''}
821
+ </div>
822
+ </div>
823
+
824
+ <!-- Data Info Section -->
825
+ <div class="jux-dataframe-settings-section">
826
+ <div class="jux-dataframe-settings-label">Data</div>
827
+ <div class="jux-dataframe-settings-value">
828
+ ${this._df ? `${this._df.height} rows × ${this._df.width} columns` : 'No data loaded'}
829
+ ${isMalformed ? '<span style="color: hsl(var(--warning)); margin-left: 8px;">⚠️ May need reformatting</span>' : ''}
830
+ </div>
831
+ </div>
832
+ `;
833
+
834
+ // Import Settings button (only if we have raw file data)
835
+ if (this._rawFileData) {
836
+ contentHTML += `
837
+ <div class="jux-dataframe-settings-section">
838
+ <div class="jux-dataframe-settings-label">Import</div>
839
+ <div class="jux-dataframe-settings-value">
840
+ <button id="${this._id}-adjust-import" class="jux-button jux-button-outline jux-button-sm">
841
+ ⚙️ Adjust Header Row / Delimiter
842
+ </button>
843
+ </div>
844
+ </div>
845
+ `;
846
+ }
847
+
848
+ contentHTML += `
849
+ </div>
850
+ `;
851
+
852
+ this._settingsModal
853
+ .content(contentHTML)
854
+ .actions([
855
+ {
856
+ label: 'Remove Data',
857
+ variant: 'secondary',
858
+ click: async () => {
859
+ await this.clear();
860
+ this._settingsModal!.closeModal();
861
+ }
862
+ },
863
+ {
864
+ label: 'Done',
865
+ variant: 'primary',
866
+ click: () => this._settingsModal!.closeModal()
867
+ }
868
+ ]);
869
+
870
+ this._settingsModal.render(document.body);
871
+ this._settingsModal.open();
872
+
873
+ // Wire up import settings button
874
+ requestAnimationFrame(() => {
875
+ const adjustBtn = document.getElementById(`${this._id}-adjust-import`);
876
+ if (adjustBtn) {
877
+ adjustBtn.addEventListener('click', () => {
878
+ this._settingsModal!.closeModal();
879
+ this._showReshapeModal();
880
+ });
881
+ }
882
+ });
747
883
  }
748
884
 
749
885
  /**
750
- * Update the collapsible summary text and add settings button
886
+ * Update the collapsible summary text
751
887
  */
752
888
  private _updateSummary(isMalformed?: boolean): void {
753
889
  if (!this._collapsible || !this._detailsElement) return;
@@ -755,10 +891,8 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
755
891
  const summaryEl = this._detailsElement.querySelector('.jux-dataframe-summary');
756
892
  if (!summaryEl) return;
757
893
 
758
- // Get or detect malformed status
759
894
  const malformed = isMalformed ?? (this._df ? this._detectMalformedData(this._df) : false);
760
895
 
761
- // Update text
762
896
  const summaryTextEl = summaryEl.querySelector('.jux-dataframe-summary-text');
763
897
  if (summaryTextEl) {
764
898
  if (!this._df) {
@@ -771,32 +905,29 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
771
905
  }
772
906
  }
773
907
 
774
- // ✅ Add settings button to summary if we have raw file data
775
- let settingsBtn = summaryEl.querySelector('.jux-dataframe-summary-settings') as HTMLButtonElement;
776
-
777
- if (this._rawFileData && this._df) {
778
- if (!settingsBtn) {
779
- settingsBtn = document.createElement('button');
780
- settingsBtn.className = 'jux-dataframe-summary-settings';
781
- settingsBtn.type = 'button';
782
- settingsBtn.addEventListener('click', (e) => {
783
- e.stopPropagation(); // Don't toggle the details
784
- this._showReshapeModal();
908
+ // ✅ Add/update settings gear in summary
909
+ let gearBtn = summaryEl.querySelector('.jux-dataframe-summary-gear') as HTMLButtonElement;
910
+
911
+ if (this._df) {
912
+ if (!gearBtn) {
913
+ gearBtn = document.createElement('button');
914
+ gearBtn.className = 'jux-dataframe-summary-gear';
915
+ gearBtn.type = 'button';
916
+ gearBtn.innerHTML = '⚙️';
917
+ gearBtn.addEventListener('click', (e) => {
918
+ e.stopPropagation();
919
+ this._showSettingsModal();
785
920
  });
786
- summaryEl.appendChild(settingsBtn);
921
+ summaryEl.appendChild(gearBtn);
787
922
  }
788
923
 
789
- // Update button text/style based on malformed status
790
924
  if (malformed) {
791
- settingsBtn.textContent = '⚙️ Fix Settings';
792
- settingsBtn.className = 'jux-dataframe-summary-settings jux-dataframe-summary-settings-warning';
925
+ gearBtn.classList.add('jux-dataframe-gear-warning');
793
926
  } else {
794
- settingsBtn.textContent = '⚙️ Settings';
795
- settingsBtn.className = 'jux-dataframe-summary-settings';
927
+ gearBtn.classList.remove('jux-dataframe-gear-warning');
796
928
  }
797
- } else if (settingsBtn) {
798
- // Remove settings button if no raw file data
799
- settingsBtn.remove();
929
+ } else if (gearBtn) {
930
+ gearBtn.remove();
800
931
  }
801
932
  }
802
933
 
@@ -969,8 +1100,8 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
969
1100
  const nonEmpty = values.filter(v => v !== null && v !== undefined && String(v).trim() !== '');
970
1101
  if (nonEmpty.length < values.length * 0.5) continue;
971
1102
  const nonNumeric = nonEmpty.filter(v => {
972
- const str = String(v).trim();
973
- return isNaN(Number(str)) && str !== '';
1103
+ const trimmed = v.trim();
1104
+ return isNaN(Number(trimmed)) && trimmed !== '';
974
1105
  }).length;
975
1106
  if (nonNumeric >= nonEmpty.length * 0.7) {
976
1107
  selectedSheetRow = sheetRow;
@@ -1274,8 +1405,10 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
1274
1405
  if (className) wrapper.className += ` ${className}`;
1275
1406
  if (style) wrapper.setAttribute('style', style);
1276
1407
 
1408
+ // ═══════════════════════════════════════════════════
1409
+ // UPLOAD AREA (shown initially, hidden after data loads)
1410
+ // ═══════════════════════════════════════════════════
1277
1411
  if (this._inlineUpload) {
1278
- // ✅ NEW: Enhanced upload area with better styling
1279
1412
  const uploadArea = document.createElement('div');
1280
1413
  uploadArea.className = 'jux-dataframe-upload-area';
1281
1414
  uploadArea.id = `${this._id}-upload-area`;
@@ -1292,11 +1425,9 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
1292
1425
  const upload = new FileUpload(`${this._id}-upload`, uploadOpts);
1293
1426
  this._uploadRef = upload;
1294
1427
 
1295
- // ✅ Handle file change AND file clear
1296
1428
  this._pendingSource = async () => {
1297
1429
  upload.bind('change', async (files: File[]) => {
1298
1430
  if (!files || files.length === 0) {
1299
- // File was cleared - reset the table
1300
1431
  await this.clear();
1301
1432
  return;
1302
1433
  }
@@ -1304,25 +1435,20 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
1304
1435
  });
1305
1436
  };
1306
1437
 
1307
- const uploadRow = document.createElement('div');
1308
- uploadRow.className = 'jux-dataframe-upload-row';
1309
-
1310
1438
  const uploadContainer = document.createElement('div');
1311
1439
  uploadContainer.className = 'jux-dataframe-upload';
1312
1440
  uploadContainer.id = `${this._id}-upload-container`;
1313
- uploadRow.appendChild(uploadContainer);
1441
+ uploadArea.appendChild(uploadContainer);
1314
1442
 
1315
- // Status bar INLINE in the same row
1443
+ // Status bar (for loading/error states only)
1316
1444
  if (this._showStatus) {
1317
1445
  const statusBar = document.createElement('div');
1318
- statusBar.className = 'jux-dataframe-status jux-dataframe-status-inline';
1446
+ statusBar.className = 'jux-dataframe-status';
1319
1447
  statusBar.id = `${this._id}-status`;
1320
- statusBar.style.display = 'none'; // Hidden until needed
1321
- uploadRow.appendChild(statusBar);
1448
+ statusBar.style.display = 'none';
1449
+ uploadArea.appendChild(statusBar);
1322
1450
  }
1323
1451
 
1324
- uploadArea.appendChild(uploadRow);
1325
-
1326
1452
  if (this._uploadDescription) {
1327
1453
  const descEl = document.createElement('div');
1328
1454
  descEl.className = 'jux-dataframe-upload-description';
@@ -1335,18 +1461,33 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
1335
1461
  upload.render(uploadContainer);
1336
1462
  } else {
1337
1463
  container.appendChild(wrapper);
1338
-
1339
- // Status bar for non-upload mode
1340
- if (this._showStatus) {
1341
- const statusBar = document.createElement('div');
1342
- statusBar.className = 'jux-dataframe-status jux-dataframe-status-empty';
1343
- statusBar.id = `${this._id}-status`;
1344
- statusBar.textContent = 'No data loaded.';
1345
- wrapper.appendChild(statusBar);
1346
- }
1347
1464
  }
1348
1465
 
1349
- // ✅ Collapsible details wrapper - HIDDEN until data loads
1466
+ // ═══════════════════════════════════════════════════
1467
+ // DATA CONTAINER (hidden initially, shown after data loads)
1468
+ // ═══════════════════════════════════════════════════
1469
+ const dataContainer = document.createElement('div');
1470
+ dataContainer.className = 'jux-dataframe-data';
1471
+ dataContainer.style.display = 'none'; // Hidden until data loads
1472
+
1473
+ // ✅ Toolbar with settings gear
1474
+ const toolbar = document.createElement('div');
1475
+ toolbar.className = 'jux-dataframe-toolbar';
1476
+
1477
+ const settingsGear = document.createElement('button');
1478
+ settingsGear.className = 'jux-dataframe-gear';
1479
+ settingsGear.id = `${this._id}-settings-gear`;
1480
+ settingsGear.type = 'button';
1481
+ settingsGear.innerHTML = '⚙️';
1482
+ settingsGear.title = 'Data Settings';
1483
+ settingsGear.addEventListener('click', () => this._showSettingsModal());
1484
+ toolbar.appendChild(settingsGear);
1485
+
1486
+ dataContainer.appendChild(toolbar);
1487
+
1488
+ // ═══════════════════════════════════════════════════
1489
+ // TABLE CONTAINER (inside data container or collapsible)
1490
+ // ═══════════════════════════════════════════════════
1350
1491
  let tableContainer: HTMLElement;
1351
1492
 
1352
1493
  if (this._collapsible) {
@@ -1374,16 +1515,21 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
1374
1515
  content.className = 'jux-dataframe-details-content';
1375
1516
  details.appendChild(content);
1376
1517
 
1377
- wrapper.appendChild(details);
1518
+ dataContainer.appendChild(details);
1378
1519
  tableContainer = content;
1379
1520
 
1380
1521
  details.addEventListener('toggle', () => {
1381
1522
  this._collapsed = !details.open;
1382
1523
  });
1383
1524
  } else {
1384
- tableContainer = wrapper;
1525
+ tableContainer = dataContainer;
1385
1526
  }
1386
1527
 
1528
+ wrapper.appendChild(dataContainer);
1529
+
1530
+ // ═══════════════════════════════════════════════════
1531
+ // TABLE
1532
+ // ═══════════════════════════════════════════════════
1387
1533
  const tbl = new Table(`${this._id}-table`, {
1388
1534
  striped: this._tableOptions.striped,
1389
1535
  hoverable: this._tableOptions.hoverable,
@@ -186,22 +186,20 @@ p { line-height: 1.75; color: hsl(var(--foreground)); }
186
186
  flex-direction: column;
187
187
  align-items: flex-start;
188
188
  gap: 0.5rem;
189
- padding: 1rem;
190
- background: hsl(var(--muted) / 0.2);
191
- border: 1px dashed hsl(var(--border));
192
- border-radius: var(--radius);
189
+ padding: 0.5rem;
190
+ background: transparent;
191
+ border: none;
192
+ border-radius: 0;
193
193
  transition: all 0.2s;
194
194
  }
195
195
 
196
196
  .jux-dataframe-upload-area:hover {
197
- background: hsl(var(--muted) / 0.3);
198
- border-color: hsl(var(--muted-foreground) / 0.3);
197
+ background: transparent;
199
198
  }
200
199
 
201
200
  .jux-dataframe-upload-area:has(.jux-fileupload-filelist:not(:empty)) {
202
- background: hsl(var(--success) / 0.05);
203
- border-color: hsl(var(--success) / 0.2);
204
- border-style: solid;
201
+ background: transparent;
202
+ border: none;
205
203
  }
206
204
 
207
205
  .jux-dataframe-upload {
@@ -954,4 +952,96 @@ code {
954
952
  .jux-dataframe-details-content .jux-table-wrapper {
955
953
  border: none;
956
954
  border-radius: 0;
955
+ }
956
+
957
+ /* ═══════════════════════════════════════════════════════════════════
958
+ * DATAFRAME DATA VIEW (Post-upload clean UI)
959
+ * ═══════════════════════════════════════════════════════════════════ */
960
+
961
+ .jux-dataframe-data {
962
+ display: flex;
963
+ flex-direction: column;
964
+ gap: 0.5rem;
965
+ }
966
+
967
+ .jux-dataframe-toolbar {
968
+ display: flex;
969
+ justify-content: flex-end;
970
+ align-items: center;
971
+ padding: 0.25rem 0;
972
+ }
973
+
974
+ .jux-dataframe-gear {
975
+ display: inline-flex;
976
+ align-items: center;
977
+ justify-content: center;
978
+ width: 2rem;
979
+ height: 2rem;
980
+ padding: 0;
981
+ border: none;
982
+ background: transparent;
983
+ border-radius: var(--radius);
984
+ cursor: pointer;
985
+ font-size: 1rem;
986
+ color: hsl(var(--muted-foreground));
987
+ transition: all 0.15s;
988
+ }
989
+
990
+ .jux-dataframe-gear:hover {
991
+ background: hsl(var(--muted) / 0.5);
992
+ color: hsl(var(--foreground));
993
+ }
994
+
995
+ .jux-dataframe-gear-warning {
996
+ color: hsl(var(--warning));
997
+ }
998
+
999
+ .jux-dataframe-gear-warning:hover {
1000
+ background: hsl(var(--warning) / 0.1);
1001
+ }
1002
+
1003
+ /* Settings modal content */
1004
+ .jux-dataframe-settings-content {
1005
+ display: flex;
1006
+ flex-direction: column;
1007
+ gap: 1rem;
1008
+ }
1009
+
1010
+ .jux-dataframe-settings-section {
1011
+ display: flex;
1012
+ flex-direction: column;
1013
+ gap: 0.25rem;
1014
+ }
1015
+
1016
+ .jux-dataframe-settings-label {
1017
+ font-size: 0.75rem;
1018
+ font-weight: 600;
1019
+ text-transform: uppercase;
1020
+ letter-spacing: 0.05em;
1021
+ color: hsl(var(--muted-foreground));
1022
+ }
1023
+
1024
+ .jux-dataframe-settings-value {
1025
+ font-size: 0.875rem;
1026
+ color: hsl(var(--foreground));
1027
+ }
1028
+
1029
+ /* Summary gear in collapsible mode */
1030
+ .jux-dataframe-summary-gear {
1031
+ padding: 0.25rem 0.5rem;
1032
+ font-size: 0.875rem;
1033
+ border: none;
1034
+ background: transparent;
1035
+ cursor: pointer;
1036
+ color: hsl(var(--muted-foreground));
1037
+ transition: all 0.15s;
1038
+ margin-left: auto;
1039
+ }
1040
+
1041
+ .jux-dataframe-summary-gear:hover {
1042
+ color: hsl(var(--foreground));
1043
+ }
1044
+
1045
+ .jux-dataframe-summary-gear.jux-dataframe-gear-warning {
1046
+ color: hsl(var(--warning));
957
1047
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.1.225",
3
+ "version": "1.1.227",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "index.js",