trotl-table 1.0.11 → 1.0.13

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.cjs.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var React = require('react');
5
+ var React$1 = require('react');
6
6
  var reactDnd = require('react-dnd');
7
7
  var reactDndHtml5Backend = require('react-dnd-html5-backend');
8
8
 
@@ -23,7 +23,7 @@ function _interopNamespaceDefault(e) {
23
23
  return Object.freeze(n);
24
24
  }
25
25
 
26
- var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
26
+ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React$1);
27
27
 
28
28
  function _classCallCheck(a, n) {
29
29
  if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
@@ -912,7 +912,7 @@ var CellMeasurer = /*#__PURE__*/function (_React$PureComponent) {
912
912
  if (resolvedChildren === null) {
913
913
  return resolvedChildren;
914
914
  }
915
- return /*#__PURE__*/React.cloneElement(resolvedChildren, {
915
+ return /*#__PURE__*/React$1.cloneElement(resolvedChildren, {
916
916
  ref: function ref(node) {
917
917
  if (typeof resolvedChildren.ref === 'function') {
918
918
  resolvedChildren.ref(node);
@@ -4140,7 +4140,7 @@ function defaultCellRangeRenderer(_ref /*:: */) {
4140
4140
  warnAboutMissingStyle(parent, renderedCell);
4141
4141
  }
4142
4142
  if (!renderedCell.props.role) {
4143
- renderedCell = /*#__PURE__*/React.cloneElement(renderedCell, {
4143
+ renderedCell = /*#__PURE__*/React$1.cloneElement(renderedCell, {
4144
4144
  role: 'gridcell'
4145
4145
  });
4146
4146
  }
@@ -9555,7 +9555,7 @@ const Modal = ({
9555
9555
  closeOnEscape = true,
9556
9556
  closeOnOutsideClick = true
9557
9557
  }) => {
9558
- React.useEffect(() => {
9558
+ React$1.useEffect(() => {
9559
9559
  const handleKey = e => {
9560
9560
  if (e.key === 'Escape' && closeOnEscape) {
9561
9561
  onCancel?.();
@@ -9565,22 +9565,22 @@ const Modal = ({
9565
9565
  return () => document.removeEventListener('keydown', handleKey);
9566
9566
  }, [closeOnEscape, onCancel]);
9567
9567
  if (!isOpen) return null;
9568
- return /*#__PURE__*/React.createElement("div", {
9568
+ return /*#__PURE__*/React$1.createElement("div", {
9569
9569
  className: "modal-overlay",
9570
9570
  onClick: closeOnOutsideClick ? onCancel : undefined
9571
- }, /*#__PURE__*/React.createElement("div", {
9571
+ }, /*#__PURE__*/React$1.createElement("div", {
9572
9572
  className: "modal-box",
9573
9573
  onClick: e => e.stopPropagation()
9574
- }, /*#__PURE__*/React.createElement("h3", {
9574
+ }, /*#__PURE__*/React$1.createElement("h3", {
9575
9575
  className: "modal-title"
9576
- }, title), /*#__PURE__*/React.createElement("div", {
9576
+ }, title), /*#__PURE__*/React$1.createElement("div", {
9577
9577
  className: "modal-content"
9578
- }, children), /*#__PURE__*/React.createElement("div", {
9578
+ }, children), /*#__PURE__*/React$1.createElement("div", {
9579
9579
  className: "modal-actions"
9580
- }, showCancel && /*#__PURE__*/React.createElement("button", {
9580
+ }, showCancel && /*#__PURE__*/React$1.createElement("button", {
9581
9581
  className: "basic-button cancel",
9582
9582
  onClick: onCancel
9583
- }, cancelLabel), showConfirm && /*#__PURE__*/React.createElement("button", {
9583
+ }, cancelLabel), showConfirm && /*#__PURE__*/React$1.createElement("button", {
9584
9584
  className: "basic-button confirm",
9585
9585
  onClick: onConfirm
9586
9586
  }, confirmLabel))));
@@ -9612,16 +9612,16 @@ const DraggableRow = ({
9612
9612
  index,
9613
9613
  moveRow,
9614
9614
  children,
9615
- item,
9615
+ row,
9616
+ tableId,
9616
9617
  enableDrag,
9617
9618
  listRef
9618
9619
  }) => {
9619
- const ref = React.useRef(null);
9620
+ const ref = React$1.useRef(null);
9620
9621
  const [, drop] = reactDnd.useDrop({
9621
9622
  accept: ITEM_TYPE,
9622
9623
  hover(draggedItem, monitor) {
9623
9624
  if (!ref.current || !enableDrag) return;
9624
- ref.current.getBoundingClientRect();
9625
9625
  const clientOffset = monitor.getClientOffset();
9626
9626
 
9627
9627
  // Auto-scroll logic
@@ -9651,23 +9651,31 @@ const DraggableRow = ({
9651
9651
  }, drag] = reactDnd.useDrag({
9652
9652
  type: ITEM_TYPE,
9653
9653
  item: {
9654
- index
9654
+ index,
9655
+ row,
9656
+ sourceTableId: tableId
9655
9657
  },
9656
9658
  canDrag: enableDrag,
9657
9659
  collect: monitor => ({
9658
9660
  isDragging: monitor.isDragging()
9659
9661
  })
9660
9662
  });
9661
- drag(drop(ref));
9662
- return /*#__PURE__*/React.createElement("div", {
9663
- ref: ref,
9663
+ // Compose drag & drop refs in effect to avoid reading ref during render
9664
+ const setRef = React$1.useCallback(node => {
9665
+ if (node) {
9666
+ ref.current = node;
9667
+ drag(drop(node));
9668
+ }
9669
+ }, [drag, drop]);
9670
+ return /*#__PURE__*/React$1.createElement("div", {
9671
+ ref: setRef,
9664
9672
  style: {
9665
9673
  opacity: isDragging ? 0.5 : 1,
9666
9674
  cursor: enableDrag ? "move" : "default"
9667
9675
  }
9668
9676
  }, children);
9669
9677
  };
9670
- function Table({
9678
+ function TableInner({
9671
9679
  tableId = "default",
9672
9680
  columns = [],
9673
9681
  data = [],
@@ -9684,17 +9692,22 @@ function Table({
9684
9692
  deleteCallback = null,
9685
9693
  buttons = ["view", "edit", "delete"],
9686
9694
  enableDragRow = false,
9687
- enableSearchUrlParam = false
9695
+ enableSearchUrlParam = false,
9696
+ enableMultiSelect = false,
9697
+ enableExternalRowDrop = false,
9698
+ onExternalRowDrop = () => {},
9699
+ useExternalDndContext = false,
9700
+ customColumns = []
9688
9701
  }) {
9689
9702
  // Local selection & sorting state (removed TableContext dependency)
9690
- const [selectedRows, setSelectedRows] = React.useState([]);
9691
- const [sorting, setSorting] = React.useState(null);
9703
+ const [selectedRows, setSelectedRows] = React$1.useState([]);
9704
+ const [sorting, setSorting] = React$1.useState(null);
9692
9705
 
9693
9706
  // Option to read search param from URL
9694
- const [searchTerm, setSearchTerm] = React.useState(extraSearchTerm);
9707
+ const [searchTerm, setSearchTerm] = React$1.useState(extraSearchTerm);
9695
9708
 
9696
9709
  // Listen to URL changes via popstate (back/forward) and custom events
9697
- React.useEffect(() => {
9710
+ React$1.useEffect(() => {
9698
9711
  if (!enableSearchUrlParam) {
9699
9712
  setSearchTerm(extraSearchTerm);
9700
9713
  return;
@@ -9736,10 +9749,10 @@ function Table({
9736
9749
  window.history.replaceState = originalReplaceState;
9737
9750
  };
9738
9751
  }, [enableSearchUrlParam, extraSearchTerm]);
9739
- const toggleRowSelection = React.useCallback(rowId => {
9752
+ const toggleRowSelection = React$1.useCallback(rowId => {
9740
9753
  setSelectedRows(prev => prev.includes(rowId) ? prev.filter(r => r !== rowId) : [...prev, rowId]);
9741
9754
  }, []);
9742
- const clearSelection = React.useCallback(() => setSelectedRows([]), []);
9755
+ const clearSelection = React$1.useCallback(() => setSelectedRows([]), []);
9743
9756
  const setSort = column => {
9744
9757
  setSorting(prev => {
9745
9758
  if (!prev || prev.column !== column) return {
@@ -9756,13 +9769,13 @@ function Table({
9756
9769
 
9757
9770
  // console.log(extraSearchTerm)
9758
9771
 
9759
- const [localData, setLocalData] = React.useState(data);
9760
- React.useEffect(() => setLocalData(data), [data]);
9761
- const listRef = React.useRef(null);
9762
- const normalizedGroups = React.useMemo(() => {
9772
+ const [localData, setLocalData] = React$1.useState(data);
9773
+ React$1.useEffect(() => setLocalData(data), [data]);
9774
+ const listRef = React$1.useRef(null);
9775
+ const normalizedGroups = React$1.useMemo(() => {
9763
9776
  return normalizeData(isGrouped ? localData : [], isGrouped ? [] : localData);
9764
9777
  }, [localData, isGrouped]);
9765
- const filterRows = React.useCallback(rows => {
9778
+ const filterRows = React$1.useCallback(rows => {
9766
9779
  if (!searchTerm) return rows;
9767
9780
  const query = searchTerm.toLowerCase();
9768
9781
  return rows.filter(row => columns.some(col => {
@@ -9804,7 +9817,7 @@ function Table({
9804
9817
  if (sx > sy) return dir === "asc" ? 1 : -1;
9805
9818
  return 0;
9806
9819
  };
9807
- const sortedGroupedData = React.useMemo(() => {
9820
+ const sortedGroupedData = React$1.useMemo(() => {
9808
9821
  const sortKey = sorting?.column;
9809
9822
  const direction = sorting?.direction || "asc";
9810
9823
  const sortRows = rows => {
@@ -9818,14 +9831,14 @@ function Table({
9818
9831
  rows: sortRows(g.rows || [])
9819
9832
  }));
9820
9833
  }, [normalizedGroups, sorting, filterRows]);
9821
- const [expandedGroups, setExpandedGroups] = React.useState({});
9834
+ const [expandedGroups, setExpandedGroups] = React$1.useState({});
9822
9835
  const toggleGroup = gid => {
9823
9836
  setExpandedGroups(prev => ({
9824
9837
  ...prev,
9825
- [gid]: !Boolean(prev[gid])
9838
+ [gid]: !prev[gid]
9826
9839
  }));
9827
9840
  };
9828
- React.useEffect(() => {
9841
+ React$1.useEffect(() => {
9829
9842
  // Pre-populate expansion state for all groups
9830
9843
  setExpandedGroups(prev => {
9831
9844
  const next = {
@@ -9838,7 +9851,7 @@ function Table({
9838
9851
  return next;
9839
9852
  });
9840
9853
  }, [normalizedGroups, groupKey]);
9841
- const groupRowsById = React.useMemo(() => {
9854
+ const groupRowsById = React$1.useMemo(() => {
9842
9855
  const map = {};
9843
9856
  for (const g of sortedGroupedData) {
9844
9857
  const gid = g[groupKey] ?? g.groupId ?? g.groupName;
@@ -9846,8 +9859,8 @@ function Table({
9846
9859
  }
9847
9860
  return map;
9848
9861
  }, [sortedGroupedData, groupKey]);
9849
- const [tableDataFlat, setTableDataFlat] = React.useState([]);
9850
- const flattened = React.useMemo(() => {
9862
+ const [tableDataFlat, setTableDataFlat] = React$1.useState([]);
9863
+ const flattened = React$1.useMemo(() => {
9851
9864
  const items = [];
9852
9865
  // Use the sortedGroupedData here so the flattened list reflects current sorting and filtering
9853
9866
  for (const g of sortedGroupedData) {
@@ -9874,16 +9887,16 @@ function Table({
9874
9887
  }
9875
9888
  return items;
9876
9889
  }, [sortedGroupedData, expandedGroups, isGrouped, groupKey]);
9877
- React.useEffect(() => {
9890
+ React$1.useEffect(() => {
9878
9891
  setTableDataFlat(flattened);
9879
9892
  }, [flattened]);
9880
9893
 
9881
9894
  // useEffect(() => setTableDataFlat(flattened), [flattened]);
9882
- React.useEffect(() => selectedRowsCallback(selectedRows), [selectedRows, selectedRowsCallback]);
9895
+ React$1.useEffect(() => selectedRowsCallback(selectedRows), [selectedRows, selectedRowsCallback]);
9883
9896
 
9884
9897
  // DELETE
9885
- const [showConfirm, setShowConfirm] = React.useState(false);
9886
- const [pendingDelete, setPendingDelete] = React.useState(null);
9898
+ const [showConfirm, setShowConfirm] = React$1.useState(false);
9899
+ const [pendingDelete, setPendingDelete] = React$1.useState(null);
9887
9900
  const confirmDelete = async () => {
9888
9901
  if (!pendingDelete) return;
9889
9902
  if (deleteCallback) {
@@ -9906,18 +9919,18 @@ function Table({
9906
9919
  };
9907
9920
 
9908
9921
  // RENDER CELL
9909
- const highlight = React.useCallback(text => {
9922
+ const highlight = React$1.useCallback(text => {
9910
9923
  // Use the actual searchTerm (from URL or prop) for highlighting
9911
9924
  if (!searchTerm || typeof text !== "string") return text;
9912
9925
  const lower = text.toLowerCase();
9913
9926
  const query = searchTerm.toLowerCase();
9914
9927
  const idx = lower.indexOf(query);
9915
9928
  if (idx === -1) return text;
9916
- return /*#__PURE__*/React.createElement(React.Fragment, null, text.slice(0, idx), /*#__PURE__*/React.createElement("span", {
9929
+ return /*#__PURE__*/React$1.createElement(React$1.Fragment, null, text.slice(0, idx), /*#__PURE__*/React$1.createElement("span", {
9917
9930
  className: "highlight"
9918
9931
  }, text.slice(idx, idx + query.length)), text.slice(idx + query.length));
9919
9932
  }, [searchTerm]);
9920
- const renderCell = React.useCallback((v, accessor) => {
9933
+ const renderCell = React$1.useCallback((v, accessor) => {
9921
9934
  if (accessor === "deadlineISO") {
9922
9935
  return v ? new Date(v).toLocaleString("sl-SI", {
9923
9936
  day: "2-digit",
@@ -9935,47 +9948,97 @@ function Table({
9935
9948
  const showDelete = buttons.includes("delete");
9936
9949
  const showActions = showView || showEdit || showDelete;
9937
9950
 
9938
- // MOVE ROW
9939
- const moveRow = React.useCallback((fromIndex, toIndex) => {
9951
+ // MOVE ROW (internal + between groups)
9952
+ // moveRow: allow toIndex to be null or an object { emptyGroupId } for empty group drop
9953
+ const moveRow = React$1.useCallback((fromIndex, toIndexOrGroup) => {
9940
9954
  const from = tableDataFlat[fromIndex];
9941
- const to = tableDataFlat[toIndex];
9942
- if (!from || !to || from.type !== "row" || to.type !== "row") return;
9943
-
9944
- // Only reorder within the same group to keep grouping consistent
9945
- if (isGrouped && from.groupId !== to.groupId) return;
9955
+ let to = null;
9956
+ let emptyGroupId = null;
9957
+ if (typeof toIndexOrGroup === 'object' && toIndexOrGroup && toIndexOrGroup.emptyGroupId) {
9958
+ emptyGroupId = toIndexOrGroup.emptyGroupId;
9959
+ } else {
9960
+ to = tableDataFlat[toIndexOrGroup];
9961
+ }
9962
+ if (!from || from.type !== "row" || toIndexOrGroup !== null && !to && !emptyGroupId) return;
9946
9963
  setLocalData(prev => {
9947
9964
  if (isGrouped) {
9948
- // Reorder within the target group
9949
- const gid = from.groupId;
9950
- return prev.map(group => {
9965
+ // Remove from old group
9966
+ let movedRow;
9967
+ const newGroups = prev.map(group => {
9951
9968
  const groupId = group[groupKey] ?? group.groupId ?? group.groupName;
9952
- if (groupId !== gid) return group;
9953
- const rows = [...group.rows];
9954
- const fromPos = rows.findIndex(r => r.id === from.row.id);
9955
- const toPos = rows.findIndex(r => r.id === to.row.id);
9956
- if (fromPos === -1 || toPos === -1) return group;
9957
- const [moved] = rows.splice(fromPos, 1);
9958
- rows.splice(toPos, 0, moved);
9959
- return {
9960
- ...group,
9961
- rows
9962
- };
9969
+ if (groupId === from.groupId) {
9970
+ const rows = [...group.rows];
9971
+ const fromPos = rows.findIndex(r => r.id === from.row.id);
9972
+ if (fromPos !== -1) {
9973
+ [movedRow] = rows.splice(fromPos, 1);
9974
+ }
9975
+ return {
9976
+ ...group,
9977
+ rows
9978
+ };
9979
+ }
9980
+ return group;
9981
+ });
9982
+ if (!movedRow) return prev;
9983
+ // Insert into new group at correct position
9984
+ return newGroups.map(group => {
9985
+ const groupId = group[groupKey] ?? group.groupId ?? group.groupName;
9986
+ // If dropping into empty group
9987
+ if (emptyGroupId && groupId === emptyGroupId) {
9988
+ const rows = [...group.rows];
9989
+ if (groupKey && movedRow[groupKey] !== undefined) {
9990
+ movedRow = {
9991
+ ...movedRow,
9992
+ [groupKey]: groupId
9993
+ };
9994
+ }
9995
+ rows.push(movedRow);
9996
+ return {
9997
+ ...group,
9998
+ rows
9999
+ };
10000
+ }
10001
+ // Normal drop
10002
+ if (to && groupId === to.groupId) {
10003
+ const rows = [...group.rows];
10004
+ const toPos = rows.findIndex(r => r.id === to.row.id);
10005
+ if (groupKey && movedRow[groupKey] !== undefined) {
10006
+ movedRow = {
10007
+ ...movedRow,
10008
+ [groupKey]: groupId
10009
+ };
10010
+ }
10011
+ if (toPos === -1) {
10012
+ rows.push(movedRow);
10013
+ } else {
10014
+ rows.splice(toPos, 0, movedRow);
10015
+ }
10016
+ return {
10017
+ ...group,
10018
+ rows
10019
+ };
10020
+ }
10021
+ return group;
9963
10022
  });
9964
10023
  } else {
9965
10024
  // Ungrouped: reorder the flat list
9966
10025
  const arr = Array.isArray(prev) ? [...prev] : [];
9967
10026
  const fromPos = arr.findIndex(r => r.id === from.row.id);
9968
- const toPos = arr.findIndex(r => r.id === to.row.id);
9969
- if (fromPos === -1 || toPos === -1) return prev;
10027
+ const toPos = to ? arr.findIndex(r => r.id === to.row.id) : -1;
10028
+ if (fromPos === -1 || to && toPos === -1) return prev;
9970
10029
  const [moved] = arr.splice(fromPos, 1);
9971
- arr.splice(toPos, 0, moved);
10030
+ if (to) {
10031
+ arr.splice(toPos, 0, moved);
10032
+ } else {
10033
+ arr.push(moved);
10034
+ }
9972
10035
  return arr;
9973
10036
  }
9974
10037
  });
9975
10038
  }, [tableDataFlat, isGrouped, groupKey]);
9976
10039
 
9977
10040
  // ROW RENDERER
9978
- const rowRenderer = React.useCallback(({
10041
+ const rowRenderer = React$1.useCallback(({
9979
10042
  index,
9980
10043
  key,
9981
10044
  style
@@ -9986,65 +10049,164 @@ function Table({
9986
10049
  const gid = item.groupId;
9987
10050
  const rows = groupRowsById[gid] || [];
9988
10051
  const allSelected = rows.length > 0 && rows.every(r => selectedRows.includes(r.id));
9989
- return /*#__PURE__*/React.createElement("div", {
10052
+
10053
+ // If expanded and group is empty and drag enabled, make the group header itself a drop target
10054
+ if (item.expanded && rows.length === 0 && enableDragRow) {
10055
+ // For empty group, drop target pushes into this group
10056
+ const GroupHeaderDrop = () => {
10057
+ const ref = React$1.useRef(null);
10058
+ const [, drop] = reactDnd.useDrop({
10059
+ accept: ITEM_TYPE,
10060
+ drop(draggedItem) {
10061
+ if (draggedItem && typeof draggedItem.index === "number") {
10062
+ moveRow(draggedItem.index, {
10063
+ emptyGroupId: gid
10064
+ });
10065
+ }
10066
+ },
10067
+ canDrop: () => true,
10068
+ collect: monitor => ({
10069
+ isOver: monitor.isOver(),
10070
+ canDrop: monitor.canDrop()
10071
+ })
10072
+ });
10073
+ drop(ref);
10074
+ return /*#__PURE__*/React$1.createElement("div", {
10075
+ ref: ref,
10076
+ key: key,
10077
+ style: {
10078
+ ...style,
10079
+ background: '#f6f6fa',
10080
+ border: '2px dashed #bbb',
10081
+ textAlign: 'center',
10082
+ color: '#888',
10083
+ minHeight: rowHeight,
10084
+ display: 'flex',
10085
+ alignItems: 'center'
10086
+ },
10087
+ className: "table-row group-row empty-group-drop",
10088
+ onClick: () => toggleGroup(gid)
10089
+ }, enableMultiSelect && showDelete && /*#__PURE__*/React$1.createElement("div", {
10090
+ className: "table-cell checkbox-cell"
10091
+ }, /*#__PURE__*/React$1.createElement("input", {
10092
+ type: "checkbox",
10093
+ checked: allSelected,
10094
+ onChange: e => {
10095
+ e.stopPropagation();
10096
+ const ids = rows.map(r => r.id);
10097
+ if (allSelected) {
10098
+ setSelectedRows(prev => prev.filter(id => !ids.includes(id)));
10099
+ } else {
10100
+ setSelectedRows(prev => [...prev, ...ids.filter(id => !prev.includes(id))]);
10101
+ }
10102
+ },
10103
+ onClick: e => e.stopPropagation()
10104
+ })), showKey && /*#__PURE__*/React$1.createElement("div", {
10105
+ className: "table-cell key-cell"
10106
+ }), /*#__PURE__*/React$1.createElement("div", {
10107
+ className: "table-cell group-header",
10108
+ style: {
10109
+ width: '100%'
10110
+ }
10111
+ }, item.expanded ? "▾" : "▸", " ", item.groupName, " (0) \u2014 Drop here to move into this group"), columns.slice(1).map((_, i) => /*#__PURE__*/React$1.createElement("div", {
10112
+ key: i,
10113
+ className: "table-cell"
10114
+ })), showActions && /*#__PURE__*/React$1.createElement("div", {
10115
+ className: "table-cell action-cell"
10116
+ }));
10117
+ };
10118
+ return /*#__PURE__*/React$1.createElement(GroupHeaderDrop, null);
10119
+ }
10120
+ // Default: normal group header
10121
+ return /*#__PURE__*/React$1.createElement("div", {
9990
10122
  key: key,
9991
10123
  style: style,
9992
10124
  className: "table-row group-row",
9993
10125
  onClick: () => toggleGroup(gid)
9994
- }, /*#__PURE__*/React.createElement("div", {
10126
+ }, enableMultiSelect && showDelete && /*#__PURE__*/React$1.createElement("div", {
9995
10127
  className: "table-cell checkbox-cell"
9996
- }, /*#__PURE__*/React.createElement("input", {
10128
+ }, /*#__PURE__*/React$1.createElement("input", {
9997
10129
  type: "checkbox",
9998
10130
  checked: allSelected,
9999
10131
  onChange: e => {
10000
10132
  e.stopPropagation();
10001
10133
  const ids = rows.map(r => r.id);
10002
- ids.forEach(id => toggleRowSelection(tableId, id));
10134
+ if (allSelected) {
10135
+ setSelectedRows(prev => prev.filter(id => !ids.includes(id)));
10136
+ } else {
10137
+ setSelectedRows(prev => [...prev, ...ids.filter(id => !prev.includes(id))]);
10138
+ }
10003
10139
  },
10004
10140
  onClick: e => e.stopPropagation()
10005
- })), showKey && /*#__PURE__*/React.createElement("div", {
10141
+ })), showKey && /*#__PURE__*/React$1.createElement("div", {
10006
10142
  className: "table-cell key-cell"
10007
- }), /*#__PURE__*/React.createElement("div", {
10143
+ }), /*#__PURE__*/React$1.createElement("div", {
10008
10144
  className: "table-cell group-header"
10009
- }, item.expanded ? "▾" : "▸", " ", item.groupName, " (", item.rowCount, ")"), columns.slice(1).map((_, i) => /*#__PURE__*/React.createElement("div", {
10145
+ }, item.expanded ? "▾" : "▸", " ", item.groupName, " (", item.rowCount, ")"), columns.slice(1).map((_, i) => /*#__PURE__*/React$1.createElement("div", {
10010
10146
  key: i,
10011
10147
  className: "table-cell"
10012
- })), showActions && /*#__PURE__*/React.createElement("div", {
10148
+ })), showActions && /*#__PURE__*/React$1.createElement("div", {
10013
10149
  className: "table-cell action-cell"
10014
10150
  }));
10015
10151
  }
10016
10152
  const row = item.row;
10017
10153
  const visualIndex = tableDataFlat.slice(0, index).filter(i => i.type === "row").length + 1;
10018
- const content = /*#__PURE__*/React.createElement("div", {
10154
+
10155
+ // Compose columns + custom columns
10156
+ const allColumns = [...columns];
10157
+ // Insert custom columns at specified places
10158
+ if (Array.isArray(customColumns)) {
10159
+ customColumns.forEach(col => {
10160
+ if (typeof col.place === 'number') {
10161
+ allColumns.splice(col.place, 0, {
10162
+ ...col,
10163
+ isCustom: true
10164
+ });
10165
+ }
10166
+ });
10167
+ }
10168
+ const content = /*#__PURE__*/React$1.createElement("div", {
10019
10169
  key: key,
10020
10170
  style: style,
10021
10171
  className: "table-row"
10022
- }, showDelete && /*#__PURE__*/React.createElement("div", {
10172
+ }, enableMultiSelect && showDelete && /*#__PURE__*/React$1.createElement("div", {
10023
10173
  className: "table-cell checkbox-cell"
10024
- }, /*#__PURE__*/React.createElement("input", {
10174
+ }, /*#__PURE__*/React$1.createElement("input", {
10025
10175
  type: "checkbox",
10026
10176
  checked: selectedRows.includes(row.id),
10027
10177
  onChange: () => toggleRowSelection(row.id)
10028
- })), showKey && /*#__PURE__*/React.createElement("div", {
10178
+ })), showKey && /*#__PURE__*/React$1.createElement("div", {
10029
10179
  className: "table-cell key-cell"
10030
- }, visualIndex), columns.map((col, i) => /*#__PURE__*/React.createElement("div", {
10031
- key: i,
10032
- className: "table-cell"
10033
- }, renderCell(row[col.accessor], col.accessor))), showActions && /*#__PURE__*/React.createElement("div", {
10180
+ }, visualIndex), allColumns.map((col, i) => {
10181
+ let cellStyle = col.isCustom && col.style ? {
10182
+ ...col.style
10183
+ } : undefined;
10184
+ if (col.isCustom && col.style && col.style.width) {
10185
+ cellStyle = cellStyle || {};
10186
+ cellStyle.minWidth = col.style.width;
10187
+ cellStyle.maxWidth = col.style.width;
10188
+ cellStyle.width = col.style.width;
10189
+ }
10190
+ return /*#__PURE__*/React$1.createElement("div", {
10191
+ key: i,
10192
+ className: "table-cell",
10193
+ style: cellStyle
10194
+ }, col.isCustom ? typeof col.render === 'function' ? col.render(row, i) : col.render : renderCell(row[col.accessor], col.accessor, row));
10195
+ }), showActions && /*#__PURE__*/React$1.createElement("div", {
10034
10196
  className: "table-cell action-cell"
10035
- }, showView && /*#__PURE__*/React.createElement("button", {
10197
+ }, showView && /*#__PURE__*/React$1.createElement("button", {
10036
10198
  className: "action-btn-table",
10037
10199
  style: {
10038
10200
  background: "#646cffaa"
10039
10201
  },
10040
10202
  onClick: () => viewCallback(row)
10041
- }, "View"), showEdit && /*#__PURE__*/React.createElement("button", {
10203
+ }, "View"), showEdit && /*#__PURE__*/React$1.createElement("button", {
10042
10204
  className: "action-btn-table",
10043
10205
  style: {
10044
10206
  background: "#4caf50"
10045
10207
  },
10046
10208
  onClick: () => editCallback(row)
10047
- }, "Edit"), showDelete && /*#__PURE__*/React.createElement("button", {
10209
+ }, "Edit"), showDelete && /*#__PURE__*/React$1.createElement("button", {
10048
10210
  className: "action-btn-table",
10049
10211
  style: {
10050
10212
  background: "#f44336"
@@ -10056,25 +10218,64 @@ function Table({
10056
10218
  }
10057
10219
  }, "Delete")));
10058
10220
  if (enableDragRow && item.type === "row") {
10059
- return /*#__PURE__*/React.createElement(DraggableRow, {
10221
+ return /*#__PURE__*/React$1.createElement(DraggableRow, {
10060
10222
  key: key,
10061
10223
  index: index,
10062
10224
  moveRow: moveRow,
10063
- item: item,
10225
+ row: row,
10226
+ tableId: tableId,
10064
10227
  enableDrag: true,
10065
10228
  listRef: listRef
10066
10229
  }, content);
10067
10230
  }
10068
10231
  return content;
10069
- }, [tableDataFlat, columns, selectedRows, toggleRowSelection, groupRowsById, renderCell, showActions, showDelete, showEdit, showKey, showView, tableId, viewCallback, editCallback, enableDragRow, moveRow]);
10232
+ }, [tableDataFlat, columns, selectedRows, toggleRowSelection, groupRowsById, renderCell, showActions, showDelete, showEdit, showKey, showView, viewCallback, editCallback, enableDragRow, moveRow, enableMultiSelect, rowHeight, tableId, customColumns]);
10070
10233
  const rowHeightGetter = ({
10071
10234
  index
10072
10235
  }) => tableDataFlat[index]?.type === "group" ? groupHeaderHeight : rowHeight;
10073
- return /*#__PURE__*/React.createElement(reactDnd.DndProvider, {
10074
- backend: reactDndHtml5Backend.HTML5Backend
10075
- }, /*#__PURE__*/React.createElement("div", {
10076
- className: "table-container"
10077
- }, /*#__PURE__*/React.createElement("div", {
10236
+
10237
+ // Table-level drop target only when using external DnD context
10238
+ const tableContainerRef = React$1.useRef(null);
10239
+ const [{
10240
+ isOver: isExternalOver,
10241
+ canDrop: canExternalDrop
10242
+ }, externalDrop] = reactDnd.useDrop({
10243
+ accept: ITEM_TYPE,
10244
+ drop: draggedItem => {
10245
+ if (!useExternalDndContext) return; // safety
10246
+ if (!enableExternalRowDrop || isGrouped) return;
10247
+ if (!draggedItem || draggedItem.sourceTableId === tableId) return;
10248
+ onExternalRowDrop(draggedItem.row, draggedItem.sourceTableId, tableId);
10249
+ }
10250
+ });
10251
+ const setTableRef = React$1.useCallback(node => {
10252
+ tableContainerRef.current = node;
10253
+ if (node && useExternalDndContext && enableExternalRowDrop) {
10254
+ externalDrop(node);
10255
+ }
10256
+ }, [useExternalDndContext, enableExternalRowDrop, externalDrop]);
10257
+
10258
+ // Compose columns + custom columns for header
10259
+ const allColumns = [...columns];
10260
+ if (Array.isArray(customColumns)) {
10261
+ customColumns.forEach(col => {
10262
+ if (typeof col.place === 'number') {
10263
+ allColumns.splice(col.place, 0, {
10264
+ ...col,
10265
+ isCustom: true
10266
+ });
10267
+ }
10268
+ });
10269
+ }
10270
+ const tableMarkup = /*#__PURE__*/React$1.createElement("div", {
10271
+ className: "table-container",
10272
+ ref: setTableRef,
10273
+ style: useExternalDndContext && enableExternalRowDrop ? {
10274
+ transition: 'background 0.15s',
10275
+ background: isExternalOver && canExternalDrop ? 'rgba(100,108,255,0.15)' : undefined,
10276
+ outline: isExternalOver && canExternalDrop ? '2px dashed #646cff' : undefined
10277
+ } : undefined
10278
+ }, /*#__PURE__*/React$1.createElement("div", {
10078
10279
  className: "table-header",
10079
10280
  style: {
10080
10281
  position: "sticky",
@@ -10082,11 +10283,11 @@ function Table({
10082
10283
  zIndex: 10,
10083
10284
  background: "#fff"
10084
10285
  }
10085
- }, /*#__PURE__*/React.createElement("div", {
10286
+ }, /*#__PURE__*/React$1.createElement("div", {
10086
10287
  className: "table-row header-row"
10087
- }, showDelete && /*#__PURE__*/React.createElement("div", {
10288
+ }, enableMultiSelect && showDelete && /*#__PURE__*/React$1.createElement("div", {
10088
10289
  className: "table-cell checkbox-cell"
10089
- }, /*#__PURE__*/React.createElement("input", {
10290
+ }, /*#__PURE__*/React$1.createElement("input", {
10090
10291
  type: "checkbox",
10091
10292
  checked: tableDataFlat.filter(i => i.type === "row").length > 0 && selectedRows.length === tableDataFlat.filter(i => i.type === "row").length,
10092
10293
  onChange: e => {
@@ -10097,33 +10298,48 @@ function Table({
10097
10298
  clearSelection();
10098
10299
  }
10099
10300
  }
10100
- })), showKey && /*#__PURE__*/React.createElement("div", {
10301
+ })), showKey && /*#__PURE__*/React$1.createElement("div", {
10101
10302
  className: "table-cell key-cell"
10102
- }, "#"), columns.map((col, i) => /*#__PURE__*/React.createElement("div", {
10103
- key: i,
10104
- className: "table-cell",
10105
- onClick: () => setSort(col.accessor),
10106
- style: {
10107
- cursor: "pointer"
10303
+ }, "#"), allColumns.map((col, i) => {
10304
+ // For custom columns, apply width and textAlign to header cell
10305
+ let cellStyle = col.isCustom && col.style ? {
10306
+ ...col.style,
10307
+ cursor: undefined,
10308
+ display: 'flex',
10309
+ alignItems: 'center',
10310
+ justifyContent: col.style.textAlign === 'center' ? 'center' : col.style.textAlign === 'right' ? 'flex-end' : 'flex-start'
10311
+ } : {
10312
+ cursor: col.isCustom ? undefined : "pointer"
10313
+ };
10314
+ if (col.isCustom && col.style && col.style.width) {
10315
+ cellStyle.minWidth = col.style.width;
10316
+ cellStyle.maxWidth = col.style.width;
10317
+ cellStyle.width = col.style.width;
10108
10318
  }
10109
- }, col.header, sorting?.column === col.accessor && (sorting.direction === "asc" ? " ↑" : " ↓"))), showActions && /*#__PURE__*/React.createElement("div", {
10319
+ return /*#__PURE__*/React$1.createElement("div", {
10320
+ key: i,
10321
+ className: "table-cell",
10322
+ style: cellStyle,
10323
+ onClick: col.isCustom ? undefined : () => setSort(col.accessor)
10324
+ }, col.isCustom ? col.header ?? '' : col.header, !col.isCustom && sorting?.column === col.accessor && (sorting.direction === "asc" ? " ↑" : " ↓"));
10325
+ }), showActions && /*#__PURE__*/React$1.createElement("div", {
10110
10326
  className: "table-cell action-cell"
10111
- }, "Action"))), /*#__PURE__*/React.createElement("div", {
10327
+ }, "Action"))), /*#__PURE__*/React$1.createElement("div", {
10112
10328
  className: "main-table",
10113
10329
  ref: listRef
10114
- }, tableDataFlat.length === 0 ? /*#__PURE__*/React.createElement("div", {
10330
+ }, tableDataFlat.length === 0 ? /*#__PURE__*/React$1.createElement("div", {
10115
10331
  className: "table-empty"
10116
- }, "No items") : /*#__PURE__*/React.createElement(AutoSizer, null, ({
10332
+ }, "No items") : /*#__PURE__*/React$1.createElement(AutoSizer, null, ({
10117
10333
  height,
10118
10334
  width
10119
- }) => /*#__PURE__*/React.createElement(List, {
10335
+ }) => /*#__PURE__*/React$1.createElement(List, {
10120
10336
  width: width,
10121
10337
  height: height,
10122
10338
  rowCount: tableDataFlat.length,
10123
10339
  rowHeight: rowHeightGetter,
10124
10340
  rowRenderer: rowRenderer,
10125
10341
  overscanRowCount: 8
10126
- }))), /*#__PURE__*/React.createElement(Modal, {
10342
+ }))), /*#__PURE__*/React$1.createElement(Modal, {
10127
10343
  isOpen: showConfirm,
10128
10344
  title: "Confirm delete",
10129
10345
  onConfirm: confirmDelete,
@@ -10132,12 +10348,67 @@ function Table({
10132
10348
  cancelLabel: "Cancel",
10133
10349
  showCancel: true,
10134
10350
  showConfirm: true
10135
- }, /*#__PURE__*/React.createElement("p", null, "Are you sure you want to delete ", /*#__PURE__*/React.createElement("strong", null, pendingDelete?.name || pendingDelete?.id), "?"))));
10351
+ }, /*#__PURE__*/React$1.createElement("p", null, "Are you sure you want to delete ", /*#__PURE__*/React$1.createElement("strong", null, pendingDelete?.name || pendingDelete?.id), "?")));
10352
+ return tableMarkup;
10353
+ }
10354
+ function Table(props) {
10355
+ const {
10356
+ useExternalDndContext = false
10357
+ } = props;
10358
+ if (useExternalDndContext) {
10359
+ return /*#__PURE__*/React$1.createElement(TableInner, props);
10360
+ }
10361
+ // Provide DnD context when not supplied externally
10362
+ return /*#__PURE__*/React$1.createElement(reactDnd.DndProvider, {
10363
+ backend: reactDndHtml5Backend.HTML5Backend
10364
+ }, /*#__PURE__*/React$1.createElement(TableInner, props));
10365
+ }
10366
+
10367
+ function Switch({
10368
+ checked,
10369
+ onChange
10370
+ }) {
10371
+ return /*#__PURE__*/React.createElement("label", {
10372
+ style: {
10373
+ display: "inline-flex",
10374
+ alignItems: "center",
10375
+ cursor: "pointer"
10376
+ }
10377
+ }, /*#__PURE__*/React.createElement("input", {
10378
+ type: "checkbox",
10379
+ checked: checked,
10380
+ onChange: onChange,
10381
+ style: {
10382
+ display: "none"
10383
+ }
10384
+ }), /*#__PURE__*/React.createElement("span", {
10385
+ style: {
10386
+ width: 36,
10387
+ height: 20,
10388
+ background: checked ? "#4caf50" : "#ccc",
10389
+ borderRadius: 12,
10390
+ position: "relative",
10391
+ transition: "background 0.2s",
10392
+ display: "inline-block"
10393
+ }
10394
+ }, /*#__PURE__*/React.createElement("span", {
10395
+ style: {
10396
+ position: "absolute",
10397
+ left: checked ? 18 : 2,
10398
+ top: 2,
10399
+ width: 16,
10400
+ height: 16,
10401
+ background: "#fff",
10402
+ borderRadius: "50%",
10403
+ transition: "left 0.2s"
10404
+ }
10405
+ })));
10136
10406
  }
10137
10407
 
10138
10408
  // src/index.js
10139
- // if you want named import
10409
+ // named exports for both
10140
10410
 
10411
+ exports.Switch = Switch;
10141
10412
  exports.Table = Table;
10142
10413
  exports.default = Table;
10143
10414
  //# sourceMappingURL=index.cjs.js.map