@dmsi/wedgekit-react 0.0.28 → 0.0.30

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.
Files changed (43) hide show
  1. package/dist/{chunk-57WRM337.js → chunk-5POWRPIO.js} +3 -2
  2. package/dist/{chunk-S5KPS4IQ.js → chunk-HXEPUO5W.js} +189 -95
  3. package/dist/chunk-KHQX42T7.js +127 -0
  4. package/dist/{chunk-OUSNH76S.js → chunk-PCCJ7L3N.js} +29 -6
  5. package/dist/{chunk-PDDZ5PMY.js → chunk-S46RZBT4.js} +3 -2
  6. package/dist/components/CalendarRange.cjs +28 -5
  7. package/dist/components/CalendarRange.js +1 -1
  8. package/dist/components/DataGrid.cjs +490 -217
  9. package/dist/components/DataGrid.js +303 -122
  10. package/dist/components/DataGridCell.cjs +192 -96
  11. package/dist/components/DataGridCell.js +4 -2
  12. package/dist/components/DateInput.cjs +231 -30
  13. package/dist/components/DateInput.js +101 -27
  14. package/dist/components/DateRangeInput.cjs +550 -37
  15. package/dist/components/DateRangeInput.js +413 -34
  16. package/dist/components/MenuOption.cjs +3 -2
  17. package/dist/components/MenuOption.js +1 -1
  18. package/dist/components/MobileDataGrid.cjs +3 -2
  19. package/dist/components/MobileDataGrid.js +1 -1
  20. package/dist/components/NestedMenu.cjs +3 -2
  21. package/dist/components/NestedMenu.js +1 -1
  22. package/dist/components/Notification.cjs +3 -2
  23. package/dist/components/Notification.js +1 -1
  24. package/dist/components/SideMenuGroup.cjs +3 -2
  25. package/dist/components/SideMenuGroup.js +1 -1
  26. package/dist/components/SideMenuItem.cjs +3 -2
  27. package/dist/components/SideMenuItem.js +1 -1
  28. package/dist/components/Stack.cjs +3 -2
  29. package/dist/components/Stack.js +1 -1
  30. package/dist/components/Swatch.cjs +3 -2
  31. package/dist/components/Swatch.js +1 -1
  32. package/dist/components/Time.cjs +3 -2
  33. package/dist/components/Time.js +1 -1
  34. package/dist/index.css +9 -0
  35. package/package.json +1 -1
  36. package/src/components/CalendarRange.tsx +37 -6
  37. package/src/components/DataGrid.tsx +284 -48
  38. package/src/components/DataGridCell.tsx +122 -35
  39. package/src/components/DateInput.tsx +118 -25
  40. package/src/components/DateRangeInput.tsx +544 -30
  41. package/src/components/MenuOption.tsx +18 -14
  42. package/src/components/Stack.tsx +4 -2
  43. package/src/utils/date.ts +206 -0
@@ -4,6 +4,7 @@ import React, { ReactNode, useCallback, useId, useRef, useState } from "react";
4
4
 
5
5
  // TanStack Table
6
6
  import {
7
+ Cell,
7
8
  Column,
8
9
  ColumnDef,
9
10
  ColumnFiltersState,
@@ -13,6 +14,7 @@ import {
13
14
  getFilteredRowModel,
14
15
  getSortedRowModel,
15
16
  Header,
17
+ HeaderGroup,
16
18
  PartialKeys,
17
19
  RowData,
18
20
  SortDirection,
@@ -50,6 +52,7 @@ import { restrictToHorizontalAxis } from "@dnd-kit/modifiers";
50
52
  import { Button } from "./Button";
51
53
  import { Checkbox } from "./Checkbox";
52
54
  import {
55
+ DataCellHeader,
53
56
  DataGridCell,
54
57
  DragAlongCell,
55
58
  DraggableCellHeader,
@@ -118,6 +121,8 @@ export interface DataGridProps<T extends Record<string, unknown>> {
118
121
  hideStatusBar?: boolean;
119
122
  centerHeader?: boolean;
120
123
  enableColumnSelector?: boolean;
124
+ predeterminedLeftPins?: string[];
125
+ predeterminedRightPins?: string[];
121
126
  }
122
127
 
123
128
  export function DataGrid<T extends Record<string, unknown>>({
@@ -141,6 +146,8 @@ export function DataGrid<T extends Record<string, unknown>>({
141
146
  hideStatusBar,
142
147
  centerHeader,
143
148
  enableColumnSelector,
149
+ predeterminedLeftPins = [],
150
+ predeterminedRightPins = []
144
151
  }: DataGridProps<T>) {
145
152
  const [columnOrder, setColumnOrder] = useState<string[]>(() =>
146
153
  columns.map((c) => c.id!),
@@ -256,19 +263,39 @@ export function DataGrid<T extends Record<string, unknown>>({
256
263
  rowSelection,
257
264
  columnVisibility,
258
265
  },
266
+ initialState: {
267
+ columnPinning: {
268
+ left: predeterminedLeftPins,
269
+ right: predeterminedRightPins,
270
+ }
271
+ },
259
272
  onColumnOrderChange: setColumnOrder,
260
273
  onSortingChange: adaptTableStateSetter(setSortingState),
261
274
  onColumnFiltersChange: adaptTableStateSetter(setColumnFilterState),
262
275
  onRowSelectionChange: adaptTableStateSetter(setRowSelection),
263
276
  filterFns: {
264
- startsWith: (row, columnId, filterValue) =>
265
- (row.getValue(columnId) as string)
266
- ?.toLowerCase()
267
- .startsWith(filterValue.toLowerCase()),
268
- endsWith: (row, columnId, filterValue) =>
269
- (row.getValue(columnId) as string)
270
- ?.toLowerCase()
271
- .endsWith(filterValue.toLowerCase()),
277
+ startsWith: (row, columnId, filterValue) => {
278
+ const cellValue = row?.getValue(columnId);
279
+
280
+ if (!cellValue || !filterValue) {
281
+ return true
282
+ }
283
+
284
+ return String(cellValue)
285
+ .toLowerCase()
286
+ .startsWith(String(filterValue).toLowerCase());
287
+ },
288
+ endsWith: (row, columnId, filterValue) => {
289
+ const cellValue = row?.getValue(columnId);
290
+
291
+ if (!cellValue || !filterValue) {
292
+ return true
293
+ }
294
+
295
+ return String(cellValue)
296
+ .toLowerCase()
297
+ .endsWith(String(filterValue).toLowerCase());
298
+ },
272
299
  },
273
300
  });
274
301
 
@@ -353,6 +380,8 @@ export function DataGrid<T extends Record<string, unknown>>({
353
380
  (virtualColumns[virtualColumns.length - 1]?.end ?? 0);
354
381
  }
355
382
 
383
+ const empty = table.getRowModel().rows.length === 0;
384
+
356
385
  return (
357
386
  <DndContext
358
387
  id={dndId}
@@ -370,12 +399,26 @@ export function DataGrid<T extends Record<string, unknown>>({
370
399
  className="flex flex-col flex-1 h-full w-full rounded border border-border-primary-normal overflow-hidden text-text-primary-normal"
371
400
  >
372
401
  <div
373
- className="overflow-auto scrollbar-thin relative contain-paint will-change-transform"
402
+ className={clsx(
403
+ "flex overflow-auto scrollbar-thin relative contain-paint will-change-transform",
404
+ empty ? "overflow-y-hidden" : "h-full"
405
+ )}
374
406
  ref={containerRef}
375
407
  >
376
- <table className="min-w-full grid">
408
+ <PinnedColumns
409
+ pinDirection="left"
410
+ table={table}
411
+ tableContainerRef={containerRef}
412
+ pagination={pagination}
413
+ isLoadingMore={isLoadingMore}
414
+ hasMore={hasMore}
415
+ showFilterRow={showFilterRow}
416
+ enableColumnSelector={enableColumnSelector}
417
+ />
418
+
419
+ <table className="flex-1 grid min-h-min">
377
420
  <thead className="sticky top-0 z-10 grid">
378
- {table.getHeaderGroups().map((headerGroup) => (
421
+ {table.getCenterHeaderGroups().map((headerGroup) => (
379
422
  <tr key={headerGroup.id} className="flex w-full">
380
423
  {virtualPaddingLeft ? (
381
424
  // fake empty column to the left for virtualization scroll padding
@@ -386,6 +429,10 @@ export function DataGrid<T extends Record<string, unknown>>({
386
429
 
387
430
  {virtualColumns.map((virtualColumn) => {
388
431
  const header = headerGroup.headers[virtualColumn.index];
432
+ if (!header) {
433
+ return;
434
+ }
435
+
389
436
  if (typeof header.column.columnDef.header === "string") {
390
437
  const customHeaderWidth =
391
438
  header.column.columnDef.meta?.headerWidth;
@@ -425,23 +472,21 @@ export function DataGrid<T extends Record<string, unknown>>({
425
472
  </Subheader>
426
473
  )}
427
474
 
428
- {!header.column.columnDef.meta?.locked && (
429
- <div
430
- onDoubleClick={(e) => {
431
- e.stopPropagation();
432
- header.column.resetSize();
433
- }}
434
- onMouseDown={(e) => {
435
- e.stopPropagation();
436
- header.getResizeHandler()(e);
437
- }}
438
- onTouchStart={(e) => {
439
- e.stopPropagation();
440
- header.getResizeHandler()(e);
441
- }}
442
- className="absolute right-0 inset-y-0 w-px bg-black cursor-col-resize"
443
- />
444
- )}
475
+ <div
476
+ onDoubleClick={(e) => {
477
+ e.stopPropagation();
478
+ header.column.resetSize();
479
+ }}
480
+ onMouseDown={(e) => {
481
+ e.stopPropagation();
482
+ header.getResizeHandler()(e);
483
+ }}
484
+ onTouchStart={(e) => {
485
+ e.stopPropagation();
486
+ header.getResizeHandler()(e);
487
+ }}
488
+ className="absolute right-0 inset-y-0 w-px bg-black cursor-col-resize"
489
+ />
445
490
  </DraggableCellHeader>
446
491
  );
447
492
  }
@@ -505,9 +550,20 @@ export function DataGrid<T extends Record<string, unknown>>({
505
550
  enableColumnSelector={enableColumnSelector}
506
551
  />
507
552
  </table>
553
+
554
+ <PinnedColumns
555
+ pinDirection="right"
556
+ table={table}
557
+ tableContainerRef={containerRef}
558
+ pagination={pagination}
559
+ isLoadingMore={isLoadingMore}
560
+ hasMore={hasMore}
561
+ showFilterRow={showFilterRow}
562
+ enableColumnSelector={enableColumnSelector}
563
+ />
508
564
  </div>
509
565
 
510
- {table.getRowModel().rows.length === 0 && (
566
+ {empty && (
511
567
  <div
512
568
  className={clsx(
513
569
  NO_RESULTS_HEIGHT,
@@ -611,16 +667,18 @@ DataGrid.displayName = "DataGrid";
611
667
 
612
668
  interface TableBodyProps<TData extends RowData> {
613
669
  id?: string;
614
- columnVirtualizer: Virtualizer<HTMLDivElement, HTMLTableCellElement>;
670
+ columnVirtualizer?: Virtualizer<HTMLDivElement, HTMLTableCellElement>;
615
671
  table: Table<TData>;
616
672
  tableContainerRef: React.RefObject<HTMLDivElement | null>;
617
- virtualPaddingLeft: number | undefined;
618
- virtualPaddingRight: number | undefined;
673
+ virtualPaddingLeft?: number | undefined;
674
+ virtualPaddingRight?: number | undefined;
619
675
  pagination: DataGridPagination | undefined;
620
676
  isLoadingMore: boolean;
621
677
  hasMore: boolean;
622
678
  showFilterRow: boolean;
623
679
  enableColumnSelector?: boolean;
680
+ locked?: boolean;
681
+ pinDirection?: 'left' | 'right';
624
682
  }
625
683
 
626
684
  // Helpers
@@ -637,6 +695,8 @@ function TableBody<T>({
637
695
  hasMore,
638
696
  showFilterRow,
639
697
  enableColumnSelector = false,
698
+ locked,
699
+ pinDirection,
640
700
  }: TableBodyProps<T>) {
641
701
  const { rows } = table.getRowModel();
642
702
 
@@ -648,9 +708,20 @@ function TableBody<T>({
648
708
  });
649
709
 
650
710
  const virtualRows = rowVirtualizer.getVirtualItems();
711
+ const CellElement = locked ? DataGridCell : DragAlongCell;
712
+
713
+ let headerGroups: HeaderGroup<T>[];
714
+ if (pinDirection === 'left') {
715
+ headerGroups = table.getLeftHeaderGroups();
716
+ } else if (pinDirection === 'right') {
717
+ headerGroups = table.getRightHeaderGroups();
718
+ } else {
719
+ headerGroups = table.getCenterHeaderGroups();
720
+ }
651
721
 
652
722
  return (
653
723
  <tbody
724
+ className={clsx(locked ? "shadow-16" : "")}
654
725
  style={{
655
726
  display: "grid",
656
727
  height: `${
@@ -673,14 +744,14 @@ function TableBody<T>({
673
744
  }}
674
745
  className="even:bg-background-grouped-primary-normal odd:bg-background-grouped-secondary-normal"
675
746
  >
676
- {table.getHeaderGroups().flatMap((x) =>
747
+ {headerGroups.flatMap((x) =>
677
748
  x.headers.map((header) => (
678
- <DragAlongCell
749
+ <CellElement
679
750
  id={id ? `${id}-filter-cell-${header.id}` : undefined}
680
751
  noPadding
681
752
  key={header.id}
682
753
  cell={header}
683
- width={header.column.columnDef.meta?.headerWidth}
754
+ width={header.column.columnDef.meta?.headerWidth || (locked ? `${header.column.getSize()}px` : '')}
684
755
  >
685
756
  {header.column.getCanFilter() &&
686
757
  (header.column.columnDef.meta?.filterRowCell?.({
@@ -698,7 +769,7 @@ function TableBody<T>({
698
769
  removeSearchIcon
699
770
  />
700
771
  ))}
701
- </DragAlongCell>
772
+ </CellElement>
702
773
  )),
703
774
  )}
704
775
  </tr>
@@ -719,6 +790,8 @@ function TableBody<T>({
719
790
  virtualRow={virtualRow}
720
791
  showFilterRow={showFilterRow}
721
792
  enableColumnSelector={enableColumnSelector}
793
+ locked={locked}
794
+ pinDirection={pinDirection}
722
795
  />
723
796
  );
724
797
  })}
@@ -746,14 +819,16 @@ function TableBody<T>({
746
819
 
747
820
  interface TableBodyRowProps<T> {
748
821
  id?: string;
749
- columnVirtualizer: Virtualizer<HTMLDivElement, HTMLTableCellElement>;
822
+ columnVirtualizer?: Virtualizer<HTMLDivElement, HTMLTableCellElement>;
750
823
  row: Row<T>;
751
824
  rowVirtualizer: Virtualizer<HTMLDivElement, HTMLTableRowElement>;
752
- virtualPaddingLeft: number | undefined;
753
- virtualPaddingRight: number | undefined;
825
+ virtualPaddingLeft?: number | undefined;
826
+ virtualPaddingRight?: number | undefined;
754
827
  virtualRow: VirtualItem;
755
828
  showFilterRow: boolean;
756
829
  enableColumnSelector?: boolean;
830
+ locked?: boolean;
831
+ pinDirection?: 'left' | 'right';
757
832
  }
758
833
 
759
834
  function TableBodyRow<T>({
@@ -766,15 +841,29 @@ function TableBodyRow<T>({
766
841
  virtualRow,
767
842
  showFilterRow,
768
843
  enableColumnSelector = false,
844
+ locked,
845
+ pinDirection,
769
846
  }: TableBodyRowProps<T>) {
770
- const visibleCells = row.getVisibleCells();
771
- const virtualColumns = columnVirtualizer.getVirtualItems();
847
+ let visibleCells: Cell<T, unknown>[];
848
+
849
+ if (locked) {
850
+ visibleCells = pinDirection === 'left'
851
+ ? row.getLeftVisibleCells()
852
+ : row.getRightVisibleCells();
853
+ } else {
854
+ visibleCells = row.getCenterVisibleCells();
855
+ }
856
+
857
+ const virtualColumns = columnVirtualizer?.getVirtualItems() ?? [];
858
+ const columns = locked ? visibleCells : virtualColumns;
772
859
 
773
860
  const isError =
774
861
  typeof row.original === "object" &&
775
862
  row.original !== null &&
776
863
  "rowState" in row.original &&
777
864
  row.original.rowState === "error";
865
+
866
+ const CellElement = locked ? DataGridCell : DragAlongCell;
778
867
 
779
868
  return (
780
869
  <tr
@@ -796,19 +885,26 @@ function TableBodyRow<T>({
796
885
  width: "100%",
797
886
  }}
798
887
  >
799
- {virtualPaddingLeft ? (
888
+ {!locked && virtualPaddingLeft ? (
800
889
  // fake empty column to the left for virtualization scroll padding
801
890
  <td style={{ display: "flex", width: virtualPaddingLeft }} />
802
891
  ) : null}
803
892
 
804
- {virtualColumns.map((virtualColumn) => {
805
- const cell = visibleCells[virtualColumn.index];
893
+ {columns.map((column) => {
894
+ const cell = locked
895
+ ? (column as Cell<T, unknown>)
896
+ : visibleCells[(column as VirtualItem).index];
897
+
898
+ if (!cell) {
899
+ return;
900
+ }
901
+
806
902
  return cell.column.columnDef.meta?.useCustomRenderer ? (
807
903
  <React.Fragment key={cell.id}>
808
904
  {flexRender(cell.column.columnDef.cell, cell.getContext())}
809
905
  </React.Fragment>
810
906
  ) : (
811
- <DragAlongCell
907
+ <CellElement
812
908
  key={cell.id}
813
909
  id={id ? `${id}-cell-${cell.id}` : undefined}
814
910
  cell={cell}
@@ -823,20 +919,160 @@ function TableBodyRow<T>({
823
919
  {cell.getValue() as ReactNode | string}
824
920
  </Paragraph>
825
921
  </Tooltip>
826
- </DragAlongCell>
922
+ </CellElement>
827
923
  );
828
924
  })}
829
925
 
830
- {virtualPaddingRight ? (
926
+ {!locked && virtualPaddingRight ? (
831
927
  // fake empty column to the right for virtualization scroll padding
832
928
  <td style={{ display: "flex", width: virtualPaddingRight }} />
833
929
  ) : null}
834
930
 
835
- {enableColumnSelector && <td></td>}
931
+ {enableColumnSelector && !locked && <td className="p-2" style={{ width: '48.8px' }}></td>}
836
932
  </tr>
837
933
  );
838
934
  }
839
935
 
936
+
937
+ interface PinnedColumnsProps<TData extends RowData> {
938
+ pinDirection: 'left' | 'right';
939
+ table: Table<TData>;
940
+ tableContainerRef: React.RefObject<HTMLDivElement | null>;
941
+ pagination: DataGridPagination | undefined;
942
+ isLoadingMore: boolean;
943
+ hasMore: boolean;
944
+ showFilterRow: boolean;
945
+ enableColumnSelector?: boolean;
946
+ centerHeader?: boolean;
947
+ allSelectedAcrossPages?: boolean;
948
+ someSelectedAcrossPages?: boolean;
949
+ toggleSelectAllAcrossPages?: () => void;
950
+ }
951
+
952
+ function PinnedColumns<TData>({
953
+ pinDirection = "left",
954
+ table,
955
+ centerHeader,
956
+ allSelectedAcrossPages,
957
+ someSelectedAcrossPages,
958
+ toggleSelectAllAcrossPages,
959
+ ...props
960
+ } : PinnedColumnsProps<TData>) {
961
+ const headerGroups = pinDirection === "left"
962
+ ? table.getLeftHeaderGroups()
963
+ : table.getRightHeaderGroups();
964
+
965
+ return headerGroups[0]?.headers.length > 0 && (
966
+ <table className={clsx(
967
+ "grid min-h-min sticky z-20 bg-background-grouped-primary-normal",
968
+ pinDirection === "left" ? "left-0" : "right-0"
969
+ )}>
970
+ <thead className="sticky top-0 z-20 grid">
971
+ {headerGroups.map((headerGroup) => {
972
+ return (
973
+ <tr key={headerGroup.id} className="flex w-full">
974
+ {headerGroup.headers.map((header) => {
975
+
976
+ if (!header) {
977
+ return;
978
+ }
979
+
980
+ if (typeof header.column.columnDef.header === "string") {
981
+ const customHeaderWidth =
982
+ header.column.columnDef.meta?.headerWidth;
983
+
984
+ return (
985
+ <DataCellHeader
986
+ locked
987
+ key={header.id}
988
+ header={header}
989
+ center={centerHeader}
990
+ width={customHeaderWidth}
991
+ className={clsx(
992
+ header.column.getCanSort()
993
+ ? "cursor-pointer"
994
+ : "cursor-grab",
995
+ "group",
996
+ )}
997
+ >
998
+ <Subheader tall>
999
+ {header.column.columnDef.header}
1000
+ </Subheader>
1001
+
1002
+ {getSortIcon(header.column.getIsSorted())}
1003
+
1004
+ {!header.column.getIsSorted() &&
1005
+ header.column.getCanSort() &&
1006
+ getSortIcon(
1007
+ header.column.getNextSortingOrder(),
1008
+ true,
1009
+ )}
1010
+
1011
+ {header.column.getSortIndex() !== -1 &&
1012
+ table.getState().sorting.length > 1 && (
1013
+ <Subheader tall>
1014
+ {header.column.getSortIndex() + 1}
1015
+ </Subheader>
1016
+ )}
1017
+
1018
+ {!header.column.columnDef.meta?.locked && (
1019
+ <div
1020
+ onDoubleClick={(e) => {
1021
+ e.stopPropagation();
1022
+ header.column.resetSize();
1023
+ }}
1024
+ onMouseDown={(e) => {
1025
+ e.stopPropagation();
1026
+ header.getResizeHandler()(e);
1027
+ }}
1028
+ onTouchStart={(e) => {
1029
+ e.stopPropagation();
1030
+ header.getResizeHandler()(e);
1031
+ }}
1032
+ className="absolute right-0 inset-y-0 w-px bg-black cursor-col-resize"
1033
+ />
1034
+ )}
1035
+ </DataCellHeader>
1036
+ );
1037
+ }
1038
+ return (
1039
+ <React.Fragment key={header.id}>
1040
+ {header.column.columnDef.meta?.checkbox ? (
1041
+ <DataGridCell
1042
+ type="header"
1043
+ component="checkbox"
1044
+ locked
1045
+ >
1046
+ <Checkbox
1047
+ checked={allSelectedAcrossPages}
1048
+ indeterminate={someSelectedAcrossPages}
1049
+ onChange={toggleSelectAllAcrossPages}
1050
+ />
1051
+ </DataGridCell>
1052
+ ) : (
1053
+ flexRender(
1054
+ header.column.columnDef.header,
1055
+ header.getContext(),
1056
+ )
1057
+ )}
1058
+ </React.Fragment>
1059
+ );
1060
+ })}
1061
+ </tr>
1062
+ )
1063
+ })}
1064
+ </thead>
1065
+
1066
+ <TableBody
1067
+ {...props}
1068
+ table={table}
1069
+ locked={true}
1070
+ pinDirection={pinDirection}
1071
+ />
1072
+ </table>
1073
+ )
1074
+ }
1075
+
840
1076
  const LoadingCell = <T extends RowData>({
841
1077
  id,
842
1078
  column,