@wallarm-org/design-system 0.82.0 → 0.83.0
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/components/DropdownMenu/DropdownMenuLabel.js +3 -2
- package/dist/components/DropdownMenu/classes.d.ts +1 -0
- package/dist/components/DropdownMenu/classes.js +3 -0
- package/dist/components/FilterInput/FilterInputField/FilterInputConnectorChip/FilterInputConnectorChip.js +1 -0
- package/dist/components/FilterInput/FilterInputMenu/FilterInputFieldMenu/FieldMenuSections.js +94 -72
- package/dist/components/FilterInput/FilterInputMenu/FilterInputFieldMenu/FilterInputFieldMenu.js +1 -0
- package/dist/components/FilterInput/FilterInputMenu/FilterInputOperatorMenu.js +1 -0
- package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/FlatValueMenu.js +2 -0
- package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/NestedValueMenu.js +62 -36
- package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/NestedValueMenuItem.d.ts +12 -4
- package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/NestedValueMenuItem.js +49 -15
- package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/ValueMenuItem.js +2 -2
- package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/useNestedValueMenuState.d.ts +4 -0
- package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/useNestedValueMenuState.js +34 -12
- package/dist/components/FilterInput/lib/buildValueMenuSections.d.ts +19 -3
- package/dist/components/FilterInput/lib/buildValueMenuSections.js +71 -6
- package/dist/metadata/components.json +8 -2
- package/package.json +1 -1
|
@@ -2,12 +2,13 @@ import { jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { cn } from "../../utils/cn.js";
|
|
3
3
|
import { useTestId } from "../../utils/testId.js";
|
|
4
4
|
import { dropdownMenuLabelVariants } from "./classes.js";
|
|
5
|
-
const DropdownMenuLabel = ({ className, inset, ...props })=>{
|
|
5
|
+
const DropdownMenuLabel = ({ className, inset, sticky, ...props })=>{
|
|
6
6
|
const testId = useTestId('label');
|
|
7
7
|
return /*#__PURE__*/ jsx("div", {
|
|
8
8
|
"data-testid": testId,
|
|
9
9
|
className: cn(dropdownMenuLabelVariants({
|
|
10
|
-
inset
|
|
10
|
+
inset,
|
|
11
|
+
sticky
|
|
11
12
|
}), className),
|
|
12
13
|
...props
|
|
13
14
|
});
|
|
@@ -6,4 +6,5 @@ export declare const dropdownMenuItemVariants: (props?: ({
|
|
|
6
6
|
export declare const dropdownMenuItemIndicatorClassName: string;
|
|
7
7
|
export declare const dropdownMenuLabelVariants: (props?: ({
|
|
8
8
|
inset?: boolean | null | undefined;
|
|
9
|
+
sticky?: boolean | null | undefined;
|
|
9
10
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
package/dist/components/FilterInput/FilterInputMenu/FilterInputFieldMenu/FieldMenuSections.js
CHANGED
|
@@ -5,40 +5,46 @@ import { CircleSlash } from "../../../../icons/CircleSlash.js";
|
|
|
5
5
|
import { DropdownMenuGroup, DropdownMenuItem, DropdownMenuItemIcon, DropdownMenuItemText, DropdownMenuLabel, DropdownMenuSeparator } from "../../../DropdownMenu/index.js";
|
|
6
6
|
const RecentSection = ({ conditions, fields, onSelect, registerItem })=>/*#__PURE__*/ jsxs(Fragment, {
|
|
7
7
|
children: [
|
|
8
|
-
/*#__PURE__*/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
8
|
+
/*#__PURE__*/ jsxs("div", {
|
|
9
|
+
className: "flex flex-col gap-1",
|
|
10
|
+
children: [
|
|
11
|
+
/*#__PURE__*/ jsx(DropdownMenuLabel, {
|
|
12
|
+
sticky: true,
|
|
13
|
+
children: "Recent"
|
|
14
|
+
}),
|
|
15
|
+
/*#__PURE__*/ jsx(DropdownMenuGroup, {
|
|
16
|
+
children: conditions.map((condition, index)=>{
|
|
17
|
+
const fieldMeta = fields.find((f)=>f.name === condition.field);
|
|
18
|
+
const attribute = fieldMeta?.label || condition.field;
|
|
19
|
+
const operator = String(condition.operator);
|
|
20
|
+
const value = String(condition.value);
|
|
21
|
+
return /*#__PURE__*/ jsx(DropdownMenuItem, {
|
|
22
|
+
value: `recent-${index}`,
|
|
23
|
+
ref: registerItem(`recent-${index}`),
|
|
24
|
+
onSelect: ()=>{
|
|
25
|
+
if (fieldMeta) onSelect(fieldMeta);
|
|
26
|
+
},
|
|
27
|
+
children: /*#__PURE__*/ jsxs("span", {
|
|
28
|
+
className: "flex gap-2 items-center text-sm",
|
|
29
|
+
children: [
|
|
30
|
+
/*#__PURE__*/ jsx("span", {
|
|
31
|
+
className: "text-text-primary",
|
|
32
|
+
children: attribute
|
|
33
|
+
}),
|
|
34
|
+
/*#__PURE__*/ jsx("span", {
|
|
35
|
+
className: "text-text-secondary",
|
|
36
|
+
children: operator
|
|
37
|
+
}),
|
|
38
|
+
/*#__PURE__*/ jsx("span", {
|
|
39
|
+
className: "font-medium text-text-info",
|
|
40
|
+
children: value
|
|
41
|
+
})
|
|
42
|
+
]
|
|
37
43
|
})
|
|
38
|
-
|
|
44
|
+
}, `recent-${index}`);
|
|
39
45
|
})
|
|
40
|
-
}
|
|
41
|
-
|
|
46
|
+
})
|
|
47
|
+
]
|
|
42
48
|
}),
|
|
43
49
|
/*#__PURE__*/ jsx(DropdownMenuSeparator, {})
|
|
44
50
|
]
|
|
@@ -46,32 +52,38 @@ const RecentSection = ({ conditions, fields, onSelect, registerItem })=>/*#__PUR
|
|
|
46
52
|
RecentSection.displayName = 'RecentSection';
|
|
47
53
|
const SuggestionsSection = ({ fields, onSelect, registerItem })=>/*#__PURE__*/ jsxs(Fragment, {
|
|
48
54
|
children: [
|
|
49
|
-
/*#__PURE__*/
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
children:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
55
|
+
/*#__PURE__*/ jsxs("div", {
|
|
56
|
+
className: "flex flex-col gap-1",
|
|
57
|
+
children: [
|
|
58
|
+
/*#__PURE__*/ jsx(DropdownMenuLabel, {
|
|
59
|
+
sticky: true,
|
|
60
|
+
children: "Suggestions"
|
|
61
|
+
}),
|
|
62
|
+
/*#__PURE__*/ jsx(DropdownMenuGroup, {
|
|
63
|
+
children: fields.map((field, index)=>/*#__PURE__*/ jsx(DropdownMenuItem, {
|
|
64
|
+
value: `suggested-${index}`,
|
|
65
|
+
ref: registerItem(`suggested-${index}`),
|
|
66
|
+
onSelect: ()=>onSelect(field),
|
|
67
|
+
children: /*#__PURE__*/ jsxs("span", {
|
|
68
|
+
className: "flex gap-2 items-center text-sm",
|
|
69
|
+
children: [
|
|
70
|
+
/*#__PURE__*/ jsx("span", {
|
|
71
|
+
className: "text-text-primary",
|
|
72
|
+
children: field.label
|
|
73
|
+
}),
|
|
74
|
+
/*#__PURE__*/ jsx("span", {
|
|
75
|
+
className: "text-text-secondary",
|
|
76
|
+
children: "operator"
|
|
77
|
+
}),
|
|
78
|
+
/*#__PURE__*/ jsx("span", {
|
|
79
|
+
className: "font-medium text-text-info",
|
|
80
|
+
children: "Value"
|
|
81
|
+
})
|
|
82
|
+
]
|
|
71
83
|
})
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
84
|
+
}, `suggested-${index}`))
|
|
85
|
+
})
|
|
86
|
+
]
|
|
75
87
|
}),
|
|
76
88
|
/*#__PURE__*/ jsx(DropdownMenuSeparator, {})
|
|
77
89
|
]
|
|
@@ -110,24 +122,34 @@ const OperatorsSection = ({ onSelectAnd, onSelectOr, registerItem })=>/*#__PURE_
|
|
|
110
122
|
});
|
|
111
123
|
OperatorsSection.displayName = 'OperatorsSection';
|
|
112
124
|
const FieldSections = ({ sections, onSelect, registerItem })=>/*#__PURE__*/ jsx(Fragment, {
|
|
113
|
-
children: sections.map((section, index)
|
|
125
|
+
children: sections.map((section, index)=>{
|
|
126
|
+
const group = /*#__PURE__*/ jsx(DropdownMenuGroup, {
|
|
127
|
+
children: section.fields.map((field)=>/*#__PURE__*/ jsx(DropdownMenuItem, {
|
|
128
|
+
value: `field-${field.name}`,
|
|
129
|
+
ref: registerItem(`field-${field.name}`),
|
|
130
|
+
onSelect: ()=>onSelect(field),
|
|
131
|
+
className: "scroll-mt-32",
|
|
132
|
+
children: /*#__PURE__*/ jsx(DropdownMenuItemText, {
|
|
133
|
+
children: field.label
|
|
134
|
+
})
|
|
135
|
+
}, field.name))
|
|
136
|
+
});
|
|
137
|
+
return /*#__PURE__*/ jsxs(external_react_Fragment, {
|
|
114
138
|
children: [
|
|
115
139
|
index > 0 && /*#__PURE__*/ jsx(DropdownMenuSeparator, {}),
|
|
116
|
-
section.label
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
})
|
|
127
|
-
}, field.name))
|
|
128
|
-
})
|
|
140
|
+
section.label ? /*#__PURE__*/ jsxs("div", {
|
|
141
|
+
className: "flex flex-col gap-1",
|
|
142
|
+
children: [
|
|
143
|
+
/*#__PURE__*/ jsx(DropdownMenuLabel, {
|
|
144
|
+
sticky: true,
|
|
145
|
+
children: section.label
|
|
146
|
+
}),
|
|
147
|
+
group
|
|
148
|
+
]
|
|
149
|
+
}) : group
|
|
129
150
|
]
|
|
130
|
-
}, `${section.label ?? 'ungrouped'}-${index}`)
|
|
151
|
+
}, `${section.label ?? 'ungrouped'}-${index}`);
|
|
152
|
+
})
|
|
131
153
|
});
|
|
132
154
|
FieldSections.displayName = 'FieldSections';
|
|
133
155
|
export { FieldSections, OperatorsSection, RecentSection, SuggestionsSection };
|
package/dist/components/FilterInput/FilterInputMenu/FilterInputFieldMenu/FilterInputFieldMenu.js
CHANGED
|
@@ -84,6 +84,7 @@ const FilterInputFieldMenu = ({ fields, filterText = '', onSelect, open = false,
|
|
|
84
84
|
registerItem: registerItem
|
|
85
85
|
}),
|
|
86
86
|
/*#__PURE__*/ jsxs(DropdownMenuFooter, {
|
|
87
|
+
className: "justify-start",
|
|
87
88
|
children: [
|
|
88
89
|
/*#__PURE__*/ jsxs("span", {
|
|
89
90
|
className: "flex items-center gap-4",
|
|
@@ -83,6 +83,7 @@ const FilterInputOperatorMenu = ({ fieldType, operators, onSelect, open = false,
|
|
|
83
83
|
]
|
|
84
84
|
}, `group-${groupIdx}`)) : /*#__PURE__*/ jsx(MenuEmptyState, {}),
|
|
85
85
|
/*#__PURE__*/ jsx(DropdownMenuFooter, {
|
|
86
|
+
className: "justify-start",
|
|
86
87
|
children: /*#__PURE__*/ jsxs("span", {
|
|
87
88
|
className: "flex items-center gap-4",
|
|
88
89
|
children: [
|
|
@@ -55,6 +55,7 @@ const FlatValueMenu = ({ values, onSelect, onCommit, open = false, onOpenChange,
|
|
|
55
55
|
"data-filter-input-menu": "true",
|
|
56
56
|
children: [
|
|
57
57
|
displayValues.length > 0 ? /*#__PURE__*/ jsx(DropdownMenuGroup, {
|
|
58
|
+
className: "flex flex-col gap-1",
|
|
58
59
|
children: displayValues.map((option)=>/*#__PURE__*/ jsx(ValueMenuItem, {
|
|
59
60
|
option: option,
|
|
60
61
|
isChecked: selectedValues.some((v)=>String(v) === String(option.value)),
|
|
@@ -69,6 +70,7 @@ const FlatValueMenu = ({ values, onSelect, onCommit, open = false, onOpenChange,
|
|
|
69
70
|
}, String(option.value)))
|
|
70
71
|
}) : /*#__PURE__*/ jsx(MenuEmptyState, {}),
|
|
71
72
|
/*#__PURE__*/ jsx(DropdownMenuFooter, {
|
|
73
|
+
className: "justify-start",
|
|
72
74
|
children: /*#__PURE__*/ jsx(ValueMenuFooterHints, {
|
|
73
75
|
multiSelect: multiSelect
|
|
74
76
|
})
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Fragment as external_react_Fragment, useMemo, useRef } from "react";
|
|
3
3
|
import { cn } from "../../../../utils/cn.js";
|
|
4
|
-
import { DropdownMenu, DropdownMenuContent, DropdownMenuFooter, DropdownMenuGroup,
|
|
5
|
-
import { Text } from "../../../Text/index.js";
|
|
4
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuFooter, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuSeparator } from "../../../DropdownMenu/index.js";
|
|
6
5
|
import { buildValueMenuSections } from "../../lib/buildValueMenuSections.js";
|
|
7
6
|
import { MenuEmptyState } from "../MenuEmptyState.js";
|
|
8
7
|
import { NestedValueMenuItem } from "./NestedValueMenuItem.js";
|
|
@@ -11,9 +10,10 @@ import { ValueMenuFooterHints } from "./ValueMenuFooterHints.js";
|
|
|
11
10
|
const NestedValueMenu = ({ values, onSelect, onCommit, open = false, onOpenChange, onEscape, multiSelect = false, initialValues = [], width = 'standard', positioning, onBuildingValueChange, onItemToggle, inputRef, filterText = '', menuRef, blurCommitRef, className })=>{
|
|
12
11
|
const submenuRef = useRef(null);
|
|
13
12
|
const rowElsRef = useRef(new Map());
|
|
14
|
-
const sections = useMemo(()=>buildValueMenuSections(values, filterText), [
|
|
13
|
+
const sections = useMemo(()=>buildValueMenuSections(values, filterText, multiSelect), [
|
|
15
14
|
values,
|
|
16
|
-
filterText
|
|
15
|
+
filterText,
|
|
16
|
+
multiSelect
|
|
17
17
|
]);
|
|
18
18
|
const state = useNestedValueMenuState({
|
|
19
19
|
sections,
|
|
@@ -43,13 +43,21 @@ const NestedValueMenu = ({ values, onSelect, onCommit, open = false, onOpenChang
|
|
|
43
43
|
};
|
|
44
44
|
const submenuPositioning = useMemo(()=>({
|
|
45
45
|
placement: 'right-start',
|
|
46
|
-
gutter:
|
|
46
|
+
gutter: 4,
|
|
47
47
|
getAnchorRect: ()=>state.openParentId && rowElsRef.current.get(state.openParentId)?.getBoundingClientRect() || null
|
|
48
48
|
}), [
|
|
49
49
|
state.openParentId
|
|
50
50
|
]);
|
|
51
51
|
const openParentRow = state.openParentRow;
|
|
52
|
-
const
|
|
52
|
+
const submenuSelectAllRow = openParentRow && multiSelect ? {
|
|
53
|
+
id: SELECT_ALL_ID,
|
|
54
|
+
option: {
|
|
55
|
+
label: `All ${openParentRow.option.label}`,
|
|
56
|
+
children: openParentRow.option.children ?? []
|
|
57
|
+
},
|
|
58
|
+
isGroup: true,
|
|
59
|
+
isSelectAll: true
|
|
60
|
+
} : null;
|
|
53
61
|
const hasRows = sections.some((section)=>section.rows.length > 0);
|
|
54
62
|
return /*#__PURE__*/ jsxs(Fragment, {
|
|
55
63
|
children: [
|
|
@@ -65,31 +73,48 @@ const NestedValueMenu = ({ values, onSelect, onCommit, open = false, onOpenChang
|
|
|
65
73
|
className: cn(widthClass, 'max-h-[430px]', className),
|
|
66
74
|
style: widthStyle,
|
|
67
75
|
"data-filter-input-menu": "true",
|
|
76
|
+
onMouseMove: state.handleMainMouseMove,
|
|
68
77
|
children: [
|
|
69
|
-
hasRows ? sections.map((section, index)
|
|
78
|
+
hasRows ? sections.map((section, index)=>{
|
|
79
|
+
const rows = /*#__PURE__*/ jsx(DropdownMenuGroup, {
|
|
80
|
+
className: "flex flex-col gap-1",
|
|
81
|
+
children: section.rows.map((row)=>{
|
|
82
|
+
const isParent = row.isGroup && !row.isSelectAll;
|
|
83
|
+
return /*#__PURE__*/ jsx(NestedValueMenuItem, {
|
|
84
|
+
id: row.id,
|
|
85
|
+
option: row.option,
|
|
86
|
+
isGroup: isParent,
|
|
87
|
+
checkedState: state.getRowCheckState(row),
|
|
88
|
+
isPending: state.topPendingIds.has(row.id),
|
|
89
|
+
multiSelect: multiSelect,
|
|
90
|
+
onSelect: ()=>state.selectRow(row, false),
|
|
91
|
+
onMouseEnter: isParent ? ()=>state.openParent(row.id) : void 0,
|
|
92
|
+
onMouseLeave: isParent ? ()=>state.scheduleClose() : void 0,
|
|
93
|
+
registerRef: setRowRef(row.id),
|
|
94
|
+
expanded: state.openParentId === row.id,
|
|
95
|
+
selectAll: row.isSelectAll,
|
|
96
|
+
highlight: filterText
|
|
97
|
+
}, row.id);
|
|
98
|
+
})
|
|
99
|
+
});
|
|
100
|
+
return /*#__PURE__*/ jsxs(external_react_Fragment, {
|
|
70
101
|
children: [
|
|
71
102
|
index > 0 && /*#__PURE__*/ jsx(DropdownMenuSeparator, {}),
|
|
72
|
-
section.label
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
multiSelect: multiSelect,
|
|
83
|
-
onSelect: ()=>state.selectRow(row, false),
|
|
84
|
-
onMouseEnter: row.isGroup ? ()=>state.openParent(row.id) : void 0,
|
|
85
|
-
onMouseLeave: row.isGroup ? ()=>state.scheduleClose() : void 0,
|
|
86
|
-
registerRef: setRowRef(row.id),
|
|
87
|
-
expanded: state.openParentId === row.id
|
|
88
|
-
}, row.id))
|
|
89
|
-
})
|
|
103
|
+
section.label ? /*#__PURE__*/ jsxs("div", {
|
|
104
|
+
className: "flex flex-col gap-1",
|
|
105
|
+
children: [
|
|
106
|
+
/*#__PURE__*/ jsx(DropdownMenuLabel, {
|
|
107
|
+
sticky: true,
|
|
108
|
+
children: section.label
|
|
109
|
+
}),
|
|
110
|
+
rows
|
|
111
|
+
]
|
|
112
|
+
}) : rows
|
|
90
113
|
]
|
|
91
|
-
}, section.label ?? `section-${index}`)
|
|
114
|
+
}, section.label ?? `section-${index}`);
|
|
115
|
+
}) : /*#__PURE__*/ jsx(MenuEmptyState, {}),
|
|
92
116
|
/*#__PURE__*/ jsx(DropdownMenuFooter, {
|
|
117
|
+
className: "justify-start",
|
|
93
118
|
children: /*#__PURE__*/ jsx(ValueMenuFooterHints, {
|
|
94
119
|
multiSelect: multiSelect
|
|
95
120
|
})
|
|
@@ -111,19 +136,20 @@ const NestedValueMenu = ({ values, onSelect, onCommit, open = false, onOpenChang
|
|
|
111
136
|
onMouseEnter: state.cancelClose,
|
|
112
137
|
onMouseLeave: state.scheduleClose,
|
|
113
138
|
children: /*#__PURE__*/ jsxs(DropdownMenuGroup, {
|
|
139
|
+
className: "flex flex-col gap-1",
|
|
114
140
|
children: [
|
|
115
|
-
/*#__PURE__*/ jsx(
|
|
116
|
-
|
|
117
|
-
|
|
141
|
+
submenuSelectAllRow && /*#__PURE__*/ jsx(NestedValueMenuItem, {
|
|
142
|
+
id: SELECT_ALL_ID,
|
|
143
|
+
option: submenuSelectAllRow.option,
|
|
144
|
+
isGroup: false,
|
|
145
|
+
checkedState: state.getRowCheckState(submenuSelectAllRow),
|
|
146
|
+
isPending: state.submenuPendingIds.has(SELECT_ALL_ID),
|
|
147
|
+
multiSelect: multiSelect,
|
|
118
148
|
onSelect: ()=>state.toggleGroup(openParentRow.option),
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
size: "sm",
|
|
122
|
-
color: "secondary",
|
|
123
|
-
children: allChecked ? 'Unselect all' : 'Select all'
|
|
124
|
-
})
|
|
149
|
+
registerRef: state.registerSubmenuItem(SELECT_ALL_ID),
|
|
150
|
+
selectAll: true
|
|
125
151
|
}),
|
|
126
|
-
/*#__PURE__*/ jsx(DropdownMenuSeparator, {}),
|
|
152
|
+
submenuSelectAllRow && /*#__PURE__*/ jsx(DropdownMenuSeparator, {}),
|
|
127
153
|
state.submenuRows.map((row)=>/*#__PURE__*/ jsx(NestedValueMenuItem, {
|
|
128
154
|
id: row.id,
|
|
129
155
|
option: row.option,
|
package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/NestedValueMenuItem.d.ts
CHANGED
|
@@ -15,12 +15,20 @@ interface NestedValueMenuItemProps {
|
|
|
15
15
|
registerRef?: (el: HTMLElement | null) => void;
|
|
16
16
|
/** For group rows: whether its submenu is currently open. */
|
|
17
17
|
expanded?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* True for the synthetic "All {group}" bulk-select row: its label renders in a
|
|
20
|
+
* medium weight to read as a section-level control rather than a plain option.
|
|
21
|
+
*/
|
|
22
|
+
selectAll?: boolean;
|
|
23
|
+
/** Active search query — its matched substring is emphasized in flat search. */
|
|
24
|
+
highlight?: string;
|
|
18
25
|
}
|
|
19
26
|
/**
|
|
20
|
-
* A single row in the nested value menu — a committable leaf
|
|
21
|
-
*
|
|
22
|
-
* submenu
|
|
23
|
-
*
|
|
27
|
+
* A single row in the nested value menu — a committable leaf, a group (parent
|
|
28
|
+
* category), or the "All {group}" bulk-select row. Parent categories show a
|
|
29
|
+
* right-side chevron and open a submenu on hover; a checked row is highlighted
|
|
30
|
+
* with a persistent background. Selection is driven by the (tri-state, for
|
|
31
|
+
* groups) checkbox.
|
|
24
32
|
*/
|
|
25
33
|
export declare const NestedValueMenuItem: FC<NestedValueMenuItemProps>;
|
|
26
34
|
export {};
|
package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/NestedValueMenuItem.js
CHANGED
|
@@ -1,15 +1,48 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ChevronRight } from "../../../../icons/ChevronRight.js";
|
|
3
|
+
import { cn } from "../../../../utils/cn.js";
|
|
2
4
|
import { Badge } from "../../../Badge/index.js";
|
|
3
5
|
import { Checkmark } from "../../../Checkmark/index.js";
|
|
4
6
|
import { DropdownMenuItem } from "../../../DropdownMenu/index.js";
|
|
5
7
|
import { Text } from "../../../Text/index.js";
|
|
6
|
-
const
|
|
8
|
+
const highlightMatch = (text, query)=>{
|
|
9
|
+
const q = query?.trim().toLowerCase();
|
|
10
|
+
if (!q) return text;
|
|
11
|
+
const lower = text.toLowerCase();
|
|
12
|
+
const parts = [];
|
|
13
|
+
let cursor = 0;
|
|
14
|
+
let key = 0;
|
|
15
|
+
while(cursor < text.length){
|
|
16
|
+
const at = lower.indexOf(q, cursor);
|
|
17
|
+
if (-1 === at) {
|
|
18
|
+
parts.push(/*#__PURE__*/ jsx("span", {
|
|
19
|
+
children: text.slice(cursor)
|
|
20
|
+
}, key++));
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
if (at > cursor) parts.push(/*#__PURE__*/ jsx("span", {
|
|
24
|
+
children: text.slice(cursor, at)
|
|
25
|
+
}, key++));
|
|
26
|
+
parts.push(/*#__PURE__*/ jsx("mark", {
|
|
27
|
+
className: "bg-transparent font-medium text-text-brand",
|
|
28
|
+
children: text.slice(at, at + q.length)
|
|
29
|
+
}, key++));
|
|
30
|
+
cursor = at + q.length;
|
|
31
|
+
}
|
|
32
|
+
return parts;
|
|
33
|
+
};
|
|
34
|
+
const NestedValueMenuItem = ({ id, option, isGroup, checkedState, isPending, multiSelect, onSelect, onMouseEnter, onMouseLeave, registerRef, expanded, selectAll, highlight })=>{
|
|
35
|
+
const isChecked = true === checkedState;
|
|
36
|
+
const checkmark = multiSelect || !isGroup && checkedState ? /*#__PURE__*/ jsx(Checkmark, {
|
|
37
|
+
checkedState: multiSelect ? checkedState : true
|
|
38
|
+
}) : null;
|
|
39
|
+
return /*#__PURE__*/ jsxs(DropdownMenuItem, {
|
|
7
40
|
value: id,
|
|
8
41
|
ref: registerRef,
|
|
9
42
|
onSelect: onSelect,
|
|
10
43
|
onMouseEnter: onMouseEnter,
|
|
11
44
|
onMouseLeave: onMouseLeave,
|
|
12
|
-
className:
|
|
45
|
+
className: cn('scroll-mt-32', isChecked && 'bg-states-primary-active', isPending && 'bg-states-primary-hover'),
|
|
13
46
|
"aria-checked": multiSelect ? 'indeterminate' === checkedState ? 'mixed' : !!checkedState : void 0,
|
|
14
47
|
...isGroup && {
|
|
15
48
|
'aria-haspopup': 'menu',
|
|
@@ -26,29 +59,30 @@ const NestedValueMenuItem = ({ id, option, isGroup, checkedState, isPending, mul
|
|
|
26
59
|
children: [
|
|
27
60
|
/*#__PURE__*/ jsx(Text, {
|
|
28
61
|
size: "sm",
|
|
62
|
+
weight: selectAll ? 'medium' : 'regular',
|
|
29
63
|
truncate: true,
|
|
30
|
-
children: option.label
|
|
64
|
+
children: highlightMatch(option.label, highlight)
|
|
31
65
|
}),
|
|
32
66
|
option.description && /*#__PURE__*/ jsx(Text, {
|
|
33
67
|
size: "xs",
|
|
34
68
|
color: "secondary",
|
|
35
69
|
truncate: true,
|
|
36
|
-
children: option.description
|
|
70
|
+
children: highlightMatch(option.description, highlight)
|
|
37
71
|
})
|
|
38
72
|
]
|
|
39
73
|
}),
|
|
40
|
-
|
|
41
|
-
className: "flex shrink-0 items-
|
|
42
|
-
children:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}) : null
|
|
74
|
+
/*#__PURE__*/ jsxs("div", {
|
|
75
|
+
className: "flex shrink-0 items-center justify-end gap-8 ml-auto",
|
|
76
|
+
children: [
|
|
77
|
+
isGroup && /*#__PURE__*/ jsx("span", {
|
|
78
|
+
className: "flex text-text-secondary",
|
|
79
|
+
children: /*#__PURE__*/ jsx(ChevronRight, {})
|
|
80
|
+
}),
|
|
81
|
+
checkmark
|
|
82
|
+
]
|
|
83
|
+
})
|
|
51
84
|
]
|
|
52
85
|
});
|
|
86
|
+
};
|
|
53
87
|
NestedValueMenuItem.displayName = 'NestedValueMenuItem';
|
|
54
88
|
export { NestedValueMenuItem };
|
|
@@ -32,12 +32,12 @@ const ValueMenuItem = ({ option, isChecked, isPending, multiSelect, onSelect, re
|
|
|
32
32
|
]
|
|
33
33
|
}),
|
|
34
34
|
multiSelect ? /*#__PURE__*/ jsx("div", {
|
|
35
|
-
className: "flex shrink-0 items-start justify-end
|
|
35
|
+
className: "flex shrink-0 items-start justify-end ml-auto",
|
|
36
36
|
children: /*#__PURE__*/ jsx(Checkmark, {
|
|
37
37
|
checkedState: isChecked
|
|
38
38
|
})
|
|
39
39
|
}) : isChecked ? /*#__PURE__*/ jsx("div", {
|
|
40
|
-
className: "flex shrink-0 items-start justify-end
|
|
40
|
+
className: "flex shrink-0 items-start justify-end ml-auto",
|
|
41
41
|
children: /*#__PURE__*/ jsx(Checkmark, {
|
|
42
42
|
checkedState: true
|
|
43
43
|
})
|
|
@@ -41,6 +41,10 @@ export declare const useNestedValueMenuState: ({ sections, allValues, open, mult
|
|
|
41
41
|
closeParent: () => void;
|
|
42
42
|
cancelClose: () => void;
|
|
43
43
|
scheduleClose: () => void;
|
|
44
|
+
handleMainMouseMove: (event: {
|
|
45
|
+
clientX: number;
|
|
46
|
+
clientY: number;
|
|
47
|
+
}) => void;
|
|
44
48
|
openParentRow: ValueMenuRow | undefined;
|
|
45
49
|
submenuRows: ValueMenuRow[];
|
|
46
50
|
selectRow: (row: ValueMenuRow, fromSubmenu: boolean) => void;
|
package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/useNestedValueMenuState.js
CHANGED
|
@@ -32,7 +32,7 @@ const useNestedValueMenuState = ({ sections, allValues, open, multiSelect, initi
|
|
|
32
32
|
]);
|
|
33
33
|
const topRowsRef = useRef(topRows);
|
|
34
34
|
topRowsRef.current = topRows;
|
|
35
|
-
const openParentRow = useMemo(()=>topRows.find((row)=>row.id === openParentId && row.isGroup), [
|
|
35
|
+
const openParentRow = useMemo(()=>topRows.find((row)=>row.id === openParentId && row.isGroup && !row.isSelectAll), [
|
|
36
36
|
topRows,
|
|
37
37
|
openParentId
|
|
38
38
|
]);
|
|
@@ -123,7 +123,7 @@ const useNestedValueMenuState = ({ sections, allValues, open, multiSelect, initi
|
|
|
123
123
|
closeTimerRef.current = setTimeout(()=>{
|
|
124
124
|
closeTimerRef.current = null;
|
|
125
125
|
setOpenParentId(null);
|
|
126
|
-
},
|
|
126
|
+
}, 250);
|
|
127
127
|
}, [
|
|
128
128
|
cancelClose
|
|
129
129
|
]);
|
|
@@ -142,6 +142,25 @@ const useNestedValueMenuState = ({ sections, allValues, open, multiSelect, initi
|
|
|
142
142
|
useEffect(()=>()=>cancelClose(), [
|
|
143
143
|
cancelClose
|
|
144
144
|
]);
|
|
145
|
+
const lastPointRef = useRef(null);
|
|
146
|
+
const handleMainMouseMove = useCallback((event)=>{
|
|
147
|
+
const prev = lastPointRef.current;
|
|
148
|
+
const point = {
|
|
149
|
+
x: event.clientX,
|
|
150
|
+
y: event.clientY
|
|
151
|
+
};
|
|
152
|
+
lastPointRef.current = point;
|
|
153
|
+
if (null == openParentId || !prev) return;
|
|
154
|
+
const sub = submenuRef?.current?.getBoundingClientRect();
|
|
155
|
+
if (!sub) return;
|
|
156
|
+
const headingRight = point.x >= prev.x;
|
|
157
|
+
const insideBand = point.y >= sub.top - 12 && point.y <= sub.bottom + 12;
|
|
158
|
+
if (headingRight && insideBand && point.x <= sub.left) cancelClose();
|
|
159
|
+
}, [
|
|
160
|
+
openParentId,
|
|
161
|
+
submenuRef,
|
|
162
|
+
cancelClose
|
|
163
|
+
]);
|
|
145
164
|
const toggleGroup = useCallback((option)=>{
|
|
146
165
|
const leaves = collectLeaves(option.children).map((l)=>l.value);
|
|
147
166
|
toggleMany(leaves, !allLeavesChecked(option));
|
|
@@ -153,7 +172,7 @@ const useNestedValueMenuState = ({ sections, allValues, open, multiSelect, initi
|
|
|
153
172
|
]);
|
|
154
173
|
const selectRow = useCallback((row, fromSubmenu)=>{
|
|
155
174
|
if (row.isGroup) {
|
|
156
|
-
if (multiSelect) toggleGroup(row.option);
|
|
175
|
+
if (multiSelect || row.isSelectAll) toggleGroup(row.option);
|
|
157
176
|
else if (!fromSubmenu) openParent(row.id);
|
|
158
177
|
return;
|
|
159
178
|
}
|
|
@@ -194,7 +213,7 @@ const useNestedValueMenuState = ({ sections, allValues, open, multiSelect, initi
|
|
|
194
213
|
]);
|
|
195
214
|
const handleTopArrowRight = useCallback(()=>{
|
|
196
215
|
const row = topRowsRef.current.find((r)=>r.id === topHighlightRef.current);
|
|
197
|
-
if (row?.isGroup) openParent(row.id);
|
|
216
|
+
if (row?.isGroup && !row.isSelectAll) openParent(row.id);
|
|
198
217
|
else if (multiSelect) commitChecked();
|
|
199
218
|
}, [
|
|
200
219
|
openParent,
|
|
@@ -214,21 +233,23 @@ const useNestedValueMenuState = ({ sections, allValues, open, multiSelect, initi
|
|
|
214
233
|
topHighlightRef.current = top.highlightedValue;
|
|
215
234
|
const submenuNavItems = useMemo(()=>{
|
|
216
235
|
if (!openParentRow) return [];
|
|
217
|
-
|
|
236
|
+
const leafItems = submenuRows.map((row)=>({
|
|
237
|
+
id: row.id,
|
|
238
|
+
label: row.option.label,
|
|
239
|
+
value: row.option.value
|
|
240
|
+
}));
|
|
241
|
+
return multiSelect ? [
|
|
218
242
|
{
|
|
219
243
|
id: SELECT_ALL_ID,
|
|
220
244
|
label: 'Select all',
|
|
221
245
|
value: SELECT_ALL_ID
|
|
222
246
|
},
|
|
223
|
-
...
|
|
224
|
-
|
|
225
|
-
label: row.option.label,
|
|
226
|
-
value: row.option.value
|
|
227
|
-
}))
|
|
228
|
-
];
|
|
247
|
+
...leafItems
|
|
248
|
+
] : leafItems;
|
|
229
249
|
}, [
|
|
230
250
|
openParentRow,
|
|
231
|
-
submenuRows
|
|
251
|
+
submenuRows,
|
|
252
|
+
multiSelect
|
|
232
253
|
]);
|
|
233
254
|
const handleSubmenuSelect = useCallback((item)=>{
|
|
234
255
|
if (!openParentRow) return;
|
|
@@ -272,6 +293,7 @@ const useNestedValueMenuState = ({ sections, allValues, open, multiSelect, initi
|
|
|
272
293
|
closeParent,
|
|
273
294
|
cancelClose,
|
|
274
295
|
scheduleClose,
|
|
296
|
+
handleMainMouseMove,
|
|
275
297
|
openParentRow,
|
|
276
298
|
submenuRows,
|
|
277
299
|
selectRow,
|
|
@@ -9,12 +9,21 @@ export interface ValueMenuRow {
|
|
|
9
9
|
id: string;
|
|
10
10
|
option: FieldValueOption;
|
|
11
11
|
isGroup: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* True for the synthetic **"All {group}"** bulk-select row rendered at the top
|
|
14
|
+
* of a labeled section. It is a group row for check-state/toggle purposes (its
|
|
15
|
+
* `option.children` are the section's full scope) but is NOT a submenu trigger:
|
|
16
|
+
* it never opens a right-side panel, it only toggles its descendant leaves.
|
|
17
|
+
*/
|
|
18
|
+
isSelectAll?: boolean;
|
|
12
19
|
}
|
|
13
20
|
/** A render-ready value-menu section. `label` undefined = headerless. */
|
|
14
21
|
export interface ValueMenuSection {
|
|
15
22
|
label?: string;
|
|
16
23
|
rows: ValueMenuRow[];
|
|
17
24
|
}
|
|
25
|
+
/** Joins ancestry labels for a flat-search row's muted second line. */
|
|
26
|
+
export declare const PATH_SEPARATOR = " \u203A ";
|
|
18
27
|
/**
|
|
19
28
|
* Bucket value options into ordered, filtered menu sections.
|
|
20
29
|
*
|
|
@@ -27,7 +36,14 @@ export interface ValueMenuSection {
|
|
|
27
36
|
* 3. **Flat** — no grouping: a single headerless section (today's behavior, so
|
|
28
37
|
* existing fields are visually unchanged).
|
|
29
38
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
39
|
+
* A non-empty `filterText` **flattens** a grouped tree into a single flat list
|
|
40
|
+
* of matches at any depth (see {@link buildFlatSearchSections}) — hover submenus
|
|
41
|
+
* are unreachable while typing, so deep values are surfaced directly with their
|
|
42
|
+
* ancestry path. With an empty query the grouped structure below is returned.
|
|
43
|
+
*
|
|
44
|
+
* When `multiSelect` is set, every **labeled** section is prefixed with a
|
|
45
|
+
* synthetic "All {label}" bulk-select row (see {@link selectAllRow}) so the user
|
|
46
|
+
* can select/deselect the whole group's scope in one click; single-select menus
|
|
47
|
+
* omit it (bulk selection is meaningless there).
|
|
32
48
|
*/
|
|
33
|
-
export declare function buildValueMenuSections(values: FieldValueOption[], filterText: string): ValueMenuSection[];
|
|
49
|
+
export declare function buildValueMenuSections(values: FieldValueOption[], filterText: string, multiSelect?: boolean): ValueMenuSection[];
|
|
@@ -15,7 +15,70 @@ const toRows = (options, filterText)=>filterAndSort(options, filterText, rowSear
|
|
|
15
15
|
option,
|
|
16
16
|
isGroup: isValueGroup(option)
|
|
17
17
|
}));
|
|
18
|
-
|
|
18
|
+
const selectAllRow = (label, scope)=>({
|
|
19
|
+
id: `select-all:${label}`,
|
|
20
|
+
option: {
|
|
21
|
+
label: `All ${label}`,
|
|
22
|
+
children: scope
|
|
23
|
+
},
|
|
24
|
+
isGroup: true,
|
|
25
|
+
isSelectAll: true
|
|
26
|
+
});
|
|
27
|
+
const PATH_SEPARATOR = ' › ';
|
|
28
|
+
const matchesQuery = (value, query)=>null != value && String(value).toLowerCase().includes(query);
|
|
29
|
+
function buildFlatSearchSections(values, query, multiSelect) {
|
|
30
|
+
const shortcuts = [];
|
|
31
|
+
const leaves = [];
|
|
32
|
+
const walk = (options, path)=>{
|
|
33
|
+
for (const option of options)if (isValueGroup(option)) {
|
|
34
|
+
if (multiSelect && matchesQuery(option.label, query)) shortcuts.push({
|
|
35
|
+
id: `select-all:${[
|
|
36
|
+
...path,
|
|
37
|
+
option.label
|
|
38
|
+
].join('/')}`,
|
|
39
|
+
option: {
|
|
40
|
+
...option,
|
|
41
|
+
label: `All ${option.label}`,
|
|
42
|
+
description: path.join(PATH_SEPARATOR) || void 0
|
|
43
|
+
},
|
|
44
|
+
isGroup: true,
|
|
45
|
+
isSelectAll: true
|
|
46
|
+
});
|
|
47
|
+
walk(option.children ?? [], [
|
|
48
|
+
...path,
|
|
49
|
+
option.label
|
|
50
|
+
]);
|
|
51
|
+
} else if (matchesQuery(option.label, query) || matchesQuery(option.value, query) || matchesQuery(option.description, query)) {
|
|
52
|
+
const ancestry = path.length > 0 ? path.join(PATH_SEPARATOR) : option.section;
|
|
53
|
+
leaves.push({
|
|
54
|
+
id: `leaf:${String(option.value)}`,
|
|
55
|
+
option: {
|
|
56
|
+
...option,
|
|
57
|
+
description: ancestry || void 0
|
|
58
|
+
},
|
|
59
|
+
isGroup: false
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
walk(values, []);
|
|
64
|
+
const rows = [
|
|
65
|
+
...shortcuts,
|
|
66
|
+
...leaves
|
|
67
|
+
];
|
|
68
|
+
return rows.length > 0 ? [
|
|
69
|
+
{
|
|
70
|
+
rows
|
|
71
|
+
}
|
|
72
|
+
] : [];
|
|
73
|
+
}
|
|
74
|
+
function buildValueMenuSections(values, filterText, multiSelect = false) {
|
|
75
|
+
const query = filterText.trim().toLowerCase();
|
|
76
|
+
const hasHierarchy = values.some((v)=>isValueGroup(v) || null != v.section);
|
|
77
|
+
if (query.length > 0 && hasHierarchy) return buildFlatSearchSections(values, query, multiSelect);
|
|
78
|
+
const withSelectAll = (label, scope, rows)=>multiSelect ? [
|
|
79
|
+
selectAllRow(label, scope),
|
|
80
|
+
...rows
|
|
81
|
+
] : rows;
|
|
19
82
|
const topGroups = values.filter(isValueGroup);
|
|
20
83
|
if (topGroups.length > 0) {
|
|
21
84
|
const sections = [];
|
|
@@ -25,10 +88,11 @@ function buildValueMenuSections(values, filterText) {
|
|
|
25
88
|
rows: leafRows
|
|
26
89
|
});
|
|
27
90
|
for (const group of topGroups){
|
|
28
|
-
const
|
|
91
|
+
const children = group.children ?? [];
|
|
92
|
+
const rows = toRows(children, filterText);
|
|
29
93
|
if (rows.length > 0) sections.push({
|
|
30
94
|
label: group.label,
|
|
31
|
-
rows
|
|
95
|
+
rows: withSelectAll(group.label, children, rows)
|
|
32
96
|
});
|
|
33
97
|
}
|
|
34
98
|
return sections;
|
|
@@ -50,10 +114,11 @@ function buildValueMenuSections(values, filterText) {
|
|
|
50
114
|
rows: unsectionedRows
|
|
51
115
|
});
|
|
52
116
|
for (const label of order){
|
|
53
|
-
const
|
|
117
|
+
const bucket = buckets.get(label);
|
|
118
|
+
const rows = toRows(bucket, filterText);
|
|
54
119
|
if (rows.length > 0) sections.push({
|
|
55
120
|
label,
|
|
56
|
-
rows
|
|
121
|
+
rows: withSelectAll(label, bucket, rows)
|
|
57
122
|
});
|
|
58
123
|
}
|
|
59
124
|
return sections;
|
|
@@ -65,4 +130,4 @@ function buildValueMenuSections(values, filterText) {
|
|
|
65
130
|
}
|
|
66
131
|
] : [];
|
|
67
132
|
}
|
|
68
|
-
export { buildValueMenuSections };
|
|
133
|
+
export { PATH_SEPARATOR, buildValueMenuSections };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
3
|
-
"generatedAt": "2026-08-
|
|
2
|
+
"version": "0.82.0",
|
|
3
|
+
"generatedAt": "2026-08-05T07:53:56.679Z",
|
|
4
4
|
"components": [
|
|
5
5
|
{
|
|
6
6
|
"name": "Accordion",
|
|
@@ -25561,6 +25561,12 @@
|
|
|
25561
25561
|
"options": [
|
|
25562
25562
|
"true"
|
|
25563
25563
|
]
|
|
25564
|
+
},
|
|
25565
|
+
{
|
|
25566
|
+
"name": "sticky",
|
|
25567
|
+
"options": [
|
|
25568
|
+
"true"
|
|
25569
|
+
]
|
|
25564
25570
|
}
|
|
25565
25571
|
],
|
|
25566
25572
|
"subComponents": [
|