@rowakit/table 0.5.0 → 1.0.0

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/dist/index.d.cts CHANGED
@@ -242,6 +242,16 @@ type ExporterResult = {
242
242
  } | Blob;
243
243
  type Exporter = (query: FetcherQuery) => Promise<ExporterResult>;
244
244
 
245
+ interface BulkActionDef {
246
+ id: string;
247
+ label: string;
248
+ confirm?: {
249
+ title: string;
250
+ description?: string;
251
+ };
252
+ onClick: (selectedKeys: Array<string | number>) => void;
253
+ }
254
+
245
255
  /**
246
256
  * Column helper factory functions
247
257
  *
@@ -479,16 +489,6 @@ declare const col: {
479
489
  readonly custom: typeof custom;
480
490
  };
481
491
 
482
- interface BulkActionDef {
483
- id: string;
484
- label: string;
485
- confirm?: {
486
- title: string;
487
- description?: string;
488
- };
489
- onClick: (selectedKeys: Array<string | number>) => void;
490
- }
491
-
492
492
  interface SmartTableProps<T> {
493
493
  /** Server-side data fetcher function */
494
494
  fetcher: Fetcher<T>;
@@ -586,4 +586,4 @@ declare const SmartTable: typeof RowaKitTable;
586
586
 
587
587
  declare const VERSION: string;
588
588
 
589
- export { type ActionDef, type ActionsColumnDef, type BadgeColumnDef, type BadgeTone, type BaseColumnDef, type BooleanColumnDef, type ColumnDef, type ColumnKind, type CustomColumnDef, type DateColumnDef, type Exporter, type ExporterResult, type Fetcher, type FetcherQuery, type FetcherResult, type FilterValue, type Filters, type NumberColumnDef, RowaKitTable, SmartTable, type SmartTableProps, type TextColumnDef, VERSION, col };
589
+ export { type ActionDef, type ActionsColumnDef, type BadgeColumnDef, type BadgeTone, type BaseColumnDef, type BooleanColumnDef, type BulkActionDef, type ColumnDef, type ColumnKind, type CustomColumnDef, type DateColumnDef, type Exporter, type ExporterResult, type Fetcher, type FetcherQuery, type FetcherResult, type FilterValue, type Filters, type NumberColumnDef, RowaKitTable, SmartTable, type SmartTableProps, type SortColumn, type TextColumnDef, VERSION, col };
package/dist/index.d.ts CHANGED
@@ -242,6 +242,16 @@ type ExporterResult = {
242
242
  } | Blob;
243
243
  type Exporter = (query: FetcherQuery) => Promise<ExporterResult>;
244
244
 
245
+ interface BulkActionDef {
246
+ id: string;
247
+ label: string;
248
+ confirm?: {
249
+ title: string;
250
+ description?: string;
251
+ };
252
+ onClick: (selectedKeys: Array<string | number>) => void;
253
+ }
254
+
245
255
  /**
246
256
  * Column helper factory functions
247
257
  *
@@ -479,16 +489,6 @@ declare const col: {
479
489
  readonly custom: typeof custom;
480
490
  };
481
491
 
482
- interface BulkActionDef {
483
- id: string;
484
- label: string;
485
- confirm?: {
486
- title: string;
487
- description?: string;
488
- };
489
- onClick: (selectedKeys: Array<string | number>) => void;
490
- }
491
-
492
492
  interface SmartTableProps<T> {
493
493
  /** Server-side data fetcher function */
494
494
  fetcher: Fetcher<T>;
@@ -586,4 +586,4 @@ declare const SmartTable: typeof RowaKitTable;
586
586
 
587
587
  declare const VERSION: string;
588
588
 
589
- export { type ActionDef, type ActionsColumnDef, type BadgeColumnDef, type BadgeTone, type BaseColumnDef, type BooleanColumnDef, type ColumnDef, type ColumnKind, type CustomColumnDef, type DateColumnDef, type Exporter, type ExporterResult, type Fetcher, type FetcherQuery, type FetcherResult, type FilterValue, type Filters, type NumberColumnDef, RowaKitTable, SmartTable, type SmartTableProps, type TextColumnDef, VERSION, col };
589
+ export { type ActionDef, type ActionsColumnDef, type BadgeColumnDef, type BadgeTone, type BaseColumnDef, type BooleanColumnDef, type BulkActionDef, type ColumnDef, type ColumnKind, type CustomColumnDef, type DateColumnDef, type Exporter, type ExporterResult, type Fetcher, type FetcherQuery, type FetcherResult, type FilterValue, type Filters, type NumberColumnDef, RowaKitTable, SmartTable, type SmartTableProps, type SortColumn, type TextColumnDef, VERSION, col };
package/dist/index.js CHANGED
@@ -567,11 +567,22 @@ function parseUrlState(params, defaultPageSize, pageSizeOptions) {
567
567
  } catch {
568
568
  }
569
569
  }
570
+ if (!result.sorts) {
571
+ const sortStr = params.get("sort");
572
+ if (sortStr) {
573
+ const [field, dir] = sortStr.split(":");
574
+ if (field && (dir === "asc" || dir === "desc")) {
575
+ result.sort = { field, direction: dir };
576
+ result.sorts = [{ field, direction: dir, priority: 0 }];
577
+ }
578
+ }
579
+ }
570
580
  if (!result.sorts) {
571
581
  const sortField = params.get("sortField");
572
582
  const sortDir = params.get("sortDirection");
573
583
  if (sortField && (sortDir === "asc" || sortDir === "desc")) {
574
584
  result.sort = { field: sortField, direction: sortDir };
585
+ result.sorts = [{ field: sortField, direction: sortDir, priority: 0 }];
575
586
  }
576
587
  }
577
588
  const filtersStr = params.get("filters");
@@ -643,40 +654,59 @@ function useUrlSync({
643
654
  setColumnWidths
644
655
  }) {
645
656
  const didHydrateUrlRef = useRef(false);
646
- const didSkipInitialUrlSyncRef = useRef(false);
647
657
  const urlSyncDebounceRef = useRef(null);
658
+ const isApplyingUrlStateRef = useRef(false);
659
+ const clearApplyingTimerRef = useRef(null);
660
+ const hasWrittenUrlRef = useRef(false);
661
+ const lastQueryForUrlRef = useRef(null);
662
+ const defaultPageSizeRef = useRef(defaultPageSize);
663
+ const pageSizeOptionsRef = useRef(pageSizeOptions);
664
+ const enableColumnResizingRef = useRef(enableColumnResizing);
665
+ const columnsRef = useRef(columns);
666
+ defaultPageSizeRef.current = defaultPageSize;
667
+ pageSizeOptionsRef.current = pageSizeOptions;
668
+ enableColumnResizingRef.current = enableColumnResizing;
669
+ columnsRef.current = columns;
648
670
  useEffect(() => {
649
671
  if (!syncToUrl) {
650
- didSkipInitialUrlSyncRef.current = false;
651
- return;
652
- }
653
- if (!didSkipInitialUrlSyncRef.current) {
654
- didSkipInitialUrlSyncRef.current = true;
672
+ hasWrittenUrlRef.current = false;
673
+ lastQueryForUrlRef.current = null;
655
674
  return;
656
675
  }
676
+ if (!didHydrateUrlRef.current) return;
677
+ if (isApplyingUrlStateRef.current) return;
657
678
  if (urlSyncDebounceRef.current) {
658
679
  clearTimeout(urlSyncDebounceRef.current);
659
680
  urlSyncDebounceRef.current = null;
660
681
  }
661
- const urlStr = serializeUrlState(query, filters, columnWidths, defaultPageSize, enableColumnResizing);
682
+ const urlStr = serializeUrlState(query, filters, columnWidths, defaultPageSizeRef.current, enableColumnResizingRef.current);
662
683
  const qs = urlStr ? `?${urlStr}` : "";
663
- window.history.replaceState(null, "", `${window.location.pathname}${qs}${window.location.hash}`);
684
+ const nextUrl = `${window.location.pathname}${qs}${window.location.hash}`;
685
+ const prevQuery = lastQueryForUrlRef.current;
686
+ const shouldPush = hasWrittenUrlRef.current && prevQuery != null && prevQuery.page !== query.page;
687
+ if (shouldPush) {
688
+ window.history.pushState(null, "", nextUrl);
689
+ } else {
690
+ window.history.replaceState(null, "", nextUrl);
691
+ }
692
+ hasWrittenUrlRef.current = true;
693
+ lastQueryForUrlRef.current = query;
664
694
  }, [
665
695
  query,
666
696
  filters,
667
697
  syncToUrl,
668
- enableColumnResizing,
669
- defaultPageSize,
670
698
  columnWidths
671
699
  ]);
672
700
  useEffect(() => {
673
- if (!syncToUrl || !enableColumnResizing) return;
674
- if (!didSkipInitialUrlSyncRef.current) return;
701
+ if (!syncToUrl || !enableColumnResizingRef.current) return;
702
+ if (!didHydrateUrlRef.current) return;
703
+ if (!hasWrittenUrlRef.current) return;
704
+ if (isApplyingUrlStateRef.current) return;
675
705
  if (urlSyncDebounceRef.current) {
676
706
  clearTimeout(urlSyncDebounceRef.current);
677
707
  }
678
708
  urlSyncDebounceRef.current = setTimeout(() => {
679
- const urlStr = serializeUrlState(query, filters, columnWidths, defaultPageSize, enableColumnResizing);
709
+ const urlStr = serializeUrlState(query, filters, columnWidths, defaultPageSizeRef.current, enableColumnResizingRef.current);
680
710
  const qs = urlStr ? `?${urlStr}` : "";
681
711
  window.history.replaceState(null, "", `${window.location.pathname}${qs}${window.location.hash}`);
682
712
  urlSyncDebounceRef.current = null;
@@ -690,36 +720,52 @@ function useUrlSync({
690
720
  }, [
691
721
  columnWidths,
692
722
  syncToUrl,
693
- enableColumnResizing,
694
723
  query,
695
- filters,
696
- defaultPageSize
724
+ filters
697
725
  ]);
698
- useEffect(() => {
699
- if (!syncToUrl) {
700
- didHydrateUrlRef.current = false;
701
- return;
726
+ function scheduleClearApplyingFlag() {
727
+ if (clearApplyingTimerRef.current) {
728
+ clearTimeout(clearApplyingTimerRef.current);
729
+ clearApplyingTimerRef.current = null;
702
730
  }
703
- if (didHydrateUrlRef.current) return;
704
- didHydrateUrlRef.current = true;
731
+ clearApplyingTimerRef.current = setTimeout(() => {
732
+ isApplyingUrlStateRef.current = false;
733
+ clearApplyingTimerRef.current = null;
734
+ }, 0);
735
+ }
736
+ function applyUrlToState() {
705
737
  const params = new URLSearchParams(window.location.search);
706
- const parsed = parseUrlState(params, defaultPageSize, pageSizeOptions);
707
- setQuery({
738
+ const parsed = parseUrlState(params, defaultPageSizeRef.current, pageSizeOptionsRef.current);
739
+ const nextQuery = {
708
740
  page: parsed.page,
709
741
  pageSize: parsed.pageSize,
710
742
  sort: parsed.sort,
711
743
  sorts: parsed.sorts,
712
744
  filters: parsed.filters
713
- });
714
- if (parsed.filters) {
715
- setFilters(parsed.filters);
745
+ };
746
+ isApplyingUrlStateRef.current = true;
747
+ scheduleClearApplyingFlag();
748
+ setQuery(nextQuery);
749
+ setFilters(parsed.filters ?? {});
750
+ if (!hasWrittenUrlRef.current) {
751
+ const urlStr = serializeUrlState(
752
+ nextQuery,
753
+ parsed.filters ?? {},
754
+ parsed.columnWidths ?? {},
755
+ defaultPageSizeRef.current,
756
+ enableColumnResizingRef.current
757
+ );
758
+ const qs = urlStr ? `?${urlStr}` : "";
759
+ window.history.replaceState(null, "", `${window.location.pathname}${qs}${window.location.hash}`);
760
+ hasWrittenUrlRef.current = true;
761
+ lastQueryForUrlRef.current = nextQuery;
716
762
  }
717
- if (parsed.columnWidths && enableColumnResizing) {
763
+ if (enableColumnResizingRef.current && parsed.columnWidths) {
718
764
  const clamped = {};
719
765
  for (const [colId, rawWidth] of Object.entries(parsed.columnWidths)) {
720
766
  const widthNum = typeof rawWidth === "number" ? rawWidth : Number(rawWidth);
721
767
  if (!Number.isFinite(widthNum)) continue;
722
- const colDef = columns.find((c) => c.id === colId);
768
+ const colDef = columnsRef.current.find((c) => c.id === colId);
723
769
  if (!colDef) continue;
724
770
  const minW = colDef.minWidth ?? 80;
725
771
  const maxW = colDef.maxWidth;
@@ -730,17 +776,44 @@ function useUrlSync({
730
776
  clamped[colId] = finalW;
731
777
  }
732
778
  setColumnWidths(clamped);
779
+ } else if (enableColumnResizingRef.current) {
780
+ setColumnWidths({});
733
781
  }
782
+ }
783
+ useEffect(() => {
784
+ if (!syncToUrl) {
785
+ didHydrateUrlRef.current = false;
786
+ hasWrittenUrlRef.current = false;
787
+ lastQueryForUrlRef.current = null;
788
+ return;
789
+ }
790
+ if (didHydrateUrlRef.current) return;
791
+ didHydrateUrlRef.current = true;
792
+ applyUrlToState();
734
793
  }, [
735
794
  syncToUrl,
736
- defaultPageSize,
737
- enableColumnResizing,
738
- pageSizeOptions,
739
- columns,
740
795
  setQuery,
741
796
  setFilters,
742
797
  setColumnWidths
743
798
  ]);
799
+ useEffect(() => {
800
+ if (!syncToUrl) return;
801
+ const onPopState = () => {
802
+ applyUrlToState();
803
+ };
804
+ window.addEventListener("popstate", onPopState);
805
+ return () => {
806
+ window.removeEventListener("popstate", onPopState);
807
+ };
808
+ }, [syncToUrl, setQuery, setFilters, setColumnWidths]);
809
+ useEffect(() => {
810
+ return () => {
811
+ if (clearApplyingTimerRef.current) {
812
+ clearTimeout(clearApplyingTimerRef.current);
813
+ clearApplyingTimerRef.current = null;
814
+ }
815
+ };
816
+ }, []);
744
817
  }
745
818
  var FOCUSABLE_SELECTORS = [
746
819
  "button",
@@ -1091,9 +1164,13 @@ function RowaKitTable({
1091
1164
  const headerChecked = isAllSelected(selectedKeys, pageRowKeys);
1092
1165
  const headerIndeterminate = isIndeterminate(selectedKeys, pageRowKeys);
1093
1166
  useEffect(() => {
1094
- if (!enableRowSelection) return;
1095
1167
  setSelectedKeys(clearSelection());
1096
- }, [enableRowSelection, query.page, dataState.items]);
1168
+ }, [query.page]);
1169
+ useEffect(() => {
1170
+ if (!enableRowSelection) {
1171
+ setSelectedKeys(clearSelection());
1172
+ }
1173
+ }, [enableRowSelection]);
1097
1174
  useEffect(() => {
1098
1175
  if (!enableRowSelection || !onSelectionChange) return;
1099
1176
  onSelectionChange(selectedKeys);
@@ -1770,7 +1847,7 @@ function RowaKitTable({
1770
1847
  var SmartTable = RowaKitTable;
1771
1848
 
1772
1849
  // src/index.ts
1773
- var VERSION = "0.5.0" ;
1850
+ var VERSION = "1.0.0" ;
1774
1851
 
1775
1852
  export { RowaKitTable, SmartTable, VERSION, col };
1776
1853
  //# sourceMappingURL=index.js.map