juxscript 1.1.192 → 1.1.193

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.
@@ -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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"}
@@ -360,8 +360,8 @@ export class DataFrameComponent extends BaseComponent {
360
360
  this._table.columns(columnDefs).rows(this._df.toRows());
361
361
  }
362
362
  const isMalformed = this._detectMalformedData(this._df);
363
- if (isMalformed && this._showReshapeWarning && this._rawFileData) {
364
- this._updateStatus(`${sourceName} — ${this._df.height} rows × ${this._df.width} cols (Data may be malformed — headers may be on wrong row)`, 'warning');
363
+ if (isMalformed && this._rawFileData) {
364
+ this._updateStatus(`${sourceName} — ${this._df.height} rows × ${this._df.width} cols (Data may need reformatting)`, 'warning');
365
365
  requestAnimationFrame(() => {
366
366
  const statusEl = document.getElementById(`${this._id}-status`);
367
367
  if (statusEl) {
@@ -376,12 +376,13 @@ export class DataFrameComponent extends BaseComponent {
376
376
  }
377
377
  else {
378
378
  this._updateStatus(`${sourceName} — ${this._df.height} rows × ${this._df.width} cols`, 'success');
379
- if (this._showReshapeWarning && this._rawFileData) {
379
+ // Always show settings button if we have raw file data
380
+ if (this._rawFileData) {
380
381
  requestAnimationFrame(() => {
381
382
  const statusEl = document.getElementById(`${this._id}-status`);
382
383
  if (statusEl) {
383
384
  const settingsBtn = document.createElement('button');
384
- settingsBtn.textContent = 'Settings';
385
+ settingsBtn.textContent = 'Import Settings';
385
386
  settingsBtn.className = 'jux-button jux-button-sm jux-button-ghost';
386
387
  settingsBtn.style.marginLeft = '0.5rem';
387
388
  settingsBtn.addEventListener('click', () => this._showReshapeModal());
@@ -485,10 +486,7 @@ export class DataFrameComponent extends BaseComponent {
485
486
  max="50"
486
487
  style="width: 100%;"
487
488
  />
488
- <div class="jux-reshape-hint">
489
- <strong>Detected issue:</strong> The current header row appears to contain metadata or empty values.
490
- Row ${suggestedRow} looks like it contains the actual column headers.
491
- Adjust the value above and check the preview below. The Row column shows the index for each row.
489
+ <div id="${this._id}-reshape-hint" class="jux-reshape-hint">
492
490
  </div>
493
491
  </div>
494
492
  <div class="jux-reshape-preview-container">
@@ -526,7 +524,6 @@ export class DataFrameComponent extends BaseComponent {
526
524
  this._renderMultiSheet(sheets, this._rawFileData.file.name);
527
525
  }
528
526
  else {
529
- this._showReshapeWarning = false;
530
527
  this._setDataFrame(sheets[sheetNames[0]], this._rawFileData.file.name);
531
528
  }
532
529
  this._reshapeModal.closeModal();
@@ -542,8 +539,16 @@ export class DataFrameComponent extends BaseComponent {
542
539
  await new Promise(resolve => requestAnimationFrame(resolve));
543
540
  const headerRowInput = document.getElementById(`${this._id}-header-row`);
544
541
  const previewDiv = document.getElementById(`${this._id}-preview`);
542
+ const hintDiv = document.getElementById(`${this._id}-reshape-hint`);
543
+ const updateHint = (headerRow) => {
544
+ if (!hintDiv)
545
+ return;
546
+ hintDiv.innerHTML = `The data starting at <strong>row ${headerRow}</strong> will be used as column headers. ` +
547
+ `Rows before it will be skipped. The preview below shows the row index as the first column.`;
548
+ };
545
549
  const updatePreview = async () => {
546
550
  const headerRow = parseInt(headerRowInput?.value) || 0;
551
+ updateHint(headerRow);
547
552
  try {
548
553
  const sheets = await this._driver.streamFileMultiSheet(this._rawFileData.file, {
549
554
  headerRow,
@@ -556,15 +561,17 @@ export class DataFrameComponent extends BaseComponent {
556
561
  return;
557
562
  }
558
563
  const dataRows = firstSheet.toRows().slice(0, 10);
559
- const colHeader = 'Row'.padEnd(6) + firstSheet.columns.map(c => String(c).padEnd(20)).join(' | ');
560
- const separator = '─'.repeat(Math.min(colHeader.length, 120));
564
+ const idxWidth = 6;
565
+ const colWidth = 22;
566
+ const headerLine = 'Idx'.padEnd(idxWidth) + firstSheet.columns.map(c => String(c).substring(0, colWidth - 2).padEnd(colWidth)).join('| ');
567
+ const separator = '─'.repeat(Math.min(headerLine.length, 140));
561
568
  const preview = dataRows.map((row, i) => {
562
- const rowIdx = String(headerRow + 1 + i).padEnd(6);
563
- const cols = Object.values(row).map(v => String(v ?? '').padEnd(20)).join(' | ');
569
+ const rowIdx = String(headerRow + 1 + i).padEnd(idxWidth);
570
+ const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('| ');
564
571
  return `${rowIdx}${cols}`;
565
572
  }).join('\n');
566
573
  if (previewDiv) {
567
- previewDiv.textContent = `${'Row'.padEnd(6)}Columns: ${firstSheet.columns.join(' | ')}\n${separator}\n${preview}`;
574
+ previewDiv.textContent = `${headerLine}\n${separator}\n${preview}`;
568
575
  }
569
576
  }
570
577
  catch (err) {
@@ -605,7 +612,8 @@ export class DataFrameComponent extends BaseComponent {
605
612
  <label style="display: block; font-weight: 600; margin-bottom: 0.5rem;">Skip Rows Before Header</label>
606
613
  <input type="number" id="${this._id}-skip-rows" class="jux-input-element" value="0" min="0" max="50" style="width: 100%;" />
607
614
  </div>
608
- <div class="jux-reshape-preview-container">
615
+ <div id="${this._id}-reshape-hint" class="jux-reshape-hint"></div>
616
+ <div class="jux-reshape-preview-container" style="margin-top: 1rem;">
609
617
  <div style="font-weight: 600; margin-bottom: 0.5rem; color: hsl(var(--foreground));">Preview</div>
610
618
  <div id="${this._id}-preview" class="jux-reshape-preview"></div>
611
619
  </div>
@@ -640,7 +648,6 @@ export class DataFrameComponent extends BaseComponent {
640
648
  hasHeader: true
641
649
  });
642
650
  await this._driver.store(this._rawFileData.file.name, df, { source: this._rawFileData.file.name });
643
- this._showReshapeWarning = false;
644
651
  this._setDataFrame(df, this._rawFileData.file.name);
645
652
  this._reshapeModal.closeModal();
646
653
  }
@@ -657,6 +664,7 @@ export class DataFrameComponent extends BaseComponent {
657
664
  const headerRowInput = document.getElementById(`${this._id}-header-row`);
658
665
  const skipRowsInput = document.getElementById(`${this._id}-skip-rows`);
659
666
  const previewDiv = document.getElementById(`${this._id}-preview`);
667
+ const hintDiv = document.getElementById(`${this._id}-reshape-hint`);
660
668
  if (this._rawFileData?.text) {
661
669
  const detected = this._driver._detectDelimiter(this._rawFileData.text);
662
670
  if (delimiterSelect)
@@ -665,12 +673,22 @@ export class DataFrameComponent extends BaseComponent {
665
673
  if (headerRowInput)
666
674
  headerRowInput.value = String(detectedHeaderRow);
667
675
  }
676
+ const updateHint = () => {
677
+ if (!hintDiv)
678
+ return;
679
+ const headerRow = parseInt(headerRowInput?.value) || 0;
680
+ const skipRows = parseInt(skipRowsInput?.value) || 0;
681
+ hintDiv.innerHTML = `Using <strong>row ${headerRow}</strong> as column headers` +
682
+ (skipRows > 0 ? ` (skipping ${skipRows} rows before it)` : '') +
683
+ `. The Idx column shows the file row index.`;
684
+ };
668
685
  const updatePreview = () => {
669
686
  if (!this._rawFileData?.text)
670
687
  return;
671
688
  const delim = delimiterSelect?.value || ',';
672
689
  const headerRow = parseInt(headerRowInput?.value) || 0;
673
690
  const skipRows = parseInt(skipRowsInput?.value) || 0;
691
+ updateHint();
674
692
  try {
675
693
  const df = this._driver.parseCSV(this._rawFileData.text, {
676
694
  delimiter: delim,
@@ -680,15 +698,17 @@ export class DataFrameComponent extends BaseComponent {
680
698
  maxRows: 10
681
699
  });
682
700
  const dataRows = df.toRows();
683
- const colHeader = 'Row'.padEnd(6) + df.columns.map(c => String(c).padEnd(20)).join(' | ');
684
- const separator = '─'.repeat(Math.min(colHeader.length, 120));
701
+ const idxWidth = 6;
702
+ const colWidth = 22;
703
+ const headerLine = 'Idx'.padEnd(idxWidth) + df.columns.map(c => String(c).substring(0, colWidth - 2).padEnd(colWidth)).join('| ');
704
+ const separator = '─'.repeat(Math.min(headerLine.length, 140));
685
705
  const preview = dataRows.map((row, i) => {
686
- const rowIdx = String(headerRow + skipRows + 1 + i).padEnd(6);
687
- const cols = Object.values(row).map(v => String(v ?? '').padEnd(20)).join(' | ');
706
+ const rowIdx = String(headerRow + skipRows + 1 + i).padEnd(idxWidth);
707
+ const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('| ');
688
708
  return `${rowIdx}${cols}`;
689
709
  }).join('\n');
690
710
  if (previewDiv) {
691
- previewDiv.textContent = `${'Row'.padEnd(6)}Columns: ${df.columns.join(' | ')}\n${separator}\n${preview}`;
711
+ previewDiv.textContent = `${headerLine}\n${separator}\n${preview}`;
692
712
  }
693
713
  }
694
714
  catch (err) {
@@ -452,9 +452,9 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
452
452
 
453
453
  const isMalformed = this._detectMalformedData(this._df!);
454
454
 
455
- if (isMalformed && this._showReshapeWarning && this._rawFileData) {
455
+ if (isMalformed && this._rawFileData) {
456
456
  this._updateStatus(
457
- `${sourceName} — ${this._df!.height} rows × ${this._df!.width} cols (Data may be malformed — headers may be on wrong row)`,
457
+ `${sourceName} — ${this._df!.height} rows × ${this._df!.width} cols (Data may need reformatting)`,
458
458
  'warning'
459
459
  );
460
460
 
@@ -475,12 +475,13 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
475
475
  'success'
476
476
  );
477
477
 
478
- if (this._showReshapeWarning && this._rawFileData) {
478
+ // Always show settings button if we have raw file data
479
+ if (this._rawFileData) {
479
480
  requestAnimationFrame(() => {
480
481
  const statusEl = document.getElementById(`${this._id}-status`);
481
482
  if (statusEl) {
482
483
  const settingsBtn = document.createElement('button');
483
- settingsBtn.textContent = 'Settings';
484
+ settingsBtn.textContent = 'Import Settings';
484
485
  settingsBtn.className = 'jux-button jux-button-sm jux-button-ghost';
485
486
  settingsBtn.style.marginLeft = '0.5rem';
486
487
  settingsBtn.addEventListener('click', () => this._showReshapeModal());
@@ -603,10 +604,7 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
603
604
  max="50"
604
605
  style="width: 100%;"
605
606
  />
606
- <div class="jux-reshape-hint">
607
- <strong>Detected issue:</strong> The current header row appears to contain metadata or empty values.
608
- Row ${suggestedRow} looks like it contains the actual column headers.
609
- Adjust the value above and check the preview below. The Row column shows the index for each row.
607
+ <div id="${this._id}-reshape-hint" class="jux-reshape-hint">
610
608
  </div>
611
609
  </div>
612
610
  <div class="jux-reshape-preview-container">
@@ -648,7 +646,6 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
648
646
  if (sheetNames.length > 1) {
649
647
  this._renderMultiSheet(sheets, this._rawFileData!.file.name);
650
648
  } else {
651
- this._showReshapeWarning = false;
652
649
  this._setDataFrame(sheets[sheetNames[0]], this._rawFileData!.file.name);
653
650
  }
654
651
 
@@ -667,9 +664,19 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
667
664
 
668
665
  const headerRowInput = document.getElementById(`${this._id}-header-row`) as HTMLInputElement;
669
666
  const previewDiv = document.getElementById(`${this._id}-preview`)!;
667
+ const hintDiv = document.getElementById(`${this._id}-reshape-hint`)!;
668
+
669
+ const updateHint = (headerRow: number) => {
670
+ if (!hintDiv) return;
671
+ hintDiv.innerHTML = `The data starting at <strong>row ${headerRow}</strong> will be used as column headers. ` +
672
+ `Rows before it will be skipped. The preview below shows the row index as the first column.`;
673
+ };
670
674
 
671
675
  const updatePreview = async () => {
672
676
  const headerRow = parseInt(headerRowInput?.value) || 0;
677
+
678
+ updateHint(headerRow);
679
+
673
680
  try {
674
681
  const sheets = await this._driver.streamFileMultiSheet(this._rawFileData!.file, {
675
682
  headerRow,
@@ -683,16 +690,20 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
683
690
  }
684
691
 
685
692
  const dataRows = firstSheet.toRows().slice(0, 10);
686
- const colHeader = 'Row'.padEnd(6) + firstSheet.columns.map(c => String(c).padEnd(20)).join(' | ');
687
- const separator = '─'.repeat(Math.min(colHeader.length, 120));
693
+ const idxWidth = 6;
694
+ const colWidth = 22;
695
+
696
+ const headerLine = 'Idx'.padEnd(idxWidth) + firstSheet.columns.map(c => String(c).substring(0, colWidth - 2).padEnd(colWidth)).join('| ');
697
+ const separator = '─'.repeat(Math.min(headerLine.length, 140));
698
+
688
699
  const preview = dataRows.map((row, i) => {
689
- const rowIdx = String(headerRow + 1 + i).padEnd(6);
690
- const cols = Object.values(row).map(v => String(v ?? '').padEnd(20)).join(' | ');
700
+ const rowIdx = String(headerRow + 1 + i).padEnd(idxWidth);
701
+ const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('| ');
691
702
  return `${rowIdx}${cols}`;
692
703
  }).join('\n');
693
704
 
694
705
  if (previewDiv) {
695
- previewDiv.textContent = `${'Row'.padEnd(6)}Columns: ${firstSheet.columns.join(' | ')}\n${separator}\n${preview}`;
706
+ previewDiv.textContent = `${headerLine}\n${separator}\n${preview}`;
696
707
  }
697
708
  } catch (err: any) {
698
709
  if (previewDiv) previewDiv.textContent = `Error: ${err.message}`;
@@ -735,7 +746,8 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
735
746
  <label style="display: block; font-weight: 600; margin-bottom: 0.5rem;">Skip Rows Before Header</label>
736
747
  <input type="number" id="${this._id}-skip-rows" class="jux-input-element" value="0" min="0" max="50" style="width: 100%;" />
737
748
  </div>
738
- <div class="jux-reshape-preview-container">
749
+ <div id="${this._id}-reshape-hint" class="jux-reshape-hint"></div>
750
+ <div class="jux-reshape-preview-container" style="margin-top: 1rem;">
739
751
  <div style="font-weight: 600; margin-bottom: 0.5rem; color: hsl(var(--foreground));">Preview</div>
740
752
  <div id="${this._id}-preview" class="jux-reshape-preview"></div>
741
753
  </div>
@@ -775,7 +787,6 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
775
787
  });
776
788
 
777
789
  await this._driver.store(this._rawFileData.file.name, df, { source: this._rawFileData.file.name });
778
- this._showReshapeWarning = false;
779
790
  this._setDataFrame(df, this._rawFileData.file.name);
780
791
 
781
792
  this._reshapeModal!.closeModal();
@@ -794,6 +805,7 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
794
805
  const headerRowInput = document.getElementById(`${this._id}-header-row`) as HTMLInputElement;
795
806
  const skipRowsInput = document.getElementById(`${this._id}-skip-rows`) as HTMLInputElement;
796
807
  const previewDiv = document.getElementById(`${this._id}-preview`)!;
808
+ const hintDiv = document.getElementById(`${this._id}-reshape-hint`)!;
797
809
 
798
810
  if (this._rawFileData?.text) {
799
811
  const detected = (this._driver as any)._detectDelimiter(this._rawFileData.text);
@@ -803,6 +815,15 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
803
815
  if (headerRowInput) headerRowInput.value = String(detectedHeaderRow);
804
816
  }
805
817
 
818
+ const updateHint = () => {
819
+ if (!hintDiv) return;
820
+ const headerRow = parseInt(headerRowInput?.value) || 0;
821
+ const skipRows = parseInt(skipRowsInput?.value) || 0;
822
+ hintDiv.innerHTML = `Using <strong>row ${headerRow}</strong> as column headers` +
823
+ (skipRows > 0 ? ` (skipping ${skipRows} rows before it)` : '') +
824
+ `. The Idx column shows the file row index.`;
825
+ };
826
+
806
827
  const updatePreview = () => {
807
828
  if (!this._rawFileData?.text) return;
808
829
 
@@ -810,6 +831,8 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
810
831
  const headerRow = parseInt(headerRowInput?.value) || 0;
811
832
  const skipRows = parseInt(skipRowsInput?.value) || 0;
812
833
 
834
+ updateHint();
835
+
813
836
  try {
814
837
  const df = this._driver.parseCSV(this._rawFileData.text, {
815
838
  delimiter: delim,
@@ -820,16 +843,20 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
820
843
  });
821
844
 
822
845
  const dataRows = df.toRows();
823
- const colHeader = 'Row'.padEnd(6) + df.columns.map(c => String(c).padEnd(20)).join(' | ');
824
- const separator = '─'.repeat(Math.min(colHeader.length, 120));
846
+ const idxWidth = 6;
847
+ const colWidth = 22;
848
+
849
+ const headerLine = 'Idx'.padEnd(idxWidth) + df.columns.map(c => String(c).substring(0, colWidth - 2).padEnd(colWidth)).join('| ');
850
+ const separator = '─'.repeat(Math.min(headerLine.length, 140));
851
+
825
852
  const preview = dataRows.map((row, i) => {
826
- const rowIdx = String(headerRow + skipRows + 1 + i).padEnd(6);
827
- const cols = Object.values(row).map(v => String(v ?? '').padEnd(20)).join(' | ');
853
+ const rowIdx = String(headerRow + skipRows + 1 + i).padEnd(idxWidth);
854
+ const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('| ');
828
855
  return `${rowIdx}${cols}`;
829
856
  }).join('\n');
830
857
 
831
858
  if (previewDiv) {
832
- previewDiv.textContent = `${'Row'.padEnd(6)}Columns: ${df.columns.join(' | ')}\n${separator}\n${preview}`;
859
+ previewDiv.textContent = `${headerLine}\n${separator}\n${preview}`;
833
860
  }
834
861
  } catch (err: any) {
835
862
  if (previewDiv) previewDiv.textContent = `Error: ${err.message}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.1.192",
3
+ "version": "1.1.193",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "index.js",