@wallarm-org/design-system 0.76.2 → 0.77.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/FilterInput/FilterInput.d.ts +9 -1
- package/dist/components/FilterInput/FilterInput.js +2 -1
- package/dist/components/FilterInput/FilterInputMenu/FilterInputFieldMenu/FieldMenuSections.d.ts +8 -1
- package/dist/components/FilterInput/FilterInputMenu/FilterInputFieldMenu/FieldMenuSections.js +23 -1
- package/dist/components/FilterInput/FilterInputMenu/FilterInputFieldMenu/FilterInputFieldMenu.d.ts +4 -3
- package/dist/components/FilterInput/FilterInputMenu/FilterInputFieldMenu/FilterInputFieldMenu.js +18 -72
- package/dist/components/FilterInput/FilterInputMenu/FilterInputMenu.d.ts +2 -1
- package/dist/components/FilterInput/FilterInputMenu/FilterInputMenu.js +2 -1
- package/dist/components/FilterInput/FilterInputMenu/hooks/useFieldMenuNavItems.d.ts +19 -0
- package/dist/components/FilterInput/FilterInputMenu/hooks/useFieldMenuNavItems.js +63 -0
- package/dist/components/FilterInput/lib/buildFieldMenuSections.d.ts +14 -0
- package/dist/components/FilterInput/lib/buildFieldMenuSections.js +44 -0
- package/dist/components/FilterInput/lib/index.d.ts +1 -0
- package/dist/components/FilterInput/lib/index.js +1 -0
- package/dist/components/FilterInput/types.d.ts +13 -0
- package/dist/metadata/components.json +14 -2
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FC, HTMLAttributes } from 'react';
|
|
2
|
-
import type { ExprNode, FieldMetadata } from './types';
|
|
2
|
+
import type { ExprNode, FieldGroup, FieldMetadata } from './types';
|
|
3
3
|
export interface FilterInputProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'onChange'> {
|
|
4
4
|
/**
|
|
5
5
|
* Filter-field configurations driving the autocomplete. A few names are
|
|
@@ -15,6 +15,14 @@ export interface FilterInputProps extends Omit<HTMLAttributes<HTMLDivElement>, '
|
|
|
15
15
|
* (`createStatusCodeSuggestions`, …) manually.
|
|
16
16
|
*/
|
|
17
17
|
fields?: FieldMetadata[];
|
|
18
|
+
/**
|
|
19
|
+
* Optional grouping for the field-selection menu. When omitted, fields
|
|
20
|
+
* render as a flat list. When provided, fields render under labeled group
|
|
21
|
+
* headers (group order = array order; field order = listed order). Fields
|
|
22
|
+
* not referenced by any group fall into a trailing headerless section.
|
|
23
|
+
* Referenced by field `name`; unknown names are ignored.
|
|
24
|
+
*/
|
|
25
|
+
fieldGroups?: FieldGroup[];
|
|
18
26
|
value?: ExprNode | null;
|
|
19
27
|
onChange?: (expression: ExprNode | null) => void;
|
|
20
28
|
placeholder?: string;
|
|
@@ -7,7 +7,7 @@ import { FilterInputField } from "./FilterInputField/index.js";
|
|
|
7
7
|
import { FilterInputMenu } from "./FilterInputMenu/FilterInputMenu.js";
|
|
8
8
|
import { useFilterInputAutocomplete, useFilterInputExpression, useFilterInputSelection } from "./hooks/index.js";
|
|
9
9
|
import { applyKnownFieldHelpers } from "./lib/applyKnownFieldHelpers.js";
|
|
10
|
-
const FilterInput = ({ fields: rawFields = [], value, onChange, placeholder = 'Type to filter...', error = false, externalErrors, onErrorsChange, showKeyboardHint = false, className, ...props })=>{
|
|
10
|
+
const FilterInput = ({ fields: rawFields = [], fieldGroups, value, onChange, placeholder = 'Type to filter...', error = false, externalErrors, onErrorsChange, showKeyboardHint = false, className, ...props })=>{
|
|
11
11
|
const inputRef = useRef(null);
|
|
12
12
|
const containerRef = useRef(null);
|
|
13
13
|
const buildingChipRef = useRef(null);
|
|
@@ -112,6 +112,7 @@ const FilterInput = ({ fields: rawFields = [], value, onChange, placeholder = 'T
|
|
|
112
112
|
}),
|
|
113
113
|
/*#__PURE__*/ jsx(FilterInputMenu, {
|
|
114
114
|
fields: fields,
|
|
115
|
+
fieldGroups: fieldGroups,
|
|
115
116
|
autocomplete: autocomplete
|
|
116
117
|
}),
|
|
117
118
|
/*#__PURE__*/ jsx(FilterInputErrors, {
|
package/dist/components/FilterInput/FilterInputMenu/FilterInputFieldMenu/FieldMenuSections.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type FC } from 'react';
|
|
2
|
+
import type { FieldMenuSection } from '../../lib';
|
|
2
3
|
import type { Condition, FieldMetadata } from '../../types';
|
|
3
4
|
interface RecentSectionProps {
|
|
4
5
|
conditions: Condition[];
|
|
@@ -19,4 +20,10 @@ interface OperatorsSectionProps {
|
|
|
19
20
|
registerItem: (id: string) => (el: HTMLElement | null) => void;
|
|
20
21
|
}
|
|
21
22
|
export declare const OperatorsSection: FC<OperatorsSectionProps>;
|
|
23
|
+
interface FieldSectionsProps {
|
|
24
|
+
sections: FieldMenuSection[];
|
|
25
|
+
onSelect: (field: FieldMetadata) => void;
|
|
26
|
+
registerItem: (id: string) => (el: HTMLElement | null) => void;
|
|
27
|
+
}
|
|
28
|
+
export declare const FieldSections: FC<FieldSectionsProps>;
|
|
22
29
|
export {};
|
package/dist/components/FilterInput/FilterInputMenu/FilterInputFieldMenu/FieldMenuSections.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment as external_react_Fragment } from "react";
|
|
2
3
|
import { CirclePlus } from "../../../../icons/CirclePlus.js";
|
|
3
4
|
import { CircleSlash } from "../../../../icons/CircleSlash.js";
|
|
4
5
|
import { DropdownMenuGroup, DropdownMenuItem, DropdownMenuItemIcon, DropdownMenuItemText, DropdownMenuLabel, DropdownMenuSeparator } from "../../../DropdownMenu/index.js";
|
|
@@ -108,4 +109,25 @@ const OperatorsSection = ({ onSelectAnd, onSelectOr, registerItem })=>/*#__PURE_
|
|
|
108
109
|
]
|
|
109
110
|
});
|
|
110
111
|
OperatorsSection.displayName = 'OperatorsSection';
|
|
111
|
-
|
|
112
|
+
const FieldSections = ({ sections, onSelect, registerItem })=>/*#__PURE__*/ jsx(Fragment, {
|
|
113
|
+
children: sections.map((section, index)=>/*#__PURE__*/ jsxs(external_react_Fragment, {
|
|
114
|
+
children: [
|
|
115
|
+
index > 0 && /*#__PURE__*/ jsx(DropdownMenuSeparator, {}),
|
|
116
|
+
section.label && /*#__PURE__*/ jsx(DropdownMenuLabel, {
|
|
117
|
+
children: section.label
|
|
118
|
+
}),
|
|
119
|
+
/*#__PURE__*/ jsx(DropdownMenuGroup, {
|
|
120
|
+
children: section.fields.map((field)=>/*#__PURE__*/ jsx(DropdownMenuItem, {
|
|
121
|
+
value: `field-${field.name}`,
|
|
122
|
+
ref: registerItem(`field-${field.name}`),
|
|
123
|
+
onSelect: ()=>onSelect(field),
|
|
124
|
+
children: /*#__PURE__*/ jsx(DropdownMenuItemText, {
|
|
125
|
+
children: field.label
|
|
126
|
+
})
|
|
127
|
+
}, field.name))
|
|
128
|
+
})
|
|
129
|
+
]
|
|
130
|
+
}, `${section.label ?? 'ungrouped'}-${index}`))
|
|
131
|
+
});
|
|
132
|
+
FieldSections.displayName = 'FieldSections';
|
|
133
|
+
export { FieldSections, OperatorsSection, RecentSection, SuggestionsSection };
|
package/dist/components/FilterInput/FilterInputMenu/FilterInputFieldMenu/FilterInputFieldMenu.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import {
|
|
3
|
-
import type { Condition, FieldMetadata } from '../../types';
|
|
1
|
+
import { type FC, type RefObject } from 'react';
|
|
2
|
+
import type { Condition, FieldGroup, FieldMetadata } from '../../types';
|
|
4
3
|
export interface FilterInputFieldMenuProps {
|
|
5
4
|
fields: FieldMetadata[];
|
|
6
5
|
/** Text from the input to filter displayed fields */
|
|
@@ -10,6 +9,8 @@ export interface FilterInputFieldMenuProps {
|
|
|
10
9
|
onOpenChange?: (open: boolean) => void;
|
|
11
10
|
recentConditions?: Condition[];
|
|
12
11
|
suggestedFields?: FieldMetadata[];
|
|
12
|
+
/** Optional grouping for the field list. When omitted, fields render flat. */
|
|
13
|
+
fieldGroups?: FieldGroup[];
|
|
13
14
|
onSelectAnd?: () => void;
|
|
14
15
|
onSelectOr?: () => void;
|
|
15
16
|
onEscape?: () => void;
|
package/dist/components/FilterInput/FilterInputMenu/FilterInputFieldMenu/FilterInputFieldMenu.js
CHANGED
|
@@ -1,85 +1,36 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useMemo } from "react";
|
|
3
3
|
import { cn } from "../../../../utils/cn.js";
|
|
4
|
-
import { DropdownMenu, DropdownMenuContent, DropdownMenuFooter
|
|
4
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuFooter } from "../../../DropdownMenu/index.js";
|
|
5
5
|
import { Kbd } from "../../../Kbd/Kbd.js";
|
|
6
6
|
import { KbdGroup } from "../../../Kbd/KbdGroup.js";
|
|
7
|
-
import {
|
|
7
|
+
import { buildFieldMenuSections } from "../../lib/index.js";
|
|
8
|
+
import { useFieldMenuNavItems } from "../hooks/useFieldMenuNavItems.js";
|
|
8
9
|
import { useKeyboardNav } from "../hooks/useKeyboardNav.js";
|
|
9
10
|
import { MenuEmptyState } from "../MenuEmptyState.js";
|
|
10
|
-
import { OperatorsSection, RecentSection, SuggestionsSection } from "./FieldMenuSections.js";
|
|
11
|
-
const FilterInputFieldMenu = ({ fields, filterText = '', onSelect, open = false, onOpenChange, recentConditions = [], suggestedFields = [], onSelectAnd, onSelectOr, onEscape, positioning, inputRef, menuRef, className })=>{
|
|
11
|
+
import { FieldSections, OperatorsSection, RecentSection, SuggestionsSection } from "./FieldMenuSections.js";
|
|
12
|
+
const FilterInputFieldMenu = ({ fields, filterText = '', onSelect, open = false, onOpenChange, recentConditions = [], suggestedFields = [], fieldGroups, onSelectAnd, onSelectOr, onEscape, positioning, inputRef, menuRef, className })=>{
|
|
12
13
|
const limitedRecentConditions = useMemo(()=>recentConditions.slice(0, 3), [
|
|
13
14
|
recentConditions
|
|
14
15
|
]);
|
|
15
16
|
const showRecent = limitedRecentConditions.length > 0;
|
|
16
17
|
const showSuggestions = suggestedFields.length > 0;
|
|
17
|
-
const
|
|
18
|
-
f.label,
|
|
19
|
-
f.name
|
|
20
|
-
]), [
|
|
18
|
+
const sections = useMemo(()=>buildFieldMenuSections(fields, fieldGroups, filterText), [
|
|
21
19
|
fields,
|
|
20
|
+
fieldGroups,
|
|
22
21
|
filterText
|
|
23
22
|
]);
|
|
24
|
-
const flatItems =
|
|
25
|
-
|
|
26
|
-
if (!filterText && showRecent) limitedRecentConditions.forEach((condition, index)=>{
|
|
27
|
-
const fieldMeta = fields.find((f)=>f.name === condition.field);
|
|
28
|
-
items.push({
|
|
29
|
-
id: `recent-${index}`,
|
|
30
|
-
label: fieldMeta?.label || condition.field,
|
|
31
|
-
value: {
|
|
32
|
-
type: 'recent',
|
|
33
|
-
field: fieldMeta
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
if (!filterText && showSuggestions && !showRecent) suggestedFields.forEach((field, index)=>{
|
|
38
|
-
items.push({
|
|
39
|
-
id: `suggested-${index}`,
|
|
40
|
-
label: field.label,
|
|
41
|
-
value: {
|
|
42
|
-
type: 'field',
|
|
43
|
-
field
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
filteredFields.forEach((field)=>{
|
|
48
|
-
items.push({
|
|
49
|
-
id: `field-${field.name}`,
|
|
50
|
-
label: field.label,
|
|
51
|
-
value: {
|
|
52
|
-
type: 'field',
|
|
53
|
-
field
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
if (!filterText && onSelectAnd) items.push({
|
|
58
|
-
id: 'and',
|
|
59
|
-
label: 'AND',
|
|
60
|
-
value: {
|
|
61
|
-
type: 'and'
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
if (!filterText && onSelectOr) items.push({
|
|
65
|
-
id: 'or',
|
|
66
|
-
label: 'OR',
|
|
67
|
-
value: {
|
|
68
|
-
type: 'or'
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
return items;
|
|
72
|
-
}, [
|
|
73
|
-
filteredFields,
|
|
23
|
+
const flatItems = useFieldMenuNavItems({
|
|
24
|
+
sections,
|
|
74
25
|
fields,
|
|
26
|
+
filterText,
|
|
75
27
|
limitedRecentConditions,
|
|
76
|
-
suggestedFields,
|
|
77
28
|
showRecent,
|
|
29
|
+
suggestedFields,
|
|
78
30
|
showSuggestions,
|
|
79
31
|
onSelectAnd,
|
|
80
|
-
onSelectOr
|
|
81
|
-
|
|
82
|
-
]);
|
|
32
|
+
onSelectOr
|
|
33
|
+
});
|
|
83
34
|
const handleItemSelect = (item)=>{
|
|
84
35
|
const data = item.value;
|
|
85
36
|
if ('recent' === data.type || 'field' === data.type) {
|
|
@@ -97,7 +48,7 @@ const FilterInputFieldMenu = ({ fields, filterText = '', onSelect, open = false,
|
|
|
97
48
|
inputRef,
|
|
98
49
|
menuRef
|
|
99
50
|
});
|
|
100
|
-
const hasResults =
|
|
51
|
+
const hasResults = sections.length > 0 || !filterText;
|
|
101
52
|
return /*#__PURE__*/ jsx(DropdownMenu, {
|
|
102
53
|
open: open && hasResults,
|
|
103
54
|
onOpenChange: onOpenChange,
|
|
@@ -122,15 +73,10 @@ const FilterInputFieldMenu = ({ fields, filterText = '', onSelect, open = false,
|
|
|
122
73
|
onSelect: onSelect,
|
|
123
74
|
registerItem: registerItem
|
|
124
75
|
}),
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
onSelect: ()=>onSelect(field),
|
|
130
|
-
children: /*#__PURE__*/ jsx(DropdownMenuItemText, {
|
|
131
|
-
children: field.label
|
|
132
|
-
})
|
|
133
|
-
}, field.name))
|
|
76
|
+
sections.length > 0 ? /*#__PURE__*/ jsx(FieldSections, {
|
|
77
|
+
sections: sections,
|
|
78
|
+
onSelect: onSelect,
|
|
79
|
+
registerItem: registerItem
|
|
134
80
|
}) : /*#__PURE__*/ jsx(MenuEmptyState, {}),
|
|
135
81
|
!filterText && (onSelectAnd || onSelectOr) && /*#__PURE__*/ jsx(OperatorsSection, {
|
|
136
82
|
onSelectAnd: onSelectAnd,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type FC, type RefObject } from 'react';
|
|
2
2
|
import { type ChipSegment } from '../FilterInputField/FilterInputChip';
|
|
3
|
-
import type { FieldMetadata, FilterOperator, MenuState } from '../types';
|
|
3
|
+
import type { FieldGroup, FieldMetadata, FilterOperator, MenuState } from '../types';
|
|
4
4
|
export interface FilterInputAutocompleteState {
|
|
5
5
|
inputText: string;
|
|
6
6
|
menuState: MenuState;
|
|
@@ -29,6 +29,7 @@ export interface FilterInputAutocompleteState {
|
|
|
29
29
|
}
|
|
30
30
|
export interface FilterInputMenuProps {
|
|
31
31
|
fields: FieldMetadata[];
|
|
32
|
+
fieldGroups?: FieldGroup[];
|
|
32
33
|
autocomplete: FilterInputAutocompleteState;
|
|
33
34
|
}
|
|
34
35
|
export declare const FilterInputMenu: FC<FilterInputMenuProps>;
|
|
@@ -6,7 +6,7 @@ import { FilterInputDateValueMenu } from "./FilterInputDateValueMenu/index.js";
|
|
|
6
6
|
import { FilterInputFieldMenu } from "./FilterInputFieldMenu/index.js";
|
|
7
7
|
import { FilterInputOperatorMenu } from "./FilterInputOperatorMenu.js";
|
|
8
8
|
import { FilterInputValueMenu } from "./FilterInputValueMenu/index.js";
|
|
9
|
-
const FilterInputMenu = ({ fields, autocomplete })=>{
|
|
9
|
+
const FilterInputMenu = ({ fields, fieldGroups, autocomplete })=>{
|
|
10
10
|
const { inputText, menuState, selectedField, selectedOperator, menuPositioning, editingMultiValues, editingSingleValue, editingDateRange, inputRef, menuRef, handleFieldSelect, handleOperatorSelect, handleValueSelect, handleMultiCommit, handleRangeSelect, handleMenuClose, handleMenuDiscard, handleBuildingValueChange, handleMultiSelectToggle, segmentMenuFilterText, editingSegment, blurCommitRef } = autocomplete;
|
|
11
11
|
const fieldFilterText = editingSegment === SEGMENT_VARIANT.attribute ? segmentMenuFilterText : inputText;
|
|
12
12
|
const operatorFilterText = editingSegment === SEGMENT_VARIANT.operator ? segmentMenuFilterText : inputText;
|
|
@@ -74,6 +74,7 @@ const FilterInputMenu = ({ fields, autocomplete })=>{
|
|
|
74
74
|
children: [
|
|
75
75
|
/*#__PURE__*/ jsx(FilterInputFieldMenu, {
|
|
76
76
|
fields: fields,
|
|
77
|
+
fieldGroups: fieldGroups,
|
|
77
78
|
filterText: fieldFilterText,
|
|
78
79
|
open: 'field' === menuState,
|
|
79
80
|
onSelect: handleFieldSelect,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { FieldMenuSection } from '../../lib';
|
|
2
|
+
import type { Condition, FieldMetadata, FilterInputDropdownItem } from '../../types';
|
|
3
|
+
interface UseFieldMenuNavItemsParams {
|
|
4
|
+
sections: FieldMenuSection[];
|
|
5
|
+
fields: FieldMetadata[];
|
|
6
|
+
filterText: string;
|
|
7
|
+
limitedRecentConditions: Condition[];
|
|
8
|
+
showRecent: boolean;
|
|
9
|
+
suggestedFields: FieldMetadata[];
|
|
10
|
+
showSuggestions: boolean;
|
|
11
|
+
onSelectAnd?: () => void;
|
|
12
|
+
onSelectOr?: () => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Builds the flat, ordered list of keyboard-navigable items for the field menu:
|
|
16
|
+
* recent → suggestions → grouped section fields → and → or.
|
|
17
|
+
*/
|
|
18
|
+
export declare const useFieldMenuNavItems: ({ sections, fields, filterText, limitedRecentConditions, showRecent, suggestedFields, showSuggestions, onSelectAnd, onSelectOr, }: UseFieldMenuNavItemsParams) => FilterInputDropdownItem[];
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
const useFieldMenuNavItems = ({ sections, fields, filterText, limitedRecentConditions, showRecent, suggestedFields, showSuggestions, onSelectAnd, onSelectOr })=>useMemo(()=>{
|
|
3
|
+
const items = [];
|
|
4
|
+
if (!filterText && showRecent) limitedRecentConditions.forEach((condition, index)=>{
|
|
5
|
+
const fieldMeta = fields.find((f)=>f.name === condition.field);
|
|
6
|
+
items.push({
|
|
7
|
+
id: `recent-${index}`,
|
|
8
|
+
label: fieldMeta?.label || condition.field,
|
|
9
|
+
value: {
|
|
10
|
+
type: 'recent',
|
|
11
|
+
field: fieldMeta
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
if (!filterText && showSuggestions && !showRecent) suggestedFields.forEach((field, index)=>{
|
|
16
|
+
items.push({
|
|
17
|
+
id: `suggested-${index}`,
|
|
18
|
+
label: field.label,
|
|
19
|
+
value: {
|
|
20
|
+
type: 'field',
|
|
21
|
+
field
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
sections.forEach((section)=>{
|
|
26
|
+
section.fields.forEach((field)=>{
|
|
27
|
+
items.push({
|
|
28
|
+
id: `field-${field.name}`,
|
|
29
|
+
label: field.label,
|
|
30
|
+
value: {
|
|
31
|
+
type: 'field',
|
|
32
|
+
field
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
if (!filterText && onSelectAnd) items.push({
|
|
38
|
+
id: 'and',
|
|
39
|
+
label: 'AND',
|
|
40
|
+
value: {
|
|
41
|
+
type: 'and'
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
if (!filterText && onSelectOr) items.push({
|
|
45
|
+
id: 'or',
|
|
46
|
+
label: 'OR',
|
|
47
|
+
value: {
|
|
48
|
+
type: 'or'
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return items;
|
|
52
|
+
}, [
|
|
53
|
+
sections,
|
|
54
|
+
fields,
|
|
55
|
+
limitedRecentConditions,
|
|
56
|
+
suggestedFields,
|
|
57
|
+
showRecent,
|
|
58
|
+
showSuggestions,
|
|
59
|
+
onSelectAnd,
|
|
60
|
+
onSelectOr,
|
|
61
|
+
filterText
|
|
62
|
+
]);
|
|
63
|
+
export { useFieldMenuNavItems };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { FieldGroup, FieldMetadata } from '../types';
|
|
2
|
+
/** A render-ready field-menu section. `label` undefined = headerless. */
|
|
3
|
+
export interface FieldMenuSection {
|
|
4
|
+
label?: string;
|
|
5
|
+
fields: FieldMetadata[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Bucket `fields` into ordered, filtered menu sections. With no `fieldGroups`,
|
|
9
|
+
* returns a single headerless section (today's flat list). With groups: fields
|
|
10
|
+
* render under group headers in group/listed order, unclaimed fields fall into
|
|
11
|
+
* a trailing headerless section, each section is filtered by `filterText`, and
|
|
12
|
+
* sections with no surviving fields are dropped.
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildFieldMenuSections(fields: FieldMetadata[], fieldGroups: FieldGroup[] | undefined, filterText: string): FieldMenuSection[];
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { filterAndSort } from "./filterSort.js";
|
|
2
|
+
const getText = (field)=>[
|
|
3
|
+
field.label,
|
|
4
|
+
field.name
|
|
5
|
+
];
|
|
6
|
+
function buildFieldMenuSections(fields, fieldGroups, filterText) {
|
|
7
|
+
if (!fieldGroups || 0 === fieldGroups.length) {
|
|
8
|
+
const flat = filterAndSort(fields, filterText, getText);
|
|
9
|
+
return flat.length > 0 ? [
|
|
10
|
+
{
|
|
11
|
+
fields: flat
|
|
12
|
+
}
|
|
13
|
+
] : [];
|
|
14
|
+
}
|
|
15
|
+
const byName = new Map(fields.map((field)=>[
|
|
16
|
+
field.name,
|
|
17
|
+
field
|
|
18
|
+
]));
|
|
19
|
+
const claimed = new Set();
|
|
20
|
+
const sections = [];
|
|
21
|
+
for (const group of fieldGroups){
|
|
22
|
+
const groupFields = [];
|
|
23
|
+
for (const name of group.fields){
|
|
24
|
+
if (claimed.has(name)) continue;
|
|
25
|
+
const field = byName.get(name);
|
|
26
|
+
if (field) {
|
|
27
|
+
claimed.add(name);
|
|
28
|
+
groupFields.push(field);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const filtered = filterAndSort(groupFields, filterText, getText);
|
|
32
|
+
if (filtered.length > 0) sections.push({
|
|
33
|
+
label: group.label,
|
|
34
|
+
fields: filtered
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
const ungrouped = fields.filter((field)=>!claimed.has(field.name));
|
|
38
|
+
const filteredUngrouped = filterAndSort(ungrouped, filterText, getText);
|
|
39
|
+
if (filteredUngrouped.length > 0) sections.push({
|
|
40
|
+
fields: filteredUngrouped
|
|
41
|
+
});
|
|
42
|
+
return sections;
|
|
43
|
+
}
|
|
44
|
+
export { buildFieldMenuSections };
|
|
@@ -3,6 +3,7 @@ export { DATE_PRESETS, formatDateForChip, getDateDisplayLabel, isDatePreset, } f
|
|
|
3
3
|
export { applyAcceptChar } from './applyAcceptChar';
|
|
4
4
|
export { applyFieldValueTransforms } from './applyFieldValueTransforms';
|
|
5
5
|
export { applyKnownFieldHelpers, getKnownFieldSerializer } from './applyKnownFieldHelpers';
|
|
6
|
+
export { buildFieldMenuSections, type FieldMenuSection } from './buildFieldMenuSections';
|
|
6
7
|
export { chipIdToConditionIndex, findChipSplitIndex, incompleteTripletError, isEmptyFilterValue, } from './conditions';
|
|
7
8
|
export { CONNECTOR_ID_PATTERN, MENU_BASE_GUTTER, MENU_CHIP_GUTTER_OFFSET, NO_VALUE_OPERATORS, OPERATOR_LABELS, OPERATOR_LABELS_BY_TYPE, OPERATOR_SYMBOLS, OPERATORS_BY_TYPE, QUERY_BAR_SELECTOR, VARIANT_LABELS, } from './constants';
|
|
8
9
|
export { COUNTRY_OPTIONS } from './country';
|
|
@@ -2,6 +2,7 @@ export { DATE_PRESETS, formatDateForChip, getDateDisplayLabel, isDatePreset } fr
|
|
|
2
2
|
export { applyAcceptChar } from "./applyAcceptChar.js";
|
|
3
3
|
export { applyFieldValueTransforms } from "./applyFieldValueTransforms.js";
|
|
4
4
|
export { applyKnownFieldHelpers, getKnownFieldSerializer } from "./applyKnownFieldHelpers.js";
|
|
5
|
+
export { buildFieldMenuSections } from "./buildFieldMenuSections.js";
|
|
5
6
|
export { chipIdToConditionIndex, findChipSplitIndex, incompleteTripletError, isEmptyFilterValue } from "./conditions.js";
|
|
6
7
|
export { CONNECTOR_ID_PATTERN, MENU_BASE_GUTTER, MENU_CHIP_GUTTER_OFFSET, NO_VALUE_OPERATORS, OPERATORS_BY_TYPE, OPERATOR_LABELS, OPERATOR_LABELS_BY_TYPE, OPERATOR_SYMBOLS, QUERY_BAR_SELECTOR, VARIANT_LABELS } from "./constants.js";
|
|
7
8
|
export { COUNTRY_OPTIONS } from "./country/index.js";
|
|
@@ -146,6 +146,19 @@ export interface FieldMetadata {
|
|
|
146
146
|
*/
|
|
147
147
|
pairedField?: FieldMetadata;
|
|
148
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* A labeled group of filter fields for the field-selection menu, referenced by
|
|
151
|
+
* field `name`. Passed to `FilterInput` via the optional `fieldGroups` prop.
|
|
152
|
+
* Groups render in array order; fields within a group in listed order; fields
|
|
153
|
+
* not referenced by any group fall into a trailing headerless section. Unknown
|
|
154
|
+
* names are ignored; a field listed in multiple groups resolves to its first.
|
|
155
|
+
*/
|
|
156
|
+
export interface FieldGroup {
|
|
157
|
+
/** Section header text (e.g. "Threat classification"). */
|
|
158
|
+
label: string;
|
|
159
|
+
/** Field names in display order. */
|
|
160
|
+
fields: string[];
|
|
161
|
+
}
|
|
149
162
|
/**
|
|
150
163
|
* Expression Tree Types
|
|
151
164
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.76.
|
|
3
|
-
"generatedAt": "2026-07-
|
|
2
|
+
"version": "0.76.2",
|
|
3
|
+
"generatedAt": "2026-07-16T14:33:05.767Z",
|
|
4
4
|
"components": [
|
|
5
5
|
{
|
|
6
6
|
"name": "Accordion",
|
|
@@ -29800,6 +29800,12 @@
|
|
|
29800
29800
|
"required": false,
|
|
29801
29801
|
"description": "Filter-field configurations driving the autocomplete. A few names are\n**reserved** and auto-wired with design-system helpers — DS-supplied\ncallbacks **override** consumer values for the reserved slots, because\nthe field semantics (mask range, accepted chars, backend form) are fixed\nby DS:\n\n - `status_code` — HTTP status code field (mask suggestions, format\n validation, digit-or-X input filter, partial-input normalization).\n\nTo opt out, use a different `name` and attach the factories\n(`createStatusCodeSuggestions`, …) manually."
|
|
29802
29802
|
},
|
|
29803
|
+
{
|
|
29804
|
+
"name": "fieldGroups",
|
|
29805
|
+
"type": "FieldGroup[] | undefined",
|
|
29806
|
+
"required": false,
|
|
29807
|
+
"description": "Optional grouping for the field-selection menu. When omitted, fields\nrender as a flat list. When provided, fields render under labeled group\nheaders (group order = array order; field order = listed order). Fields\nnot referenced by any group fall into a trailing headerless section.\nReferenced by field `name`; unknown names are ignored."
|
|
29808
|
+
},
|
|
29803
29809
|
{
|
|
29804
29810
|
"name": "value",
|
|
29805
29811
|
"type": "ExprNode | null | undefined",
|
|
@@ -30463,6 +30469,12 @@
|
|
|
30463
30469
|
"type": "FieldMetadata[] | undefined",
|
|
30464
30470
|
"required": false
|
|
30465
30471
|
},
|
|
30472
|
+
{
|
|
30473
|
+
"name": "fieldGroups",
|
|
30474
|
+
"type": "FieldGroup[] | undefined",
|
|
30475
|
+
"required": false,
|
|
30476
|
+
"description": "Optional grouping for the field list. When omitted, fields render flat."
|
|
30477
|
+
},
|
|
30466
30478
|
{
|
|
30467
30479
|
"name": "positioning",
|
|
30468
30480
|
"type": "Record<string, unknown> | undefined",
|