@jinaan/uikit 0.1.48 → 0.1.50

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jinaan/uikit",
3
- "version": "0.1.48",
3
+ "version": "0.1.50",
4
4
  "description": "Reusable React and Tailwind UI components for Jinaan projects.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -416,6 +416,17 @@ export function DataTable<T>({
416
416
  // column steals its neighbor's width and every column shifts by one.
417
417
  const structureKey = `${selectable ? "s" : "-"}|${rowActions ? "a" : "-"}|${renderExpanded ? "e" : "-"}|${columnKey}`;
418
418
  const structureRef = useRef(structureKey);
419
+ // Column widths are measured from the rendered rows, so any data change
420
+ // (renamed key, new row with longer content) must invalidate the pinned
421
+ // widths — otherwise the stale widths truncate the new content.
422
+ const contentKey = useMemo(() => {
423
+ try {
424
+ return JSON.stringify(rows);
425
+ } catch {
426
+ return `rows:${rows.length}`;
427
+ }
428
+ }, [rows]);
429
+ const contentRef = useRef(contentKey);
419
430
  const pinned = columnWidths.length > 0;
420
431
 
421
432
  // Panel-scroll mode: the band stays fixed to the shell and cannot scroll
@@ -430,15 +441,7 @@ export function DataTable<T>({
430
441
  useLayoutEffect(() => {
431
442
  const table = bodyTableRef.current;
432
443
  if (!table) return;
433
- if (structureRef.current !== structureKey) {
434
- // Column set changed: drop the pinned widths so the body re-renders
435
- // content-sized (table-auto) and the next pass measures intrinsic
436
- // widths against the new structure. Without this, the effect would
437
- // measure the stale colgroup's shifted layout and pin the wrong widths.
438
- structureRef.current = structureKey;
439
- setColumnWidths((prev) => (prev.length === 0 ? prev : []));
440
- return;
441
- }
444
+
442
445
  const measure = () => {
443
446
  const cells = table.tBodies[0]?.rows.item(0)?.cells;
444
447
  if (!cells || cells.length === 0) {
@@ -469,6 +472,23 @@ export function DataTable<T>({
469
472
  prev.length === widths.length && prev.every((w, i) => w === widths[i]) ? prev : widths,
470
473
  );
471
474
  };
475
+ if (structureRef.current !== structureKey || contentRef.current !== contentKey) {
476
+ // Column set or row content changed: drop the pinned widths so the body
477
+ // re-renders content-sized (table-auto) and the next pass measures
478
+ // intrinsic widths again. Without this, the effect would measure the
479
+ // stale colgroup's shifted layout and pin the wrong (truncating) widths.
480
+ structureRef.current = structureKey;
481
+ contentRef.current = contentKey;
482
+ if (pinned) {
483
+ // The widths -> [] state flip re-runs this effect (see `pinned` in the
484
+ // deps); measuring now would read the still-pinned layout.
485
+ setColumnWidths([]);
486
+ return;
487
+ }
488
+ // Already unpinned: no state flip would re-run the effect, so measure
489
+ // the content-sized layout right away.
490
+ }
491
+
472
492
  measure();
473
493
  syncBandScroll();
474
494
  if (typeof ResizeObserver === "undefined") return;
@@ -479,7 +499,7 @@ export function DataTable<T>({
479
499
  // widths (false) and again after re-pinning (true). Safe to measure in
480
500
  // the pinned state because the floor reads sizer spans — intrinsic in
481
501
  // every state — never the pinned layout itself.
482
- }, [structureKey, pinned, loading, error, syncBandScroll]);
502
+ }, [structureKey, contentKey, pinned, loading, error, syncBandScroll]);
483
503
 
484
504
  const totalWidth = columnWidths.reduce((sum, width) => sum + width, 0);
485
505