@wallarm-org/design-system 0.78.1 → 0.79.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.
Files changed (33) hide show
  1. package/dist/components/FilterInput/FilterInputErrors/parseFilterInputErrors.js +2 -2
  2. package/dist/components/FilterInput/FilterInputField/ChipsWithGaps.js +1 -1
  3. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/FilterInputValueMenu.d.ts +21 -3
  4. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/FilterInputValueMenu.js +10 -75
  5. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/FlatValueMenu.d.ts +8 -0
  6. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/FlatValueMenu.js +81 -0
  7. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/NestedValueMenu.d.ts +10 -0
  8. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/NestedValueMenu.js +145 -0
  9. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/NestedValueMenuItem.d.ts +26 -0
  10. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/NestedValueMenuItem.js +54 -0
  11. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/ValueMenuFooterHints.d.ts +12 -0
  12. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/ValueMenuFooterHints.js +69 -0
  13. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/useNestedValueMenuState.d.ts +65 -0
  14. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/useNestedValueMenuState.js +293 -0
  15. package/dist/components/FilterInput/FilterInputMenu/hooks/useKeyboardNav.d.ts +3 -1
  16. package/dist/components/FilterInput/FilterInputMenu/hooks/useKeyboardNav.js +20 -1
  17. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/lib/deriveAutocompleteValues.js +3 -3
  18. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/lib/valueResolution.js +5 -5
  19. package/dist/components/FilterInput/hooks/useFilterInputExpression/buildChips.js +2 -2
  20. package/dist/components/FilterInput/lib/buildValueMenuSections.d.ts +33 -0
  21. package/dist/components/FilterInput/lib/buildValueMenuSections.js +68 -0
  22. package/dist/components/FilterInput/lib/collapseValuesToLabels.d.ts +32 -0
  23. package/dist/components/FilterInput/lib/collapseValuesToLabels.js +55 -0
  24. package/dist/components/FilterInput/lib/fields.d.ts +19 -7
  25. package/dist/components/FilterInput/lib/fields.js +18 -4
  26. package/dist/components/FilterInput/lib/index.d.ts +3 -1
  27. package/dist/components/FilterInput/lib/index.js +3 -1
  28. package/dist/components/FilterInput/lib/validation.js +2 -2
  29. package/dist/components/FilterInput/types.d.ts +31 -2
  30. package/dist/metadata/components.json +2 -2
  31. package/package.json +1 -1
  32. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/ValueMenuFooter.d.ts +0 -6
  33. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/ValueMenuFooter.js +0 -72
@@ -1,13 +1,27 @@
1
+ const isValueGroup = (option)=>Array.isArray(option?.children);
2
+ const collectLeaves = (options)=>{
3
+ if (!options) return [];
4
+ const leaves = [];
5
+ for (const option of options)if (isValueGroup(option)) leaves.push(...collectLeaves(option.children));
6
+ else leaves.push(option);
7
+ return leaves;
8
+ };
9
+ const findLeafInOptions = (options, key)=>{
10
+ if (!options) return;
11
+ for (const option of options)if (isValueGroup(option)) {
12
+ const found = findLeafInOptions(option.children, key);
13
+ if (found) return found;
14
+ } else if (String(option.value) === key) return option;
15
+ };
1
16
  const findOptionByValue = (field, value)=>{
2
17
  if (!field?.values || null == value) return;
3
- const key = String(value);
4
- return field.values.find((opt)=>String(opt.value) === key);
18
+ return findLeafInOptions(field.values, String(value));
5
19
  };
6
20
  const findValueLabelInFields = (value, fields)=>{
7
21
  if (null == value) return;
8
22
  const key = String(value);
9
23
  for (const f of fields){
10
- const opt = f.values?.find((o)=>String(o.value) === key);
24
+ const opt = findLeafInOptions(f.values, key);
11
25
  if (opt) return opt.label;
12
26
  }
13
27
  };
@@ -31,4 +45,4 @@ const hasStaticAllowlist = (field)=>{
31
45
  if ((field.values?.length ?? 0) > 0) return true;
32
46
  return (field.options?.length ?? 0) > 0;
33
47
  };
34
- export { findOptionByValue, findValueLabelInFields, getFieldValues, hasFieldValues, hasStaticAllowlist };
48
+ export { collectLeaves, findOptionByValue, findValueLabelInFields, getFieldValues, hasFieldValues, hasStaticAllowlist, isValueGroup };
@@ -4,11 +4,13 @@ export { applyAcceptChar } from './applyAcceptChar';
4
4
  export { applyFieldValueTransforms } from './applyFieldValueTransforms';
5
5
  export { applyKnownFieldHelpers, getKnownFieldSerializer } from './applyKnownFieldHelpers';
6
6
  export { buildFieldMenuSections, type FieldMenuSection } from './buildFieldMenuSections';
7
+ export { buildValueMenuSections, type ValueMenuRow, type ValueMenuSection, } from './buildValueMenuSections';
8
+ export { type CollapseToken, collapseValues } from './collapseValuesToLabels';
7
9
  export { chipIdToConditionIndex, findChipSplitIndex, incompleteTripletError, isEmptyFilterValue, } from './conditions';
8
10
  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';
9
11
  export { COUNTRY_OPTIONS } from './country';
10
12
  export { type AnchorBounds, buildAnchoredRect, isMenuRelated, toAnchorBounds } from './dom';
11
- export { findOptionByValue, findValueLabelInFields, getFieldValues, hasFieldValues, hasStaticAllowlist, } from './fields';
13
+ export { collectLeaves, findOptionByValue, findValueLabelInFields, getFieldValues, hasFieldValues, hasStaticAllowlist, isValueGroup, } from './fields';
12
14
  export { filterAndSort } from './filterSort';
13
15
  export { getCurrentValueTokenText, getValueFilterText } from './menuFilterText';
14
16
  export { getFieldOperators, getOperatorFromLabel, getOperatorLabel, isBetweenOperator, isBuildingComplete, isMultiSelectOperator, isNoValueOperator, isOperatorAllowedForField, isValueShapeCompatible, NO_VALUE_PLACEHOLDER, nextBuildingMenu, } from './operators';
@@ -3,11 +3,13 @@ export { applyAcceptChar } from "./applyAcceptChar.js";
3
3
  export { applyFieldValueTransforms } from "./applyFieldValueTransforms.js";
4
4
  export { applyKnownFieldHelpers, getKnownFieldSerializer } from "./applyKnownFieldHelpers.js";
5
5
  export { buildFieldMenuSections } from "./buildFieldMenuSections.js";
6
+ export { buildValueMenuSections } from "./buildValueMenuSections.js";
7
+ export { collapseValues } from "./collapseValuesToLabels.js";
6
8
  export { chipIdToConditionIndex, findChipSplitIndex, incompleteTripletError, isEmptyFilterValue } from "./conditions.js";
7
9
  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";
8
10
  export { COUNTRY_OPTIONS } from "./country/index.js";
9
11
  export { buildAnchoredRect, isMenuRelated, toAnchorBounds } from "./dom.js";
10
- export { findOptionByValue, findValueLabelInFields, getFieldValues, hasFieldValues, hasStaticAllowlist } from "./fields.js";
12
+ export { collectLeaves, findOptionByValue, findValueLabelInFields, getFieldValues, hasFieldValues, hasStaticAllowlist, isValueGroup } from "./fields.js";
11
13
  export { filterAndSort } from "./filterSort.js";
12
14
  export { getCurrentValueTokenText, getValueFilterText } from "./menuFilterText.js";
13
15
  export { NO_VALUE_PLACEHOLDER, getFieldOperators, getOperatorFromLabel, getOperatorLabel, isBetweenOperator, isBuildingComplete, isMultiSelectOperator, isNoValueOperator, isOperatorAllowedForField, isValueShapeCompatible, nextBuildingMenu } from "./operators.js";
@@ -1,5 +1,5 @@
1
1
  import { isDatePreset } from "../FilterInputMenu/FilterInputDateValueMenu/constants.js";
2
- import { getFieldValues, hasStaticAllowlist } from "./fields.js";
2
+ import { collectLeaves, getFieldValues, hasStaticAllowlist } from "./fields.js";
3
3
  const isValueOfType = (value, type)=>{
4
4
  switch(type){
5
5
  case 'integer':
@@ -43,7 +43,7 @@ const getInvalidValueIndices = (field, values)=>{
43
43
  return acc;
44
44
  }, []);
45
45
  if (field.getSuggestions) return [];
46
- const allowlist = hasStaticAllowlist(field) ? getFieldValues(field) : null;
46
+ const allowlist = hasStaticAllowlist(field) ? collectLeaves(getFieldValues(field)) : null;
47
47
  return values.reduce((acc, v, idx)=>{
48
48
  if (null == v) return acc;
49
49
  if (!isValueOfType(v, field.type)) {
@@ -50,10 +50,25 @@ export type FieldType = 'string' | 'integer' | 'date' | 'float' | 'boolean' | 'e
50
50
  */
51
51
  export type FilterOperator = '=' | '!=' | '>' | '<' | '>=' | '<=' | 'like' | 'not_like' | 'in' | 'not_in' | 'is_null' | 'is_not_null' | 'between';
52
52
  /**
53
- * Value option for enum/select fields
53
+ * Value option for enum/select fields.
54
+ *
55
+ * A value option is one of two shapes:
56
+ * - a **leaf**: carries a committable `value` (the only thing that reaches the
57
+ * expression tree / backend);
58
+ * - a **group**: carries `children` and **no** `value` — a purely presentational
59
+ * node. Top-level groups render as section headers in the value menu; nested
60
+ * groups render as a submenu trigger row (e.g. an "Attack type" like
61
+ * `SQL injection` that opens a submenu of concrete leaf sub-types). Selecting
62
+ * or toggling a group is a bulk shortcut for its descendant leaves; the group
63
+ * itself is never committed. Nesting is recursive.
54
64
  */
55
65
  export interface FieldValueOption {
56
- value: string | number | boolean;
66
+ /**
67
+ * The committable value. Present on **leaf** options only. Group options
68
+ * (those with `children`) omit it — they are presentational and never
69
+ * committed; only their descendant leaves reach the expression.
70
+ */
71
+ value?: string | number | boolean;
57
72
  label: string;
58
73
  badge?: {
59
74
  color: BadgeColor;
@@ -67,6 +82,20 @@ export interface FieldValueOption {
67
82
  * share a label (two `request-id` rows with different paths).
68
83
  */
69
84
  description?: string;
85
+ /**
86
+ * Nested sub-values. When present, this option is a **group** (no own
87
+ * `value`): a section header at the top level, or a submenu trigger when
88
+ * nested. Recursive — a group's children may themselves be groups. Only the
89
+ * leaves (options without `children`) are committable.
90
+ */
91
+ children?: FieldValueOption[];
92
+ /**
93
+ * Optional section-header label used to bucket top-level value options under
94
+ * a heading in the value menu (parallel to `FieldGroup` for the field menu).
95
+ * An alternative to wrapping options in a top-level group node; ignored for
96
+ * options nested inside a group.
97
+ */
98
+ section?: string;
70
99
  }
71
100
  /**
72
101
  * Field Metadata Interface
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "0.78.0",
3
- "generatedAt": "2026-07-30T09:07:02.172Z",
2
+ "version": "0.78.1",
3
+ "generatedAt": "2026-07-31T19:42:49.319Z",
4
4
  "components": [
5
5
  {
6
6
  "name": "Accordion",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wallarm-org/design-system",
3
- "version": "0.78.1",
3
+ "version": "0.79.0",
4
4
  "description": "Core design system library with React components and Storybook documentation",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -1,6 +0,0 @@
1
- import type { FC } from 'react';
2
- interface ValueMenuFooterProps {
3
- multiSelect: boolean;
4
- }
5
- export declare const ValueMenuFooter: FC<ValueMenuFooterProps>;
6
- export {};
@@ -1,72 +0,0 @@
1
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import { DropdownMenuFooter } from "../../../DropdownMenu/index.js";
3
- import { Kbd } from "../../../Kbd/Kbd.js";
4
- import { KbdGroup } from "../../../Kbd/KbdGroup.js";
5
- const ValueMenuFooter = ({ multiSelect })=>/*#__PURE__*/ jsx(DropdownMenuFooter, {
6
- children: multiSelect ? /*#__PURE__*/ jsxs(Fragment, {
7
- children: [
8
- /*#__PURE__*/ jsxs("span", {
9
- className: "flex items-center gap-4",
10
- children: [
11
- /*#__PURE__*/ jsx(KbdGroup, {
12
- children: /*#__PURE__*/ jsx(Kbd, {
13
- children: "↵"
14
- })
15
- }),
16
- "to select"
17
- ]
18
- }),
19
- /*#__PURE__*/ jsxs("span", {
20
- className: "flex items-center gap-4",
21
- children: [
22
- /*#__PURE__*/ jsxs(KbdGroup, {
23
- children: [
24
- /*#__PURE__*/ jsx(Kbd, {
25
- children: "⌘"
26
- }),
27
- /*#__PURE__*/ jsx(Kbd, {
28
- children: "↑"
29
- }),
30
- /*#__PURE__*/ jsx(Kbd, {
31
- children: "↓"
32
- })
33
- ]
34
- }),
35
- "to multi-select"
36
- ]
37
- })
38
- ]
39
- }) : /*#__PURE__*/ jsxs(Fragment, {
40
- children: [
41
- /*#__PURE__*/ jsxs("span", {
42
- className: "flex items-center gap-4",
43
- children: [
44
- /*#__PURE__*/ jsxs(KbdGroup, {
45
- children: [
46
- /*#__PURE__*/ jsx(Kbd, {
47
- children: "↑"
48
- }),
49
- /*#__PURE__*/ jsx(Kbd, {
50
- children: "↓"
51
- })
52
- ]
53
- }),
54
- "to navigate"
55
- ]
56
- }),
57
- /*#__PURE__*/ jsxs("span", {
58
- className: "flex items-center gap-4",
59
- children: [
60
- /*#__PURE__*/ jsx(KbdGroup, {
61
- children: /*#__PURE__*/ jsx(Kbd, {
62
- children: "↵"
63
- })
64
- }),
65
- "to select"
66
- ]
67
- })
68
- ]
69
- })
70
- });
71
- ValueMenuFooter.displayName = 'ValueMenuFooter';
72
- export { ValueMenuFooter };