@trackunit/react-filter-components 1.3.131 → 1.3.133
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 +27 -8
- package/index.esm.js +29 -10
- package/package.json +5 -4
- package/src/Filter/Filter.d.ts +18 -2
- package/src/FilterBody/FilterBody.d.ts +1 -1
- package/src/FilterHeader/FilterHeader.d.ts +11 -7
package/index.cjs.js
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
4
4
|
var cssClassVarianceUtilities = require('@trackunit/css-class-variance-utilities');
|
5
5
|
var reactComponents = require('@trackunit/react-components');
|
6
|
+
var react = require('react');
|
6
7
|
var tailwindMerge = require('tailwind-merge');
|
7
8
|
var reactFormComponents = require('@trackunit/react-form-components');
|
8
9
|
|
@@ -30,9 +31,27 @@ const cvaFilterCustomButton = cssClassVarianceUtilities.cvaMerge(["justify-norma
|
|
30
31
|
* @param {FilterProps} props - The props for the Filter component
|
31
32
|
* @returns {ReactElement} Filter component
|
32
33
|
*/
|
33
|
-
const Filter = ({ title, children, popoverProps, isActive, activeLabel, menuListProps, className, dataTestId, withStickyHeader = false, readOnly,
|
34
|
-
const
|
35
|
-
|
34
|
+
const Filter = ({ title, asIcon, children, popoverProps, isActive, activeLabel, activeOptionsCount, menuListProps, className, dataTestId, withStickyHeader = false, readOnly, visualStyle = "button", size = "small", }) => {
|
35
|
+
const handleClick = react.useCallback((event) => {
|
36
|
+
event.stopPropagation();
|
37
|
+
}, []);
|
38
|
+
const renderButton = () => {
|
39
|
+
if (asIcon) {
|
40
|
+
return (jsxRuntime.jsx(reactComponents.IconButton, { className: className, dataTestId: dataTestId, disabled: readOnly, icon: jsxRuntime.jsx(reactComponents.Icon, { color: isActive ? "primary" : undefined, name: asIcon, size: "small" }), onClick: handleClick, size: size, variant: "ghost-neutral" }));
|
41
|
+
}
|
42
|
+
return (jsxRuntime.jsxs(reactComponents.Button, { className: cvaFilterCustomButton({ isActive, className }), dataTestId: dataTestId, disabled: readOnly, onClick: handleClick, size: size, variant: "secondary", children: [title, isActive ? (jsxRuntime.jsx("div", { className: "grid overflow-hidden text-ellipsis whitespace-nowrap", children: jsxRuntime.jsx("span", { className: "text-primary-600 truncate", children: activeLabel }) })) : null] }));
|
43
|
+
};
|
44
|
+
return (jsxRuntime.jsx(reactComponents.Popover, { dataTestId: dataTestId ? `${dataTestId}-popover` : undefined, placement: "top-start", ...popoverProps, children: modalState => {
|
45
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(reactComponents.PopoverTrigger, { children: visualStyle === "list-item" ? (jsxRuntime.jsxs("li", { className: reactComponents.cvaInteractableItem({
|
46
|
+
disabled: readOnly,
|
47
|
+
selected: modalState.isOpen,
|
48
|
+
cursor: "pointer",
|
49
|
+
className: [
|
50
|
+
className,
|
51
|
+
"text-secondary-700 hover:text-secondary-800 grid list-none grid-flow-col items-center justify-between gap-1 rounded px-3 py-2 text-sm",
|
52
|
+
],
|
53
|
+
}), "data-testid": dataTestId, tabIndex: 0, children: [jsxRuntime.jsx("span", { className: tailwindMerge.twMerge("truncate", isActive && "font-semibold"), children: title }), jsxRuntime.jsxs("span", { className: "grid grid-flow-col items-center justify-between text-slate-900", children: [isActive && activeLabel ? (jsxRuntime.jsx(reactComponents.Badge, { className: !activeOptionsCount ? "mx-2" : "mx-1", compact: !activeOptionsCount, count: activeOptionsCount })) : null, readOnly ? null : jsxRuntime.jsx(reactComponents.Icon, { ariaHidden: true, color: "secondary", name: "ChevronRight", size: "small" })] })] })) : (renderButton()) }), jsxRuntime.jsx(reactComponents.PopoverContent, { children: jsxRuntime.jsx(reactComponents.MenuList, { className: cvaMenuListOverrides({ withStickyHeader }), dataTestId: dataTestId ? dataTestId : undefined, withStickyHeader: withStickyHeader, ...menuListProps, children: children }) })] }));
|
54
|
+
} }));
|
36
55
|
};
|
37
56
|
const cvaMenuListOverrides = cssClassVarianceUtilities.cvaMerge(["overflow-x-hidden", "relative", "!max-w-full", "p-0"], {
|
38
57
|
variants: {
|
@@ -46,7 +65,7 @@ const cvaMenuListOverrides = cssClassVarianceUtilities.cvaMerge(["overflow-x-hid
|
|
46
65
|
/**
|
47
66
|
* The FilterBody component is used to display the title of the filter and a reset button.
|
48
67
|
* IT is intended for use in the Filter component.
|
49
|
-
* The reset button will
|
68
|
+
* The reset button will be enabled if the showReset prop is set to true.
|
50
69
|
*
|
51
70
|
* @param {FilterBodyProps} props - The props for the FilterBody component
|
52
71
|
*/
|
@@ -82,13 +101,13 @@ const cvaFilterFooter = cssClassVarianceUtilities.cvaMerge(["flex", "justify-end
|
|
82
101
|
/**
|
83
102
|
* The FilterHeader component is used to display the title of the filter and a reset button.
|
84
103
|
* IT is intended for use in the Filter component.
|
85
|
-
* The reset button will only be
|
104
|
+
* The reset button will only be enabled if the showReset prop is set to true.
|
86
105
|
*
|
87
106
|
* @param {FilterHeaderProps} props - The props for the FilterHeader component
|
88
107
|
* @returns {ReactElement} FilterHeader component
|
89
108
|
*/
|
90
|
-
const FilterHeader = ({ title, resetLabel, showReset,
|
91
|
-
return (jsxRuntime.
|
109
|
+
const FilterHeader = ({ dataTestId, title, resetLabel, showReset, onReset, loading, children, searchComponent, className, ...rest }) => {
|
110
|
+
return (jsxRuntime.jsx("div", { className: tailwindMerge.twMerge(className, "p-1", "min-w-[280px]"), ...rest, "data-testid": dataTestId, children: title ? (jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-between gap-1 text-sm font-medium uppercase text-slate-600", children: [searchComponent, jsxRuntime.jsxs("div", { className: "flex w-full justify-between gap-1", children: [children, jsxRuntime.jsx("div", { className: "ml-auto", children: loading ? (jsxRuntime.jsx(reactComponents.Spinner, { size: "small" })) : (jsxRuntime.jsx(reactComponents.Button, { "data-testid": `${dataTestId}-reset-button`, disabled: !showReset, onClick: onReset, size: "small", variant: "ghost", children: resetLabel })) })] }), jsxRuntime.jsx("hr", { className: "w-full border-slate-200" })] })) : null }));
|
92
111
|
};
|
93
112
|
const cvaFilterHeaderButton = cssClassVarianceUtilities.cvaMerge([], {
|
94
113
|
variants: {
|
@@ -113,7 +132,7 @@ const CheckBoxFilterItem = ({ itemCount, className, suffix, dataTestId, label, .
|
|
113
132
|
return (jsxRuntime.jsx(reactFormComponents.Checkbox, { className: reactComponents.cvaInteractableItem({
|
114
133
|
selected: "auto",
|
115
134
|
focused: "auto",
|
116
|
-
className: tailwindMerge.twMerge(["py-1", "pl-2", "pr-3", "w-
|
135
|
+
className: tailwindMerge.twMerge(["py-1", "mx-1", "pl-2", "pr-3", "w-auto", "h-auto", "items-center", "gap-x-2", "select-none", "rounded"], className),
|
117
136
|
}), dataTestId: dataTestId ?? `${label}-checkbox-filter-item`, label: label, suffix: itemCount !== undefined || suffix ? (jsxRuntime.jsxs("span", { className: reactComponents.cvaMenuItemSuffix({ selected: rest.checked }), children: [suffix, itemCount === undefined ? null : itemCount] })) : null, ...rest }));
|
118
137
|
};
|
119
138
|
|
package/index.esm.js
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
import { jsxs,
|
1
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
2
2
|
import { cvaMerge } from '@trackunit/css-class-variance-utilities';
|
3
|
-
import { Popover, PopoverTrigger,
|
3
|
+
import { Popover, PopoverTrigger, cvaInteractableItem, Badge, Icon, PopoverContent, MenuList, IconButton, Button, Spinner, cvaMenuItemSuffix } from '@trackunit/react-components';
|
4
|
+
import { useCallback } from 'react';
|
4
5
|
import { twMerge } from 'tailwind-merge';
|
5
6
|
import { Checkbox, RadioItem } from '@trackunit/react-form-components';
|
6
7
|
|
@@ -28,9 +29,27 @@ const cvaFilterCustomButton = cvaMerge(["justify-normal"], {
|
|
28
29
|
* @param {FilterProps} props - The props for the Filter component
|
29
30
|
* @returns {ReactElement} Filter component
|
30
31
|
*/
|
31
|
-
const Filter = ({ title, children, popoverProps, isActive, activeLabel, menuListProps, className, dataTestId, withStickyHeader = false, readOnly,
|
32
|
-
const
|
33
|
-
|
32
|
+
const Filter = ({ title, asIcon, children, popoverProps, isActive, activeLabel, activeOptionsCount, menuListProps, className, dataTestId, withStickyHeader = false, readOnly, visualStyle = "button", size = "small", }) => {
|
33
|
+
const handleClick = useCallback((event) => {
|
34
|
+
event.stopPropagation();
|
35
|
+
}, []);
|
36
|
+
const renderButton = () => {
|
37
|
+
if (asIcon) {
|
38
|
+
return (jsx(IconButton, { className: className, dataTestId: dataTestId, disabled: readOnly, icon: jsx(Icon, { color: isActive ? "primary" : undefined, name: asIcon, size: "small" }), onClick: handleClick, size: size, variant: "ghost-neutral" }));
|
39
|
+
}
|
40
|
+
return (jsxs(Button, { className: cvaFilterCustomButton({ isActive, className }), dataTestId: dataTestId, disabled: readOnly, onClick: handleClick, size: size, variant: "secondary", children: [title, isActive ? (jsx("div", { className: "grid overflow-hidden text-ellipsis whitespace-nowrap", children: jsx("span", { className: "text-primary-600 truncate", children: activeLabel }) })) : null] }));
|
41
|
+
};
|
42
|
+
return (jsx(Popover, { dataTestId: dataTestId ? `${dataTestId}-popover` : undefined, placement: "top-start", ...popoverProps, children: modalState => {
|
43
|
+
return (jsxs(Fragment, { children: [jsx(PopoverTrigger, { children: visualStyle === "list-item" ? (jsxs("li", { className: cvaInteractableItem({
|
44
|
+
disabled: readOnly,
|
45
|
+
selected: modalState.isOpen,
|
46
|
+
cursor: "pointer",
|
47
|
+
className: [
|
48
|
+
className,
|
49
|
+
"text-secondary-700 hover:text-secondary-800 grid list-none grid-flow-col items-center justify-between gap-1 rounded px-3 py-2 text-sm",
|
50
|
+
],
|
51
|
+
}), "data-testid": dataTestId, tabIndex: 0, children: [jsx("span", { className: twMerge("truncate", isActive && "font-semibold"), children: title }), jsxs("span", { className: "grid grid-flow-col items-center justify-between text-slate-900", children: [isActive && activeLabel ? (jsx(Badge, { className: !activeOptionsCount ? "mx-2" : "mx-1", compact: !activeOptionsCount, count: activeOptionsCount })) : null, readOnly ? null : jsx(Icon, { ariaHidden: true, color: "secondary", name: "ChevronRight", size: "small" })] })] })) : (renderButton()) }), jsx(PopoverContent, { children: jsx(MenuList, { className: cvaMenuListOverrides({ withStickyHeader }), dataTestId: dataTestId ? dataTestId : undefined, withStickyHeader: withStickyHeader, ...menuListProps, children: children }) })] }));
|
52
|
+
} }));
|
34
53
|
};
|
35
54
|
const cvaMenuListOverrides = cvaMerge(["overflow-x-hidden", "relative", "!max-w-full", "p-0"], {
|
36
55
|
variants: {
|
@@ -44,7 +63,7 @@ const cvaMenuListOverrides = cvaMerge(["overflow-x-hidden", "relative", "!max-w-
|
|
44
63
|
/**
|
45
64
|
* The FilterBody component is used to display the title of the filter and a reset button.
|
46
65
|
* IT is intended for use in the Filter component.
|
47
|
-
* The reset button will
|
66
|
+
* The reset button will be enabled if the showReset prop is set to true.
|
48
67
|
*
|
49
68
|
* @param {FilterBodyProps} props - The props for the FilterBody component
|
50
69
|
*/
|
@@ -80,13 +99,13 @@ const cvaFilterFooter = cvaMerge(["flex", "justify-end", "p-1"]);
|
|
80
99
|
/**
|
81
100
|
* The FilterHeader component is used to display the title of the filter and a reset button.
|
82
101
|
* IT is intended for use in the Filter component.
|
83
|
-
* The reset button will only be
|
102
|
+
* The reset button will only be enabled if the showReset prop is set to true.
|
84
103
|
*
|
85
104
|
* @param {FilterHeaderProps} props - The props for the FilterHeader component
|
86
105
|
* @returns {ReactElement} FilterHeader component
|
87
106
|
*/
|
88
|
-
const FilterHeader = ({ title, resetLabel, showReset,
|
89
|
-
return (
|
107
|
+
const FilterHeader = ({ dataTestId, title, resetLabel, showReset, onReset, loading, children, searchComponent, className, ...rest }) => {
|
108
|
+
return (jsx("div", { className: twMerge(className, "p-1", "min-w-[280px]"), ...rest, "data-testid": dataTestId, children: title ? (jsxs("div", { className: "flex flex-col items-center justify-between gap-1 text-sm font-medium uppercase text-slate-600", children: [searchComponent, jsxs("div", { className: "flex w-full justify-between gap-1", children: [children, jsx("div", { className: "ml-auto", children: loading ? (jsx(Spinner, { size: "small" })) : (jsx(Button, { "data-testid": `${dataTestId}-reset-button`, disabled: !showReset, onClick: onReset, size: "small", variant: "ghost", children: resetLabel })) })] }), jsx("hr", { className: "w-full border-slate-200" })] })) : null }));
|
90
109
|
};
|
91
110
|
const cvaFilterHeaderButton = cvaMerge([], {
|
92
111
|
variants: {
|
@@ -111,7 +130,7 @@ const CheckBoxFilterItem = ({ itemCount, className, suffix, dataTestId, label, .
|
|
111
130
|
return (jsx(Checkbox, { className: cvaInteractableItem({
|
112
131
|
selected: "auto",
|
113
132
|
focused: "auto",
|
114
|
-
className: twMerge(["py-1", "pl-2", "pr-3", "w-
|
133
|
+
className: twMerge(["py-1", "mx-1", "pl-2", "pr-3", "w-auto", "h-auto", "items-center", "gap-x-2", "select-none", "rounded"], className),
|
115
134
|
}), dataTestId: dataTestId ?? `${label}-checkbox-filter-item`, label: label, suffix: itemCount !== undefined || suffix ? (jsxs("span", { className: cvaMenuItemSuffix({ selected: rest.checked }), children: [suffix, itemCount === undefined ? null : itemCount] })) : null, ...rest }));
|
116
135
|
};
|
117
136
|
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@trackunit/react-filter-components",
|
3
|
-
"version": "1.3.
|
3
|
+
"version": "1.3.133",
|
4
4
|
"repository": "https://github.com/Trackunit/manager",
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
6
6
|
"engines": {
|
@@ -9,9 +9,10 @@
|
|
9
9
|
"dependencies": {
|
10
10
|
"react": "19.0.0",
|
11
11
|
"tailwind-merge": "^2.0.0",
|
12
|
-
"@trackunit/
|
13
|
-
"@trackunit/
|
14
|
-
"@trackunit/react-
|
12
|
+
"@trackunit/ui-icons": "1.3.99",
|
13
|
+
"@trackunit/css-class-variance-utilities": "1.3.98",
|
14
|
+
"@trackunit/react-components": "1.4.117",
|
15
|
+
"@trackunit/react-form-components": "1.3.133"
|
15
16
|
},
|
16
17
|
"module": "./index.esm.js",
|
17
18
|
"main": "./index.cjs.js",
|
package/src/Filter/Filter.d.ts
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
import { ButtonProps, MenuListProps, PopoverProps } from "@trackunit/react-components";
|
2
|
+
import { IconName } from "@trackunit/ui-icons";
|
2
3
|
import { ReactElement } from "react";
|
4
|
+
export type FilterVisualStyle = "button" | "list-item";
|
3
5
|
export interface FilterProps extends ButtonProps {
|
4
6
|
/**
|
5
7
|
* The title/name of the filter.
|
6
8
|
*/
|
7
|
-
title
|
9
|
+
title?: string;
|
8
10
|
/**
|
9
11
|
* Used to indicate if the user has any active selection in the filter.
|
10
12
|
*/
|
@@ -13,6 +15,14 @@ export interface FilterProps extends ButtonProps {
|
|
13
15
|
* The label that will be displayed when the filter is active.
|
14
16
|
*/
|
15
17
|
activeLabel?: string;
|
18
|
+
/**
|
19
|
+
* The number of active options for multi select filters.
|
20
|
+
*/
|
21
|
+
activeOptionsCount?: number;
|
22
|
+
/**
|
23
|
+
* The icon to be displayed in the filter button.
|
24
|
+
*/
|
25
|
+
asIcon?: IconName;
|
16
26
|
/**
|
17
27
|
* When enabled the menu list padding will be removed, and a grid will be applied to keep the first column "sticky".
|
18
28
|
* This intended to be used withe the FilterHeader component.
|
@@ -38,6 +48,12 @@ export interface FilterProps extends ButtonProps {
|
|
38
48
|
* A flag to set a filter component into readonly mode used for presenting filtering rules that cannot be change by user
|
39
49
|
*/
|
40
50
|
readOnly?: boolean;
|
51
|
+
/**
|
52
|
+
* The visual style of the filter. List-item or Button.
|
53
|
+
*
|
54
|
+
* @default "button"
|
55
|
+
*/
|
56
|
+
visualStyle?: FilterVisualStyle;
|
41
57
|
}
|
42
58
|
/**
|
43
59
|
* The Filter component is the base component used in the manager to filter data.
|
@@ -51,4 +67,4 @@ export interface FilterProps extends ButtonProps {
|
|
51
67
|
* @param {FilterProps} props - The props for the Filter component
|
52
68
|
* @returns {ReactElement} Filter component
|
53
69
|
*/
|
54
|
-
export declare const Filter: ({ title, children, popoverProps, isActive, activeLabel, menuListProps, className, dataTestId, withStickyHeader, readOnly,
|
70
|
+
export declare const Filter: ({ title, asIcon, children, popoverProps, isActive, activeLabel, activeOptionsCount, menuListProps, className, dataTestId, withStickyHeader, readOnly, visualStyle, size, }: FilterProps) => ReactElement;
|
@@ -15,7 +15,7 @@ export interface FilterBodyProps extends CommonProps {
|
|
15
15
|
/**
|
16
16
|
* The FilterBody component is used to display the title of the filter and a reset button.
|
17
17
|
* IT is intended for use in the Filter component.
|
18
|
-
* The reset button will
|
18
|
+
* The reset button will be enabled if the showReset prop is set to true.
|
19
19
|
*
|
20
20
|
* @param {FilterBodyProps} props - The props for the FilterBody component
|
21
21
|
*/
|
@@ -1,12 +1,12 @@
|
|
1
1
|
import { CommonProps } from "@trackunit/react-components";
|
2
|
-
import { ReactNode } from "react";
|
2
|
+
import { ReactElement, ReactNode } from "react";
|
3
3
|
export interface FilterHeaderProps extends CommonProps {
|
4
4
|
/**
|
5
5
|
* The title of the filter will be displayed in the header.
|
6
6
|
*/
|
7
|
-
title
|
7
|
+
title?: string;
|
8
8
|
/**
|
9
|
-
* Used to indicate if the user has any active selection in the filter.
|
9
|
+
* Used to indicate if the user has any active selection in the filter that can be reset.
|
10
10
|
*/
|
11
11
|
showReset?: boolean;
|
12
12
|
/**
|
@@ -19,20 +19,24 @@ export interface FilterHeaderProps extends CommonProps {
|
|
19
19
|
*/
|
20
20
|
onReset?: () => void;
|
21
21
|
/**
|
22
|
-
* Optional
|
23
|
-
|
22
|
+
* Optional search component to render in the header.
|
23
|
+
*/
|
24
|
+
searchComponent?: ReactNode;
|
25
|
+
/**
|
26
|
+
* Optional elements to render along the reset button.
|
27
|
+
* For example: a "Select All" button.
|
24
28
|
*/
|
25
29
|
children?: ReactNode;
|
26
30
|
}
|
27
31
|
/**
|
28
32
|
* The FilterHeader component is used to display the title of the filter and a reset button.
|
29
33
|
* IT is intended for use in the Filter component.
|
30
|
-
* The reset button will only be
|
34
|
+
* The reset button will only be enabled if the showReset prop is set to true.
|
31
35
|
*
|
32
36
|
* @param {FilterHeaderProps} props - The props for the FilterHeader component
|
33
37
|
* @returns {ReactElement} FilterHeader component
|
34
38
|
*/
|
35
|
-
export declare const FilterHeader: ({ title, resetLabel, showReset,
|
39
|
+
export declare const FilterHeader: ({ dataTestId, title, resetLabel, showReset, onReset, loading, children, searchComponent, className, ...rest }: FilterHeaderProps) => ReactElement;
|
36
40
|
export declare const cvaFilterHeaderButton: (props?: ({
|
37
41
|
isVisible?: boolean | null | undefined;
|
38
42
|
} & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
|