@trackunit/react-table 1.3.163 → 1.3.167

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/index.cjs.js CHANGED
@@ -286,6 +286,77 @@ const cvaColumnFilterGrabbable = cssClassVarianceUtilities.cvaMerge(["flex", "it
286
286
  },
287
287
  });
288
288
 
289
+ const ItemTypes = {
290
+ COLUMN: "column",
291
+ };
292
+ /**
293
+ * Component for rendering an individual column filter item with drag-and-drop,
294
+ * toggle, and locking capabilities.
295
+ *
296
+ * @param {object} props - Props for the component.
297
+ * @param {string} props.name - The name of the column.
298
+ * @param {(toggled: boolean, event: ChangeEvent<HTMLInputElement>) => void} props.onToggle - Callback for when a column's toggled state changes.
299
+ * @param {boolean} props.toggled - Whether the column is toggled on or off.
300
+ * @param {boolean} props.disabled - Whether the toggle or drag functionality is disabled.
301
+ * @param {number} props.index - The index of the current column in the list.
302
+ * @param {(dragIndex: number, hoverIndex: number) => void} props.moveColumn - Function to move columns during drag-and-drop.
303
+ * @param {() => void} props.onDrop - Callback when a column is dropped.
304
+ * @param {() => void} props.onCancelDrop - Callback for canceling a drop action.
305
+ * @param {string} props.id - Unique identifier for the column.
306
+ * @param {boolean} [props.isSortDisabled] - Optional flag to disable sorting.
307
+ * @returns {JSX.Element} A React component rendering the column filter item.
308
+ */
309
+ const ColumnFilterItem = ({ name, onToggle, toggled, disabled, index, moveColumn, onDrop, onCancelDrop, id, isSortDisabled, }) => {
310
+ const ref = react.useRef(null);
311
+ const [, drop] = reactDnd.useDrop({
312
+ accept: ItemTypes.COLUMN,
313
+ hover(item, monitor) {
314
+ if (!ref.current) {
315
+ return;
316
+ }
317
+ const dragIndex = item.index;
318
+ const hoverIndex = index;
319
+ if (dragIndex === hoverIndex) {
320
+ return;
321
+ }
322
+ const hoverBoundingRect = ref.current.getBoundingClientRect();
323
+ const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
324
+ const clientOffset = monitor.getClientOffset();
325
+ const hoverClientY = clientOffset.y - hoverBoundingRect.top;
326
+ if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
327
+ return;
328
+ }
329
+ if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
330
+ return;
331
+ }
332
+ moveColumn(dragIndex, hoverIndex);
333
+ item.index = hoverIndex;
334
+ },
335
+ drop(item, monitor) {
336
+ onDrop();
337
+ },
338
+ });
339
+ const [{ isDragging }, drag] = reactDnd.useDrag({
340
+ type: ItemTypes.COLUMN,
341
+ item: { type: ItemTypes.COLUMN, id, index },
342
+ canDrag: !isSortDisabled,
343
+ collect: (monitor) => ({
344
+ isDragging: monitor.isDragging(),
345
+ }),
346
+ end(draggedItem, monitor) {
347
+ if (!monitor.didDrop()) {
348
+ onCancelDrop();
349
+ }
350
+ },
351
+ });
352
+ const opacity = isDragging ? 0 : 1;
353
+ drag(drop(ref));
354
+ return (jsxRuntime.jsxs("div", { className: reactComponents.cvaInteractableItem({
355
+ selected: false,
356
+ className: "grid w-full grid-cols-[min-content,1fr,min-content] items-center gap-2 py-1",
357
+ }), ref: ref, style: { opacity: opacity }, children: [jsxRuntime.jsx("div", { className: cvaColumnFilterGrabbable({ disabled: isSortDisabled }), children: jsxRuntime.jsx(reactComponents.Icon, { color: "secondary", name: "EllipsisDrag", size: "small" }) }), jsxRuntime.jsxs("label", { className: "grid w-full grid-cols-[1fr,min-content] items-center gap-2", htmlFor: id, children: [jsxRuntime.jsxs("div", { className: "grid w-full grid-cols-[1fr,min-content] items-center", children: [jsxRuntime.jsx(reactComponents.Text, { className: reactFormComponents.cvaLabel(), children: name }), disabled ? jsxRuntime.jsx(reactComponents.Icon, { name: "LockClosed", size: "small" }) : null] }), jsxRuntime.jsx(reactFormComponents.ToggleSwitch, { disabled: disabled, id: id, onChange: (isToggled, event) => event && onToggle(isToggled, event), showInputFocus: false, size: "small", toggled: toggled })] })] }));
358
+ };
359
+
289
360
  /**
290
361
  * ColumnFilter component for managing visibility and order of table columns.
291
362
  *
@@ -294,7 +365,7 @@ const cvaColumnFilterGrabbable = cssClassVarianceUtilities.cvaMerge(["flex", "it
294
365
  * @param {ColumnFilterProps<TColumnFilter, TColumnFilterValue>} props - The props object containing necessary properties.
295
366
  * @returns {ReactElement | null} A React JSX element representing the ColumnFilter component or null if columns are not provided.
296
367
  */
297
- const ColumnFilter = ({ columns, setColumnOrder, defaultColumnOrder = [], columnOrder, onUserEvent, }) => {
368
+ const ColumnFilter = ({ columns, setColumnOrder, defaultColumnOrder = [], columnOrder, onUserEvent, setColumnSize, }) => {
298
369
  const [t] = useTranslation();
299
370
  const initialSetupRef = react.useRef(false);
300
371
  const [searchText, setSearchText] = react.useState("");
@@ -304,11 +375,18 @@ const ColumnFilter = ({ columns, setColumnOrder, defaultColumnOrder = [], column
304
375
  initialSetupRef.current = true;
305
376
  }
306
377
  }, [columnOrder, defaultColumnOrder, setColumnOrder]);
307
- const resetHiddenColumns = react.useCallback(() => {
308
- columns.forEach(column => column.toggleVisibility(!column.columnDef.meta?.hiddenByDefault));
378
+ const resetColumnState = react.useCallback(() => {
379
+ const sizes = {};
380
+ columns.forEach(column => {
381
+ if (column.columnDef.size) {
382
+ sizes[column.id] = column.columnDef.size;
383
+ }
384
+ column.toggleVisibility(!column.columnDef.meta?.hiddenByDefault);
385
+ column.pin(column.columnDef.meta?.pinned ?? false);
386
+ });
309
387
  setColumnOrder(defaultColumnOrder);
310
- columns.forEach(column => column.pin(column.columnDef.meta?.pinned ?? false));
311
- }, [columns, defaultColumnOrder, setColumnOrder]);
388
+ setColumnSize(sizes);
389
+ }, [columns, defaultColumnOrder, setColumnOrder, setColumnSize]);
312
390
  const sortedColumns = react.useMemo(() => {
313
391
  let filteredColumns = columns;
314
392
  if (searchText.trim() !== "") {
@@ -325,7 +403,7 @@ const ColumnFilter = ({ columns, setColumnOrder, defaultColumnOrder = [], column
325
403
  const visibleColumnsCount = react.useMemo(() => {
326
404
  return columns.filter(col => col.getIsVisible()).length;
327
405
  }, [columns]);
328
- return (jsxRuntime.jsx(reactDnd.DndProvider, { backend: reactDndHtml5Backend.HTML5Backend, children: jsxRuntime.jsx(reactComponents.Tooltip, { label: t("table.columnFilters.tooltip"), placement: "bottom", children: jsxRuntime.jsxs(reactComponents.Popover, { placement: "bottom-start", children: [jsxRuntime.jsx(reactComponents.PopoverTrigger, { children: jsxRuntime.jsx(reactComponents.Button, { prefix: jsxRuntime.jsx(reactComponents.Icon, { name: "ViewColumns", size: "small" }), size: "small", variant: "secondary", children: jsxRuntime.jsx("span", { className: "hidden md:block", children: t("table.columnFilters.columns") }) }) }), jsxRuntime.jsx(reactComponents.PopoverContent, { children: () => (jsxRuntime.jsxs(reactComponents.MenuList, { className: "relative max-h-[55vh] w-72 overflow-y-auto", children: [jsxRuntime.jsxs("div", { className: "mb-2 flex items-center gap-1", children: [jsxRuntime.jsx(reactFormComponents.Search, { autoFocus: true, className: "flex-1", fieldSize: "small", id: "column-search", onChange: e => setSearchText(e.currentTarget.value.toLowerCase()), onClear: () => setSearchText(""), placeholder: "Search", value: searchText }), jsxRuntime.jsx(reactComponents.Button, { onClick: resetHiddenColumns, size: "small", variant: "ghost-neutral", children: t("layout.actions.reset") })] }), jsxRuntime.jsx(ColumnFiltersDragAndDrop, { columns: sortedColumns, isSortDisabled: !!searchText, onUserEvent: onUserEvent, setColumnOrder: setColumnOrder, visibleColumnsCount: visibleColumnsCount })] })) })] }) }) }));
406
+ return (jsxRuntime.jsx(reactDnd.DndProvider, { backend: reactDndHtml5Backend.HTML5Backend, children: jsxRuntime.jsx(reactComponents.Tooltip, { label: t("table.columnFilters.tooltip"), placement: "bottom", children: jsxRuntime.jsxs(reactComponents.Popover, { placement: "bottom-start", children: [jsxRuntime.jsx(reactComponents.PopoverTrigger, { children: jsxRuntime.jsx(reactComponents.Button, { prefix: jsxRuntime.jsx(reactComponents.Icon, { name: "ViewColumns", size: "small" }), size: "small", variant: "secondary", children: jsxRuntime.jsx("span", { className: "hidden md:block", children: t("table.columnFilters.columns") }) }) }), jsxRuntime.jsx(reactComponents.PopoverContent, { children: () => (jsxRuntime.jsxs(reactComponents.MenuList, { className: "relative max-h-[55vh] w-72 overflow-y-auto", children: [jsxRuntime.jsxs("div", { className: "mb-2 flex items-center gap-1", children: [jsxRuntime.jsx(reactFormComponents.Search, { autoFocus: true, className: "flex-1", fieldSize: "small", id: "column-search", onChange: e => setSearchText(e.currentTarget.value.toLowerCase()), onClear: () => setSearchText(""), placeholder: "Search", value: searchText }), jsxRuntime.jsx(reactComponents.Button, { dataTestId: "resetColumnState", onClick: resetColumnState, size: "small", variant: "ghost-neutral", children: t("layout.actions.reset") })] }), jsxRuntime.jsx(ColumnFiltersDragAndDrop, { columns: sortedColumns, isSortDisabled: !!searchText, onUserEvent: onUserEvent, setColumnOrder: setColumnOrder, visibleColumnsCount: visibleColumnsCount })] })) })] }) }) }));
329
407
  };
330
408
  const ColumnFiltersDragAndDrop = ({ columns, setColumnOrder, onUserEvent, isSortDisabled, visibleColumnsCount, }) => {
331
409
  const [localColumns, setLocalColumns] = react.useState(columns);
@@ -369,59 +447,6 @@ const ColumnFiltersDragAndDrop = ({ columns, setColumnOrder, onUserEvent, isSort
369
447
  }, toggled: isVisible }, column.id));
370
448
  }) }));
371
449
  };
372
- const ItemTypes = {
373
- COLUMN: "column",
374
- };
375
- const ColumnFilterItem = ({ name, onToggle, toggled, disabled, index, moveColumn, onDrop, onCancelDrop, id, isSortDisabled, }) => {
376
- const ref = react.useRef(null);
377
- const [, drop] = reactDnd.useDrop({
378
- accept: ItemTypes.COLUMN,
379
- hover(item, monitor) {
380
- if (!ref.current) {
381
- return;
382
- }
383
- const dragIndex = item.index;
384
- const hoverIndex = index;
385
- if (dragIndex === hoverIndex) {
386
- return;
387
- }
388
- const hoverBoundingRect = ref.current.getBoundingClientRect();
389
- const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
390
- const clientOffset = monitor.getClientOffset();
391
- const hoverClientY = clientOffset.y - hoverBoundingRect.top;
392
- if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
393
- return;
394
- }
395
- if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
396
- return;
397
- }
398
- moveColumn(dragIndex, hoverIndex);
399
- item.index = hoverIndex;
400
- },
401
- drop(item, monitor) {
402
- onDrop();
403
- },
404
- });
405
- const [{ isDragging }, drag] = reactDnd.useDrag({
406
- type: ItemTypes.COLUMN,
407
- item: { type: ItemTypes.COLUMN, id, index },
408
- canDrag: !isSortDisabled,
409
- collect: (monitor) => ({
410
- isDragging: monitor.isDragging(),
411
- }),
412
- end(draggedItem, monitor) {
413
- if (!monitor.didDrop()) {
414
- onCancelDrop();
415
- }
416
- },
417
- });
418
- const opacity = isDragging ? 0 : 1;
419
- drag(drop(ref));
420
- return (jsxRuntime.jsxs("div", { className: reactComponents.cvaInteractableItem({
421
- selected: false,
422
- className: "grid w-full grid-cols-[min-content,1fr,min-content] items-center gap-2 py-1",
423
- }), ref: ref, style: { opacity: opacity }, children: [jsxRuntime.jsx("div", { className: cvaColumnFilterGrabbable({ disabled: isSortDisabled }), children: jsxRuntime.jsx(reactComponents.Icon, { color: "secondary", name: "EllipsisDrag", size: "small" }) }), jsxRuntime.jsxs("label", { className: "grid w-full grid-cols-[1fr,min-content] items-center gap-2", htmlFor: id, children: [jsxRuntime.jsxs("div", { className: "grid w-full grid-cols-[1fr,min-content] items-center", children: [jsxRuntime.jsx(reactComponents.Text, { className: reactFormComponents.cvaLabel(), children: name }), disabled ? jsxRuntime.jsx(reactComponents.Icon, { name: "LockClosed", size: "small" }) : null] }), jsxRuntime.jsx(reactFormComponents.ToggleSwitch, { disabled: disabled, id: id, onChange: (isToggled, event) => event && onToggle(isToggled, event), showInputFocus: false, size: "small", toggled: toggled })] })] }));
424
- };
425
450
 
426
451
  /**
427
452
  * RowSpacing component for managing the density of table rows.
package/index.esm.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { registerTranslations, useNamespaceTranslation } from '@trackunit/i18n-library-translation';
3
- import { MenuItem, Icon, Button, useOverflowItems, MoreMenu, MenuList, Spacer, Tooltip, Popover, PopoverTrigger, PopoverContent, cvaInteractableItem, Text, IconButton, Card, Spinner, EmptyState } from '@trackunit/react-components';
3
+ import { MenuItem, Icon, Button, useOverflowItems, MoreMenu, MenuList, Spacer, cvaInteractableItem, Text, Tooltip, Popover, PopoverTrigger, PopoverContent, IconButton, Card, Spinner, EmptyState } from '@trackunit/react-components';
4
4
  import { objectValues, nonNullable, objectKeys, objectEntries } from '@trackunit/shared-utils';
5
5
  import { useMemo, Children, cloneElement, useRef, useState, useEffect, useCallback, createElement } from 'react';
6
6
  import { cvaMerge } from '@trackunit/css-class-variance-utilities';
7
7
  import { Link } from '@tanstack/react-router';
8
- import { Search, cvaLabel, ToggleSwitch, RadioGroup, RadioItem, Checkbox } from '@trackunit/react-form-components';
8
+ import { cvaLabel, ToggleSwitch, Search, RadioGroup, RadioItem, Checkbox } from '@trackunit/react-form-components';
9
9
  import update from 'immutability-helper';
10
- import { DndProvider, useDrop, useDrag } from 'react-dnd';
10
+ import { useDrop, useDrag, DndProvider } from 'react-dnd';
11
11
  import { HTML5Backend } from 'react-dnd-html5-backend';
12
12
  import { flexRender, createColumnHelper, useReactTable, getSortedRowModel, getCoreRowModel } from '@tanstack/react-table';
13
13
  export { createColumnHelper } from '@tanstack/react-table';
@@ -285,6 +285,77 @@ const cvaColumnFilterGrabbable = cvaMerge(["flex", "items-center", "justify-cent
285
285
  },
286
286
  });
287
287
 
288
+ const ItemTypes = {
289
+ COLUMN: "column",
290
+ };
291
+ /**
292
+ * Component for rendering an individual column filter item with drag-and-drop,
293
+ * toggle, and locking capabilities.
294
+ *
295
+ * @param {object} props - Props for the component.
296
+ * @param {string} props.name - The name of the column.
297
+ * @param {(toggled: boolean, event: ChangeEvent<HTMLInputElement>) => void} props.onToggle - Callback for when a column's toggled state changes.
298
+ * @param {boolean} props.toggled - Whether the column is toggled on or off.
299
+ * @param {boolean} props.disabled - Whether the toggle or drag functionality is disabled.
300
+ * @param {number} props.index - The index of the current column in the list.
301
+ * @param {(dragIndex: number, hoverIndex: number) => void} props.moveColumn - Function to move columns during drag-and-drop.
302
+ * @param {() => void} props.onDrop - Callback when a column is dropped.
303
+ * @param {() => void} props.onCancelDrop - Callback for canceling a drop action.
304
+ * @param {string} props.id - Unique identifier for the column.
305
+ * @param {boolean} [props.isSortDisabled] - Optional flag to disable sorting.
306
+ * @returns {JSX.Element} A React component rendering the column filter item.
307
+ */
308
+ const ColumnFilterItem = ({ name, onToggle, toggled, disabled, index, moveColumn, onDrop, onCancelDrop, id, isSortDisabled, }) => {
309
+ const ref = useRef(null);
310
+ const [, drop] = useDrop({
311
+ accept: ItemTypes.COLUMN,
312
+ hover(item, monitor) {
313
+ if (!ref.current) {
314
+ return;
315
+ }
316
+ const dragIndex = item.index;
317
+ const hoverIndex = index;
318
+ if (dragIndex === hoverIndex) {
319
+ return;
320
+ }
321
+ const hoverBoundingRect = ref.current.getBoundingClientRect();
322
+ const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
323
+ const clientOffset = monitor.getClientOffset();
324
+ const hoverClientY = clientOffset.y - hoverBoundingRect.top;
325
+ if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
326
+ return;
327
+ }
328
+ if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
329
+ return;
330
+ }
331
+ moveColumn(dragIndex, hoverIndex);
332
+ item.index = hoverIndex;
333
+ },
334
+ drop(item, monitor) {
335
+ onDrop();
336
+ },
337
+ });
338
+ const [{ isDragging }, drag] = useDrag({
339
+ type: ItemTypes.COLUMN,
340
+ item: { type: ItemTypes.COLUMN, id, index },
341
+ canDrag: !isSortDisabled,
342
+ collect: (monitor) => ({
343
+ isDragging: monitor.isDragging(),
344
+ }),
345
+ end(draggedItem, monitor) {
346
+ if (!monitor.didDrop()) {
347
+ onCancelDrop();
348
+ }
349
+ },
350
+ });
351
+ const opacity = isDragging ? 0 : 1;
352
+ drag(drop(ref));
353
+ return (jsxs("div", { className: cvaInteractableItem({
354
+ selected: false,
355
+ className: "grid w-full grid-cols-[min-content,1fr,min-content] items-center gap-2 py-1",
356
+ }), ref: ref, style: { opacity: opacity }, children: [jsx("div", { className: cvaColumnFilterGrabbable({ disabled: isSortDisabled }), children: jsx(Icon, { color: "secondary", name: "EllipsisDrag", size: "small" }) }), jsxs("label", { className: "grid w-full grid-cols-[1fr,min-content] items-center gap-2", htmlFor: id, children: [jsxs("div", { className: "grid w-full grid-cols-[1fr,min-content] items-center", children: [jsx(Text, { className: cvaLabel(), children: name }), disabled ? jsx(Icon, { name: "LockClosed", size: "small" }) : null] }), jsx(ToggleSwitch, { disabled: disabled, id: id, onChange: (isToggled, event) => event && onToggle(isToggled, event), showInputFocus: false, size: "small", toggled: toggled })] })] }));
357
+ };
358
+
288
359
  /**
289
360
  * ColumnFilter component for managing visibility and order of table columns.
290
361
  *
@@ -293,7 +364,7 @@ const cvaColumnFilterGrabbable = cvaMerge(["flex", "items-center", "justify-cent
293
364
  * @param {ColumnFilterProps<TColumnFilter, TColumnFilterValue>} props - The props object containing necessary properties.
294
365
  * @returns {ReactElement | null} A React JSX element representing the ColumnFilter component or null if columns are not provided.
295
366
  */
296
- const ColumnFilter = ({ columns, setColumnOrder, defaultColumnOrder = [], columnOrder, onUserEvent, }) => {
367
+ const ColumnFilter = ({ columns, setColumnOrder, defaultColumnOrder = [], columnOrder, onUserEvent, setColumnSize, }) => {
297
368
  const [t] = useTranslation();
298
369
  const initialSetupRef = useRef(false);
299
370
  const [searchText, setSearchText] = useState("");
@@ -303,11 +374,18 @@ const ColumnFilter = ({ columns, setColumnOrder, defaultColumnOrder = [], column
303
374
  initialSetupRef.current = true;
304
375
  }
305
376
  }, [columnOrder, defaultColumnOrder, setColumnOrder]);
306
- const resetHiddenColumns = useCallback(() => {
307
- columns.forEach(column => column.toggleVisibility(!column.columnDef.meta?.hiddenByDefault));
377
+ const resetColumnState = useCallback(() => {
378
+ const sizes = {};
379
+ columns.forEach(column => {
380
+ if (column.columnDef.size) {
381
+ sizes[column.id] = column.columnDef.size;
382
+ }
383
+ column.toggleVisibility(!column.columnDef.meta?.hiddenByDefault);
384
+ column.pin(column.columnDef.meta?.pinned ?? false);
385
+ });
308
386
  setColumnOrder(defaultColumnOrder);
309
- columns.forEach(column => column.pin(column.columnDef.meta?.pinned ?? false));
310
- }, [columns, defaultColumnOrder, setColumnOrder]);
387
+ setColumnSize(sizes);
388
+ }, [columns, defaultColumnOrder, setColumnOrder, setColumnSize]);
311
389
  const sortedColumns = useMemo(() => {
312
390
  let filteredColumns = columns;
313
391
  if (searchText.trim() !== "") {
@@ -324,7 +402,7 @@ const ColumnFilter = ({ columns, setColumnOrder, defaultColumnOrder = [], column
324
402
  const visibleColumnsCount = useMemo(() => {
325
403
  return columns.filter(col => col.getIsVisible()).length;
326
404
  }, [columns]);
327
- return (jsx(DndProvider, { backend: HTML5Backend, children: jsx(Tooltip, { label: t("table.columnFilters.tooltip"), placement: "bottom", children: jsxs(Popover, { placement: "bottom-start", children: [jsx(PopoverTrigger, { children: jsx(Button, { prefix: jsx(Icon, { name: "ViewColumns", size: "small" }), size: "small", variant: "secondary", children: jsx("span", { className: "hidden md:block", children: t("table.columnFilters.columns") }) }) }), jsx(PopoverContent, { children: () => (jsxs(MenuList, { className: "relative max-h-[55vh] w-72 overflow-y-auto", children: [jsxs("div", { className: "mb-2 flex items-center gap-1", children: [jsx(Search, { autoFocus: true, className: "flex-1", fieldSize: "small", id: "column-search", onChange: e => setSearchText(e.currentTarget.value.toLowerCase()), onClear: () => setSearchText(""), placeholder: "Search", value: searchText }), jsx(Button, { onClick: resetHiddenColumns, size: "small", variant: "ghost-neutral", children: t("layout.actions.reset") })] }), jsx(ColumnFiltersDragAndDrop, { columns: sortedColumns, isSortDisabled: !!searchText, onUserEvent: onUserEvent, setColumnOrder: setColumnOrder, visibleColumnsCount: visibleColumnsCount })] })) })] }) }) }));
405
+ return (jsx(DndProvider, { backend: HTML5Backend, children: jsx(Tooltip, { label: t("table.columnFilters.tooltip"), placement: "bottom", children: jsxs(Popover, { placement: "bottom-start", children: [jsx(PopoverTrigger, { children: jsx(Button, { prefix: jsx(Icon, { name: "ViewColumns", size: "small" }), size: "small", variant: "secondary", children: jsx("span", { className: "hidden md:block", children: t("table.columnFilters.columns") }) }) }), jsx(PopoverContent, { children: () => (jsxs(MenuList, { className: "relative max-h-[55vh] w-72 overflow-y-auto", children: [jsxs("div", { className: "mb-2 flex items-center gap-1", children: [jsx(Search, { autoFocus: true, className: "flex-1", fieldSize: "small", id: "column-search", onChange: e => setSearchText(e.currentTarget.value.toLowerCase()), onClear: () => setSearchText(""), placeholder: "Search", value: searchText }), jsx(Button, { dataTestId: "resetColumnState", onClick: resetColumnState, size: "small", variant: "ghost-neutral", children: t("layout.actions.reset") })] }), jsx(ColumnFiltersDragAndDrop, { columns: sortedColumns, isSortDisabled: !!searchText, onUserEvent: onUserEvent, setColumnOrder: setColumnOrder, visibleColumnsCount: visibleColumnsCount })] })) })] }) }) }));
328
406
  };
329
407
  const ColumnFiltersDragAndDrop = ({ columns, setColumnOrder, onUserEvent, isSortDisabled, visibleColumnsCount, }) => {
330
408
  const [localColumns, setLocalColumns] = useState(columns);
@@ -368,59 +446,6 @@ const ColumnFiltersDragAndDrop = ({ columns, setColumnOrder, onUserEvent, isSort
368
446
  }, toggled: isVisible }, column.id));
369
447
  }) }));
370
448
  };
371
- const ItemTypes = {
372
- COLUMN: "column",
373
- };
374
- const ColumnFilterItem = ({ name, onToggle, toggled, disabled, index, moveColumn, onDrop, onCancelDrop, id, isSortDisabled, }) => {
375
- const ref = useRef(null);
376
- const [, drop] = useDrop({
377
- accept: ItemTypes.COLUMN,
378
- hover(item, monitor) {
379
- if (!ref.current) {
380
- return;
381
- }
382
- const dragIndex = item.index;
383
- const hoverIndex = index;
384
- if (dragIndex === hoverIndex) {
385
- return;
386
- }
387
- const hoverBoundingRect = ref.current.getBoundingClientRect();
388
- const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
389
- const clientOffset = monitor.getClientOffset();
390
- const hoverClientY = clientOffset.y - hoverBoundingRect.top;
391
- if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
392
- return;
393
- }
394
- if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
395
- return;
396
- }
397
- moveColumn(dragIndex, hoverIndex);
398
- item.index = hoverIndex;
399
- },
400
- drop(item, monitor) {
401
- onDrop();
402
- },
403
- });
404
- const [{ isDragging }, drag] = useDrag({
405
- type: ItemTypes.COLUMN,
406
- item: { type: ItemTypes.COLUMN, id, index },
407
- canDrag: !isSortDisabled,
408
- collect: (monitor) => ({
409
- isDragging: monitor.isDragging(),
410
- }),
411
- end(draggedItem, monitor) {
412
- if (!monitor.didDrop()) {
413
- onCancelDrop();
414
- }
415
- },
416
- });
417
- const opacity = isDragging ? 0 : 1;
418
- drag(drop(ref));
419
- return (jsxs("div", { className: cvaInteractableItem({
420
- selected: false,
421
- className: "grid w-full grid-cols-[min-content,1fr,min-content] items-center gap-2 py-1",
422
- }), ref: ref, style: { opacity: opacity }, children: [jsx("div", { className: cvaColumnFilterGrabbable({ disabled: isSortDisabled }), children: jsx(Icon, { color: "secondary", name: "EllipsisDrag", size: "small" }) }), jsxs("label", { className: "grid w-full grid-cols-[1fr,min-content] items-center gap-2", htmlFor: id, children: [jsxs("div", { className: "grid w-full grid-cols-[1fr,min-content] items-center", children: [jsx(Text, { className: cvaLabel(), children: name }), disabled ? jsx(Icon, { name: "LockClosed", size: "small" }) : null] }), jsx(ToggleSwitch, { disabled: disabled, id: id, onChange: (isToggled, event) => event && onToggle(isToggled, event), showInputFocus: false, size: "small", toggled: toggled })] })] }));
423
- };
424
449
 
425
450
  /**
426
451
  * RowSpacing component for managing the density of table rows.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/react-table",
3
- "version": "1.3.163",
3
+ "version": "1.3.167",
4
4
  "repository": "https://github.com/Trackunit/manager",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "engines": {
@@ -15,15 +15,16 @@
15
15
  "jest-fetch-mock": "^3.0.3",
16
16
  "@tanstack/react-router": "1.114.29",
17
17
  "tailwind-merge": "^2.0.0",
18
- "@trackunit/react-components": "1.4.132",
19
- "@trackunit/shared-utils": "1.5.109",
20
- "@trackunit/css-class-variance-utilities": "1.3.109",
21
- "@trackunit/ui-icons": "1.3.111",
22
- "@trackunit/react-table-base-components": "1.3.150",
23
- "@trackunit/react-table-pagination": "1.3.110",
24
- "@trackunit/react-form-components": "1.3.150",
25
- "@trackunit/i18n-library-translation": "1.3.123",
26
- "@trackunit/react-core-contexts-api": "1.4.115"
18
+ "@trackunit/react-components": "1.4.135",
19
+ "@trackunit/shared-utils": "1.5.112",
20
+ "@trackunit/css-class-variance-utilities": "1.3.112",
21
+ "@trackunit/ui-icons": "1.3.113",
22
+ "@trackunit/react-table-base-components": "1.3.153",
23
+ "@trackunit/react-table-pagination": "1.3.112",
24
+ "@trackunit/react-form-components": "1.3.153",
25
+ "@trackunit/i18n-library-translation": "1.3.126",
26
+ "@trackunit/react-core-contexts-api": "1.4.118",
27
+ "@trackunit/react-test-setup": "1.0.2"
27
28
  },
28
29
  "module": "./index.esm.js",
29
30
  "main": "./index.cjs.js",
@@ -1,10 +1,11 @@
1
- import { Column, ColumnOrderState, Updater } from "@tanstack/react-table";
1
+ import { Column, ColumnOrderState, ColumnSizingState, Updater } from "@tanstack/react-table";
2
2
  export interface ColumnFilterProps<TColumnFilter extends object, TColumnFilterValue> {
3
3
  columns: Column<TColumnFilter, TColumnFilterValue>[];
4
4
  defaultColumnOrder: ColumnOrderState;
5
5
  columnOrder?: ColumnOrderState;
6
6
  setColumnOrder: (updater: Updater<ColumnOrderState>) => void;
7
7
  onUserEvent?: (event: "Column Reordering" | "Column Filter", payload: Record<string, unknown>) => void;
8
+ setColumnSize: (updater: Updater<ColumnSizingState>) => void;
8
9
  }
9
10
  /**
10
11
  * ColumnFilter component for managing visibility and order of table columns.
@@ -14,7 +15,7 @@ export interface ColumnFilterProps<TColumnFilter extends object, TColumnFilterVa
14
15
  * @param {ColumnFilterProps<TColumnFilter, TColumnFilterValue>} props - The props object containing necessary properties.
15
16
  * @returns {ReactElement | null} A React JSX element representing the ColumnFilter component or null if columns are not provided.
16
17
  */
17
- export declare const ColumnFilter: <TColumnFilter extends object, TColumnFilterValue>({ columns, setColumnOrder, defaultColumnOrder, columnOrder, onUserEvent, }: ColumnFilterProps<TColumnFilter, TColumnFilterValue>) => import("react/jsx-runtime").JSX.Element;
18
+ export declare const ColumnFilter: <TColumnFilter extends object, TColumnFilterValue>({ columns, setColumnOrder, defaultColumnOrder, columnOrder, onUserEvent, setColumnSize, }: ColumnFilterProps<TColumnFilter, TColumnFilterValue>) => import("react/jsx-runtime").JSX.Element;
18
19
  export interface ColumnFiltersDragAndDropProps<TColumnFiltersDragAndDrop extends object, TColumnFiltersDragAndDropValue> {
19
20
  columns: Column<TColumnFiltersDragAndDrop, TColumnFiltersDragAndDropValue>[];
20
21
  setColumnOrder: (updater: Updater<ColumnOrderState>) => void;
@@ -0,0 +1,32 @@
1
+ import { ChangeEvent } from "react";
2
+ interface ColumnFilterItemProps {
3
+ name: string;
4
+ onToggle: (toggled: boolean, event: ChangeEvent<HTMLInputElement>) => void;
5
+ toggled: boolean;
6
+ disabled: boolean;
7
+ onDrop: () => void;
8
+ onCancelDrop: () => void;
9
+ moveColumn: (dragIndex: number, hoverIndex: number) => void;
10
+ index: number;
11
+ id: string;
12
+ isSortDisabled?: boolean;
13
+ }
14
+ /**
15
+ * Component for rendering an individual column filter item with drag-and-drop,
16
+ * toggle, and locking capabilities.
17
+ *
18
+ * @param {object} props - Props for the component.
19
+ * @param {string} props.name - The name of the column.
20
+ * @param {(toggled: boolean, event: ChangeEvent<HTMLInputElement>) => void} props.onToggle - Callback for when a column's toggled state changes.
21
+ * @param {boolean} props.toggled - Whether the column is toggled on or off.
22
+ * @param {boolean} props.disabled - Whether the toggle or drag functionality is disabled.
23
+ * @param {number} props.index - The index of the current column in the list.
24
+ * @param {(dragIndex: number, hoverIndex: number) => void} props.moveColumn - Function to move columns during drag-and-drop.
25
+ * @param {() => void} props.onDrop - Callback when a column is dropped.
26
+ * @param {() => void} props.onCancelDrop - Callback for canceling a drop action.
27
+ * @param {string} props.id - Unique identifier for the column.
28
+ * @param {boolean} [props.isSortDisabled] - Optional flag to disable sorting.
29
+ * @returns {JSX.Element} A React component rendering the column filter item.
30
+ */
31
+ export declare const ColumnFilterItem: ({ name, onToggle, toggled, disabled, index, moveColumn, onDrop, onCancelDrop, id, isSortDisabled, }: ColumnFilterItemProps) => import("react/jsx-runtime").JSX.Element;
32
+ export {};