react-restyle-components 0.4.41 → 0.4.43

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 (20) hide show
  1. package/lib/src/core-components/src/components/AutoComplete/auto-complete-filter-group-by-multiple-select-multiple-fields-display/auto-complete-filter-group-by-multiple-select-multiple-fields-display.component.d.ts +9 -1
  2. package/lib/src/core-components/src/components/AutoComplete/auto-complete-filter-group-by-multiple-select-multiple-fields-display/auto-complete-filter-group-by-multiple-select-multiple-fields-display.component.js +165 -48
  3. package/lib/src/core-components/src/components/Icon/Icon.d.ts +9 -0
  4. package/lib/src/core-components/src/components/Icon/Icon.js +80 -0
  5. package/lib/src/core-components/src/components/Table/Table.js +141 -43
  6. package/lib/src/core-components/src/components/Table/elements.d.ts +3 -0
  7. package/lib/src/core-components/src/components/Table/elements.js +56 -0
  8. package/lib/src/core-components/src/components/Table/types.d.ts +2 -0
  9. package/lib/src/core-components/src/components/ag-grid/AgGrid.js +332 -8
  10. package/lib/src/core-components/src/components/ag-grid/elements.d.ts +136 -0
  11. package/lib/src/core-components/src/components/ag-grid/elements.js +639 -1
  12. package/lib/src/core-components/src/components/ag-grid/hooks.d.ts +80 -0
  13. package/lib/src/core-components/src/components/ag-grid/hooks.js +277 -0
  14. package/lib/src/core-components/src/components/ag-grid/index.d.ts +2 -1
  15. package/lib/src/core-components/src/components/ag-grid/index.js +2 -0
  16. package/lib/src/core-components/src/tc.global.css +28 -2
  17. package/lib/src/core-components/src/tc.module.css +1 -1
  18. package/lib/src/core-components/src/utils/designTokens.d.ts +9 -9
  19. package/lib/src/core-components/src/utils/designTokens.js +13 -10
  20. package/package.json +1 -1
@@ -209,6 +209,12 @@ export const Table = forwardRef(function TableComponent(props, ref) {
209
209
  }, [showFilterRow, isFilterVisibilityControlled, onShowFiltersChange]);
210
210
  const [editingCell, setEditingCell] = useState(null);
211
211
  const [editValue, setEditValue] = useState(null);
212
+ // Cache custom editor render to avoid repeated renders while editing the same cell
213
+ const editorRendererCacheRef = useRef(new Map());
214
+ useEffect(() => {
215
+ // Clear cache when editing target changes
216
+ editorRendererCacheRef.current.clear();
217
+ }, [editingCell]);
212
218
  const searchValue = controlledSearchValue ?? internalSearchValue;
213
219
  const debouncedSearchValue = useTableDebounce(searchValue, searchDebounce);
214
220
  // Sort state
@@ -330,7 +336,8 @@ export const Table = forwardRef(function TableComponent(props, ref) {
330
336
  // Case 1: Global search cleared, column filters exist → filters only
331
337
  // Case 2: Global search cleared, no column filters → empty filters (reload all)
332
338
  // Case 3: Specific column cleared → remaining filters
333
- onFilterRef.current?.(filterTypeRef.current, filterData, page, pageSize);
339
+ // Note: page is 0-indexed internally, but onFilter expects 1-indexed page
340
+ onFilterRef.current?.(filterTypeRef.current, filterData, page + 1, pageSize);
334
341
  // Reset the flag after processing to prevent duplicate calls
335
342
  shouldCallOnFilter.current = false;
336
343
  }, [debouncedSearchValue, filters, page, pageSize]);
@@ -458,6 +465,11 @@ export const Table = forwardRef(function TableComponent(props, ref) {
458
465
  }, [changePageSize, onPageSizeChange, onPageChange, onChange]);
459
466
  // Handle row click
460
467
  const handleRowClick = useCallback((row, rowIndex, e) => {
468
+ // Prevent clicks on disabled rows
469
+ const checkboxProps = resolvedRowSelection?.getCheckboxProps?.(row);
470
+ if (checkboxProps?.disabled) {
471
+ return;
472
+ }
461
473
  // Selection handling - only for 'single' mode (checkbox mode uses checkbox click only)
462
474
  if (resolvedRowSelection?.mode === 'single') {
463
475
  const result = toggleRow(row);
@@ -473,7 +485,7 @@ export const Table = forwardRef(function TableComponent(props, ref) {
473
485
  }
474
486
  }
475
487
  onRowClick?.(row, rowIndex, e);
476
- }, [rowSelection, expandable, toggleRow, toggleExpand, onRowClick]);
488
+ }, [rowSelection, expandable, toggleRow, toggleExpand, onRowClick, resolvedRowSelection]);
477
489
  // Helper to check if cell is editable and get custom editor
478
490
  const getCellEditableInfo = useCallback((column, row, rowIndex, colIndex) => {
479
491
  // If editorRenderer is provided, column is editable by default (unless editable explicitly returns false)
@@ -499,33 +511,85 @@ export const Table = forwardRef(function TableComponent(props, ref) {
499
511
  }, []);
500
512
  // Handle cell edit
501
513
  const handleCellDoubleClick = useCallback((row, rowIndex, column, colIndex, e) => {
514
+ // Check if row is disabled
515
+ const checkboxProps = resolvedRowSelection?.getCheckboxProps?.(row);
516
+ const isRowDisabled = !!checkboxProps?.disabled;
517
+ // Check if allowRows is provided
518
+ const hasAllowRows = resolvedRowSelection?.allowRows && resolvedRowSelection.allowRows.length > 0;
519
+ // If row is disabled and allowRows is NOT provided, block all clicks
520
+ if (isRowDisabled && !hasAllowRows) {
521
+ return;
522
+ }
523
+ // If row is disabled and allowRows IS provided, only allow clicks on columns in allowRows
524
+ if (isRowDisabled && hasAllowRows) {
525
+ const isInAllowRows = resolvedRowSelection.allowRows.includes(column.dataField);
526
+ if (!isInAllowRows) {
527
+ return;
528
+ }
529
+ }
530
+ // Check if column is editable
531
+ const { isEditable } = getCellEditableInfo(column, row, rowIndex, colIndex);
502
532
  // Call column's onDoubleClick event if defined
503
533
  column.events?.onDoubleClick?.(e, row, rowIndex, column, colIndex);
504
534
  // Handle cell editing
505
535
  if (editMode !== 'none') {
506
- const { isEditable } = getCellEditableInfo(column, row, rowIndex, colIndex);
507
- if (isEditable && editMode === 'dblclick') {
536
+ // If allowRows is provided, only allow editing for columns in allowRows
537
+ // Otherwise, allow editing for all editable columns
538
+ if (hasAllowRows) {
539
+ const isInAllowRows = resolvedRowSelection.allowRows.includes(column.dataField);
540
+ if (isInAllowRows && editMode === 'dblclick') {
541
+ setEditingCell({ row: rowIndex, field: column.dataField });
542
+ setEditValue(getNestedValue(row, column.dataField));
543
+ }
544
+ }
545
+ else if (isEditable && editMode === 'dblclick') {
508
546
  setEditingCell({ row: rowIndex, field: column.dataField });
509
547
  setEditValue(getNestedValue(row, column.dataField));
510
548
  }
511
549
  }
512
550
  // Call row double click callback
513
551
  onRowDoubleClick?.(row, rowIndex, e);
514
- }, [editMode, onRowDoubleClick, getCellEditableInfo]);
552
+ }, [editMode, onRowDoubleClick, getCellEditableInfo, resolvedRowSelection]);
515
553
  const handleCellClick = useCallback((row, rowIndex, column, colIndex, e) => {
554
+ // Check if row is disabled
555
+ const checkboxProps = resolvedRowSelection?.getCheckboxProps?.(row);
556
+ const isRowDisabled = !!checkboxProps?.disabled;
557
+ // Check if allowRows is provided
558
+ const hasAllowRows = resolvedRowSelection?.allowRows && resolvedRowSelection.allowRows.length > 0;
559
+ // If row is disabled and allowRows is NOT provided, block all clicks
560
+ if (isRowDisabled && !hasAllowRows) {
561
+ return;
562
+ }
563
+ // If row is disabled and allowRows IS provided, only allow clicks on columns in allowRows
564
+ if (isRowDisabled && hasAllowRows) {
565
+ const isInAllowRows = resolvedRowSelection.allowRows.includes(column.dataField);
566
+ if (!isInAllowRows) {
567
+ return;
568
+ }
569
+ }
570
+ // Check if column is editable
571
+ const { isEditable } = getCellEditableInfo(column, row, rowIndex, colIndex);
516
572
  // Call column's onClick event if defined
517
573
  if (e) {
518
574
  column.events?.onClick?.(e, row, rowIndex, column, colIndex);
519
575
  }
520
576
  // Handle cell editing on click
521
577
  if (editMode === 'click') {
522
- const { isEditable } = getCellEditableInfo(column, row, rowIndex, colIndex);
523
- if (isEditable) {
578
+ // If allowRows is provided, only allow editing for columns in allowRows
579
+ // Otherwise, allow editing for all editable columns
580
+ if (hasAllowRows) {
581
+ const isInAllowRows = resolvedRowSelection.allowRows.includes(column.dataField);
582
+ if (isInAllowRows) {
583
+ setEditingCell({ row: rowIndex, field: column.dataField });
584
+ setEditValue(getNestedValue(row, column.dataField));
585
+ }
586
+ }
587
+ else if (isEditable) {
524
588
  setEditingCell({ row: rowIndex, field: column.dataField });
525
589
  setEditValue(getNestedValue(row, column.dataField));
526
590
  }
527
591
  }
528
- }, [editMode, getCellEditableInfo]);
592
+ }, [editMode, getCellEditableInfo, resolvedRowSelection]);
529
593
  const handleCellEditComplete = useCallback((row, rowIndex, column) => {
530
594
  if (editingCell) {
531
595
  // Validate
@@ -724,10 +788,15 @@ export const Table = forwardRef(function TableComponent(props, ref) {
724
788
  }, [toggleAll, isAllSelected, resolvedRowSelection]);
725
789
  // Handle expand toggle
726
790
  const handleExpandClick = useCallback((row, e) => {
791
+ // Prevent expand on disabled rows
792
+ const checkboxProps = resolvedRowSelection?.getCheckboxProps?.(row);
793
+ if (checkboxProps?.disabled) {
794
+ return;
795
+ }
727
796
  e.stopPropagation();
728
797
  const result = toggleExpand(row);
729
798
  expandable?.onExpandChange?.(result.expandedKeys, result.expanded, row);
730
- }, [toggleExpand, expandable]);
799
+ }, [toggleExpand, expandable, resolvedRowSelection]);
731
800
  // Filtered column list for toggle panel - use reorderedColumns to preserve reorder state
732
801
  const filteredToggleColumns = useMemo(() => {
733
802
  return reorderedColumns.filter((c) => c.dataField !== keyField &&
@@ -744,35 +813,39 @@ export const Table = forwardRef(function TableComponent(props, ref) {
744
813
  // Check for custom editorRenderer
745
814
  if (column.editorRenderer) {
746
815
  const rowId = row[keyField];
747
- const editorProps = {
748
- value: editValue,
749
- onUpdate: (newValue) => {
750
- setEditValue(newValue);
751
- // Call onUpdateItem directly for custom editors
752
- onUpdateItem?.(newValue, column.dataField, rowId);
753
- setEditingCell(null);
754
- },
755
- onCancel: () => setEditingCell(null),
756
- onBlur: () => {
757
- // Only complete if value changed
758
- if (editValue !== value) {
759
- onUpdateItem?.(editValue, column.dataField, rowId);
760
- }
761
- setEditingCell(null);
762
- },
763
- row,
764
- column,
765
- rowIndex,
766
- columnIndex: colIndex,
767
- // Additional helpers for direct update
768
- rowId,
769
- dataField: column.dataField,
770
- onUpdateItem: (newValue) => {
771
- onUpdateItem?.(newValue, column.dataField, rowId);
772
- setEditingCell(null);
773
- },
774
- };
775
- return column.editorRenderer(editorProps, editValue, row, column, rowIndex, colIndex);
816
+ const cacheKey = `${rowId ?? rowIndex}-${column.dataField}`;
817
+ if (!editorRendererCacheRef.current.has(cacheKey)) {
818
+ const editorProps = {
819
+ value: editValue,
820
+ onUpdate: (newValue) => {
821
+ setEditValue(newValue);
822
+ // Call onUpdateItem directly for custom editors
823
+ onUpdateItem?.(newValue, column.dataField, rowId);
824
+ setEditingCell(null);
825
+ },
826
+ onCancel: () => setEditingCell(null),
827
+ onBlur: () => {
828
+ // Only complete if value changed
829
+ if (editValue !== value) {
830
+ onUpdateItem?.(editValue, column.dataField, rowId);
831
+ }
832
+ setEditingCell(null);
833
+ },
834
+ row,
835
+ column,
836
+ rowIndex,
837
+ columnIndex: colIndex,
838
+ // Additional helpers for direct update
839
+ rowId,
840
+ dataField: column.dataField,
841
+ onUpdateItem: (newValue) => {
842
+ onUpdateItem?.(newValue, column.dataField, rowId);
843
+ setEditingCell(null);
844
+ },
845
+ };
846
+ editorRendererCacheRef.current.set(cacheKey, column.editorRenderer(editorProps, editValue, row, column, rowIndex, colIndex));
847
+ }
848
+ return editorRendererCacheRef.current.get(cacheKey);
776
849
  }
777
850
  // Default editor
778
851
  return (_jsx(CellEditor, { type: column.editorType === 'number' ? 'number' : 'text', value: editValue ?? '', onChange: (e) => setEditValue(e.target.value), onBlur: () => handleCellEditComplete(row, rowIndex, column), onKeyDown: (e) => {
@@ -1297,14 +1370,18 @@ export const Table = forwardRef(function TableComponent(props, ref) {
1297
1370
  ...selectedStyle,
1298
1371
  ...disabledStyle,
1299
1372
  }, onClick: (e) => handleRowClick(row, rowIndex, e), onDoubleClick: (e) => {
1373
+ // Prevent double clicks on disabled rows
1374
+ if (checkboxProps?.disabled) {
1375
+ return;
1376
+ }
1300
1377
  // Only trigger row-level double click if not handled by a cell
1301
1378
  // Cells handle their own double-clicks for editing
1302
1379
  onRowDoubleClick?.(row, rowIndex, e);
1303
- }, role: "row", "aria-selected": rowSelected, children: [resolvedRowSelection?.mode === 'checkbox' && (_jsx(TableCell, { "$align": "center", "$compact": compact, "$padding": cellPadding, children: _jsx(Checkbox, { checked: rowSelected, disabled: checkboxProps?.disabled, onChange: (e) => handleCheckboxChange(row, e), onClick: (e) => e.stopPropagation() }) })), expandable && (_jsx(TableCell, { "$align": "center", "$compact": compact, "$padding": cellPadding, children: isExpandable && (_jsx(ExpandButton, { "$expanded": rowExpanded, onClick: (e) => handleExpandClick(row, e), children: expandable.expandIcon ? (expandable.expandIcon({
1380
+ }, role: "row", "aria-selected": rowSelected, children: [resolvedRowSelection?.mode === 'checkbox' && (_jsx(TableCell, { "$align": "center", "$compact": compact, "$padding": cellPadding, "$disabled": !!checkboxProps?.disabled, children: _jsx(Checkbox, { checked: rowSelected, disabled: checkboxProps?.disabled, onChange: (e) => handleCheckboxChange(row, e), onClick: (e) => e.stopPropagation() }) })), expandable && (_jsx(TableCell, { "$align": "center", "$compact": compact, "$padding": cellPadding, "$disabled": !!checkboxProps?.disabled, children: isExpandable && (_jsx(ExpandButton, { "$expanded": rowExpanded, onClick: (e) => handleExpandClick(row, e), children: expandable.expandIcon ? (expandable.expandIcon({
1304
1381
  expanded: rowExpanded,
1305
1382
  row,
1306
1383
  onExpand: () => toggleExpand(row),
1307
- })) : (_jsx(ExpandIcon, {})) })) })), showRowNumber && (_jsx(TableCell, { "$align": "center", "$compact": compact, "$padding": cellPadding, style: {
1384
+ })) : (_jsx(ExpandIcon, {})) })) })), showRowNumber && (_jsx(TableCell, { "$align": "center", "$compact": compact, "$padding": cellPadding, "$disabled": !!checkboxProps?.disabled, style: {
1308
1385
  width: rowNumberWidth,
1309
1386
  color: '#6b7280',
1310
1387
  fontWeight: 500,
@@ -1321,7 +1398,29 @@ export const Table = forwardRef(function TableComponent(props, ref) {
1321
1398
  const cellResizeStyle = resizable
1322
1399
  ? getColumnStyle(column, columnWidths, resizable, isResizing)
1323
1400
  : {};
1324
- return (_jsx(TableCell, { "$align": column.align || 'left', "$compact": compact, "$padding": cellPadding, "$pinned": column.pinned, "$hasCustomClass": !!cellClass, className: cellClass || classNames.cell, style: {
1401
+ // Check if column is editable (needed for disabled row handling)
1402
+ const editInfo = getCellEditableInfo(column, row, rowIndex, colIndex);
1403
+ // Check if allowRows is provided
1404
+ const hasAllowRows = resolvedRowSelection?.allowRows && resolvedRowSelection.allowRows.length > 0;
1405
+ // Check if column is in allowRows (allowed to edit even when row is disabled)
1406
+ const isInAllowRows = !!(hasAllowRows && resolvedRowSelection.allowRows.includes(column.dataField));
1407
+ // Determine if column is effectively editable:
1408
+ // - If row is disabled and allowRows is NOT provided: NOT editable (even if marked as editable)
1409
+ // - If row is disabled and allowRows IS provided: editable only if in allowRows
1410
+ // - If row is NOT disabled: editable if marked as editable
1411
+ const isRowDisabled = !!checkboxProps?.disabled;
1412
+ let isEffectivelyEditable = editInfo.isEditable;
1413
+ if (isRowDisabled) {
1414
+ if (!hasAllowRows) {
1415
+ // No allowRows provided: disable all columns
1416
+ isEffectivelyEditable = false;
1417
+ }
1418
+ else {
1419
+ // allowRows provided: only columns in allowRows are editable
1420
+ isEffectivelyEditable = isInAllowRows;
1421
+ }
1422
+ }
1423
+ return (_jsx(TableCell, { "$align": column.align || 'left', "$compact": compact, "$padding": cellPadding, "$pinned": column.pinned, "$hasCustomClass": !!cellClass, "$disabled": !!checkboxProps?.disabled, "$isEditable": isEffectivelyEditable, "$isInAllowRows": isInAllowRows, className: cellClass || classNames.cell, style: {
1325
1424
  ...styles.cell,
1326
1425
  ...cellStyle,
1327
1426
  ...cellResizeStyle,
@@ -1329,8 +1428,7 @@ export const Table = forwardRef(function TableComponent(props, ref) {
1329
1428
  e.stopPropagation(); // Prevent row-level double-click from interfering
1330
1429
  handleCellDoubleClick(row, rowIndex, column, colIndex, e);
1331
1430
  }, role: "gridcell", children: (() => {
1332
- const editInfo = getCellEditableInfo(column, row, rowIndex, colIndex);
1333
- if (editInfo.isEditable &&
1431
+ if (isEffectivelyEditable &&
1334
1432
  editMode !== 'none') {
1335
1433
  // Check for custom editor
1336
1434
  if (editInfo.customEditor) {
@@ -62,6 +62,9 @@ export declare const TableCell: import("styled-components/dist/types").IStyledCo
62
62
  $pinned?: false | "left" | "right" | undefined;
63
63
  $padding?: string | undefined;
64
64
  $hasCustomClass?: boolean | undefined;
65
+ $disabled?: boolean | undefined;
66
+ $isEditable?: boolean | undefined;
67
+ $isInAllowRows?: boolean | undefined;
65
68
  }>> & string;
66
69
  export declare const Checkbox: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("styled-components").FastOmit<import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, Omit<import("react").DetailedHTMLProps<import("react").InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref"> & {
67
70
  ref?: ((instance: HTMLInputElement | null) => void) | import("react").RefObject<HTMLInputElement> | null | undefined;
@@ -412,6 +412,7 @@ export const TableRow = styled.tr `
412
412
  opacity: 0.5;
413
413
  background: ${tokens.surface || '#e5e7eb'} !important;
414
414
  color: ${tokens.onSurface || '#1f2937'};
415
+ cursor: not-allowed;
415
416
 
416
417
  &:hover {
417
418
  background: ${tokens.surface || '#e5e7eb'} !important;
@@ -446,6 +447,61 @@ export const TableCell = styled.td `
446
447
  css `
447
448
  border-left: 2px solid #d1d5db;
448
449
  `}
450
+
451
+ /* Ensure formatter content displays properly */
452
+ /* Make direct children inline-block by default (for Icon components, etc.) */
453
+ /* But preserve flex/grid/block layouts when explicitly set */
454
+ > * {
455
+ display: inline-block;
456
+ vertical-align: middle;
457
+ }
458
+
459
+ /* Preserve flex layouts - these take precedence */
460
+ > [class*="flex"],
461
+ > [style*="display: flex"],
462
+ > [style*="display:flex"],
463
+ > div[class*="flex"],
464
+ > div[style*="display: flex"],
465
+ > div[style*="display:flex"] {
466
+ display: flex !important;
467
+ }
468
+
469
+ /* Preserve grid layouts */
470
+ > [class*="grid"],
471
+ > [style*="display: grid"],
472
+ > [style*="display:grid"] {
473
+ display: grid !important;
474
+ }
475
+
476
+ /* Preserve block layouts */
477
+ > [class*="block"],
478
+ > [style*="display: block"],
479
+ > [style*="display:block"] {
480
+ display: block !important;
481
+ }
482
+
483
+ /* Disabled state - prevent clicks and show not-allowed cursor */
484
+ /* Only apply pointer-events: none if row is disabled AND column is NOT effectively editable */
485
+ ${({ $disabled, $isEditable }) => $disabled &&
486
+ !$isEditable &&
487
+ css `
488
+ cursor: not-allowed;
489
+ pointer-events: none;
490
+ `}
491
+
492
+ /* If row is disabled but column is effectively editable, show default cursor */
493
+ ${({ $disabled, $isEditable }) => $disabled &&
494
+ $isEditable &&
495
+ css `
496
+ cursor: default;
497
+ `}
498
+
499
+ /* Remove opacity for columns in allowRows when row is disabled */
500
+ ${({ $disabled, $isInAllowRows }) => $disabled &&
501
+ $isInAllowRows &&
502
+ css `
503
+ opacity: 1 !important;
504
+ `}
449
505
  `;
450
506
  export const Checkbox = styled.input.attrs({ type: 'checkbox' }) `
451
507
  width: 16px;
@@ -229,6 +229,8 @@ export interface TableSelectionConfig<T = any> {
229
229
  columnWidth?: number | string;
230
230
  /** Column title */
231
231
  columnTitle?: React.ReactNode;
232
+ /** Array of column dataField values that should remain editable and without opacity when row is disabled */
233
+ allowRows?: string[];
232
234
  }
233
235
  /** Row expand config */
234
236
  export interface TableExpandConfig<T = any> {