@wallarm-org/design-system 0.41.0 → 0.42.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 (93) hide show
  1. package/dist/components/FilterInput/FilterInput.d.ts +7 -8
  2. package/dist/components/FilterInput/FilterInputContext/types.d.ts +12 -9
  3. package/dist/components/FilterInput/FilterInputContext/useFilterInputContextValue.d.ts +4 -2
  4. package/dist/components/FilterInput/FilterInputContext/useFilterInputContextValue.js +4 -0
  5. package/dist/components/FilterInput/FilterInputErrors/parseFilterInputErrors.js +1 -2
  6. package/dist/components/FilterInput/FilterInputField/ChipsWithGaps.d.ts +1 -1
  7. package/dist/components/FilterInput/FilterInputField/ChipsWithGaps.js +1 -1
  8. package/dist/components/FilterInput/FilterInputField/FilterInputChip/FilterInputChip.d.ts +1 -1
  9. package/dist/components/FilterInput/FilterInputField/FilterInputChip/FilterInputChip.js +2 -2
  10. package/dist/components/FilterInput/FilterInputField/FilterInputField.js +11 -40
  11. package/dist/components/FilterInput/FilterInputField/hooks/useSegmentEditKeyboard.d.ts +37 -0
  12. package/dist/components/FilterInput/FilterInputField/hooks/useSegmentEditKeyboard.js +78 -0
  13. package/dist/components/FilterInput/FilterInputMenu/FilterInputDateValueMenu/constants.d.ts +2 -2
  14. package/dist/components/FilterInput/FilterInputMenu/FilterInputFieldMenu/FilterInputFieldMenu.d.ts +1 -1
  15. package/dist/components/FilterInput/FilterInputMenu/FilterInputMenu.d.ts +1 -1
  16. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/FilterInputValueMenu.d.ts +5 -6
  17. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/useValueMenuDisplayValues.d.ts +4 -14
  18. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/useValueMenuState.d.ts +3 -5
  19. package/dist/components/FilterInput/FilterInputMenu/hooks/useKeyboardNav.d.ts +1 -1
  20. package/dist/components/FilterInput/FilterInputMenu/hooks/useKeyboardNav.js +5 -2
  21. package/dist/components/FilterInput/hooks/useAutoCleanupDetachedElement.d.ts +13 -0
  22. package/dist/components/FilterInput/hooks/useAutoCleanupDetachedElement.js +22 -0
  23. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{deriveAutocompleteValues.d.ts → lib/deriveAutocompleteValues.d.ts} +3 -3
  24. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{deriveAutocompleteValues.js → lib/deriveAutocompleteValues.js} +1 -1
  25. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/lib/getInitialSegmentText.d.ts +9 -0
  26. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/lib/getInitialSegmentText.js +8 -0
  27. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/lib/index.d.ts +3 -0
  28. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/lib/index.js +4 -0
  29. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{valueCommitHelpers.d.ts → lib/valueResolution.d.ts} +1 -7
  30. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{valueCommitHelpers.js → lib/valueResolution.js} +3 -25
  31. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useAutocompleteState.d.ts +36 -0
  32. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useAutocompleteState.js +53 -0
  33. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useBlurCommit.d.ts +5 -16
  34. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useBlurCommit.js +12 -5
  35. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useChipActions.d.ts +2 -2
  36. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useChipActions.js +5 -5
  37. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useChipCascade.d.ts +44 -0
  38. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useChipCascade.js +99 -0
  39. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useChipEditing.d.ts +7 -8
  40. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useChipEditing.js +21 -16
  41. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFilterInputAutocomplete.d.ts +9 -10
  42. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFilterInputAutocomplete.js +50 -83
  43. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFocusManagement.d.ts +9 -11
  44. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFocusManagement.js +47 -20
  45. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useInputHandlers.d.ts +6 -4
  46. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useInputHandlers.js +32 -15
  47. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/index.d.ts +1 -0
  48. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/index.js +2 -0
  49. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{useMenuFlow.d.ts → useMenuFlow/types.d.ts} +15 -18
  50. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/types.js +0 -0
  51. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useFieldFlow.d.ts +11 -0
  52. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useFieldFlow.js +95 -0
  53. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useMenuFlow.d.ts +20 -0
  54. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useMenuFlow.js +47 -0
  55. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useOperatorFlow.d.ts +11 -0
  56. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useOperatorFlow.js +87 -0
  57. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useValueFlow.d.ts +14 -0
  58. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useValueFlow.js +107 -0
  59. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuPositioning.d.ts +25 -8
  60. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuPositioning.js +38 -22
  61. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useResetState.d.ts +10 -19
  62. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useResetState.js +3 -3
  63. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useSegmentEditFlow.d.ts +36 -0
  64. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useSegmentEditFlow.js +69 -0
  65. package/dist/components/FilterInput/hooks/useFilterInputExpression/buildChips.js +1 -2
  66. package/dist/components/FilterInput/hooks/useFilterInputPositioning.d.ts +9 -4
  67. package/dist/components/FilterInput/hooks/useFilterInputPositioning.js +7 -6
  68. package/dist/components/FilterInput/hooks/useFilterInputSelection/lib/dom.d.ts +4 -4
  69. package/dist/components/FilterInput/hooks/useFilterInputSelection/useFilterInputSelection.d.ts +2 -2
  70. package/dist/components/FilterInput/hooks/useFilterInputSelection/useSelectionClipboard.d.ts +2 -5
  71. package/dist/components/FilterInput/hooks/useFloatingRecomputeOn.d.ts +14 -0
  72. package/dist/components/FilterInput/hooks/useFloatingRecomputeOn.js +18 -0
  73. package/dist/components/FilterInput/hooks/useResizeTracker.d.ts +10 -0
  74. package/dist/components/FilterInput/hooks/useResizeTracker.js +21 -0
  75. package/dist/components/FilterInput/lib/applyAcceptChar.d.ts +3 -4
  76. package/dist/components/FilterInput/lib/applyKnownFieldHelpers.d.ts +13 -25
  77. package/dist/components/FilterInput/lib/constants.d.ts +16 -34
  78. package/dist/components/FilterInput/lib/constants.js +3 -1
  79. package/dist/components/FilterInput/lib/dom.d.ts +15 -11
  80. package/dist/components/FilterInput/lib/dom.js +14 -9
  81. package/dist/components/FilterInput/lib/fields.d.ts +10 -19
  82. package/dist/components/FilterInput/lib/index.d.ts +4 -2
  83. package/dist/components/FilterInput/lib/index.js +5 -3
  84. package/dist/components/FilterInput/lib/menuFilterText.d.ts +8 -18
  85. package/dist/components/FilterInput/lib/operators.d.ts +11 -21
  86. package/dist/components/FilterInput/lib/segmentMenu.d.ts +4 -0
  87. package/dist/components/FilterInput/lib/segmentMenu.js +7 -0
  88. package/dist/components/FilterInput/lib/serializeExpression.d.ts +5 -12
  89. package/dist/components/FilterInput/lib/validation.d.ts +9 -0
  90. package/dist/components/FilterInput/lib/validation.js +24 -0
  91. package/dist/metadata/components.json +8 -8
  92. package/package.json +1 -1
  93. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow.js +0 -260
@@ -1,19 +1,20 @@
1
1
  import { useMemo } from "react";
2
- import { QUERY_BAR_SELECTOR, buildContainerAnchoredRect } from "../lib/index.js";
3
- const useFilterInputPositioning = ({ anchorRef, containerRef, getAnchorLeft }, deps = [])=>useMemo(()=>({
2
+ import { QUERY_BAR_SELECTOR, buildAnchoredRect, toAnchorBounds } from "../lib/index.js";
3
+ const useFilterInputPositioning = ({ anchorRef, containerRef, getAnchorBounds, gutter = 12 }, deps = [])=>useMemo(()=>({
4
4
  placement: 'bottom-start',
5
- gutter: 4,
5
+ gutter,
6
6
  getAnchorRect: ()=>{
7
7
  const containerEl = containerRef?.current ?? anchorRef?.current?.closest(QUERY_BAR_SELECTOR);
8
8
  const containerRect = containerEl?.getBoundingClientRect();
9
9
  if (!containerRect) return null;
10
- const left = getAnchorLeft ? getAnchorLeft(containerRect) : anchorRef?.current?.getBoundingClientRect().left ?? containerRect.left;
11
- return buildContainerAnchoredRect(containerRect, left);
10
+ const anchor = getAnchorBounds ? getAnchorBounds(containerRect) : toAnchorBounds(anchorRef?.current?.getBoundingClientRect() ?? containerRect);
11
+ return buildAnchoredRect(anchor, containerRect);
12
12
  }
13
13
  }), [
14
14
  anchorRef,
15
15
  containerRef,
16
- getAnchorLeft,
16
+ getAnchorBounds,
17
+ gutter,
17
18
  ...deps
18
19
  ]);
19
20
  export { useFilterInputPositioning };
@@ -11,12 +11,12 @@ interface VisualEntry {
11
11
  }
12
12
  /** Snapshot registry entries with cached rects, sorted by visual position (top→bottom, left→right) */
13
13
  export declare const getVisualEntries: (registry: Map<string, HTMLElement>) => VisualEntry[];
14
- /** Resolve the condition chip ID at the mousedown point (called once per drag). */
14
+ /** Resolve the condition chip ID at the mousedown point (once per drag). */
15
15
  export declare const resolveAnchorChipId: (registry: Map<string, HTMLElement>, target: HTMLElement, x: number, y: number) => string | null;
16
16
  /**
17
- * Mark chips as drag-selected from a fixed anchor chip to the current cursor position.
18
- * Both anchor and end are resolved in the same visually-sorted array so indices always match.
19
- * Connectors between selected condition chips are included automatically.
17
+ * Mark chips drag-selected from anchor to cursor. Both ends resolve in the
18
+ * same visually-sorted array so indices match; intermediate connectors are
19
+ * included automatically.
20
20
  */
21
21
  export declare const updateDragSelection: (all: VisualEntry[], anchorChipId: string, currentX: number, currentY: number) => boolean;
22
22
  export {};
@@ -10,9 +10,9 @@ interface UseFilterInputSelectionOptions {
10
10
  clearAll: () => void;
11
11
  setInputText: (text: string) => void;
12
12
  closeMenu: () => void;
13
- /** Replace the entire expression used by paste so local state stays in sync even when uncontrolled. */
13
+ /** Replace the entire expression (paste path keeps local state in sync). */
14
14
  replaceExpression: (expression: ExprNode | null) => void;
15
- /** Reset transient autocomplete state after paste (insertIndex, selectedField, menuState, …). */
15
+ /** Reset transient autocomplete state after paste. */
16
16
  resetAutocompleteState: () => void;
17
17
  }
18
18
  export declare const useFilterInputSelection: ({ conditions, connectors, fields, containerRef, chipRegistryRef, inputRef, clearAll, setInputText, closeMenu, replaceExpression, resetAutocompleteState, }: UseFilterInputSelectionOptions) => {
@@ -11,11 +11,8 @@ interface UseSelectionClipboardOptions {
11
11
  closeMenu: () => void;
12
12
  /** Replace the whole expression. Updates local state so paste works in uncontrolled mode too. */
13
13
  replaceExpression: (expression: ExprNode | null) => void;
14
- /**
15
- * Reset transient autocomplete state (insertIndex, selectedField/Operator, menuState, etc.)
16
- * after a successful paste — otherwise a stale `insertIndex` from a prior gap-click or
17
- * Backspace puts the input cursor between newly-pasted chips instead of at the end.
18
- */
14
+ /** Reset transient autocomplete state after paste; otherwise stale
15
+ * insertIndex puts the cursor between newly-pasted chips. */
19
16
  resetAutocompleteState: () => void;
20
17
  }
21
18
  export declare const useSelectionClipboard: ({ conditions, connectors, fields, chipRegistryRef, clearSelection, setPasteError, setInputText, closeMenu, replaceExpression, resetAutocompleteState, }: UseSelectionClipboardOptions) => {
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Pokes floating-ui (via @zag-js / Ark UI) to recompute when `dep` changes.
3
+ * floating-ui's autoUpdate listens for resize/scroll but not sibling reflow,
4
+ * so a laterally-shifting anchor would lag one paint. Must be useLayoutEffect
5
+ * — useEffect runs after paint.
6
+ *
7
+ * Two scoping rules:
8
+ * - `enabled = false` short-circuits entirely (no event while menu closed).
9
+ * - First mount is skipped (no transition has occurred yet).
10
+ *
11
+ * The dispatch is still a global `resize` (autoUpdate's only listener) — keep
12
+ * dep-change rate low at the call site.
13
+ */
14
+ export declare const useFloatingRecomputeOn: (dep: unknown, enabled?: boolean) => void;
@@ -0,0 +1,18 @@
1
+ import { useLayoutEffect, useRef } from "react";
2
+ const useFloatingRecomputeOn = (dep, enabled = true)=>{
3
+ const prevDepRef = useRef(dep);
4
+ useLayoutEffect(()=>{
5
+ if (!enabled) {
6
+ prevDepRef.current = dep;
7
+ return;
8
+ }
9
+ if ("u" < typeof window) return;
10
+ if (Object.is(prevDepRef.current, dep)) return;
11
+ prevDepRef.current = dep;
12
+ window.dispatchEvent(new Event('resize'));
13
+ }, [
14
+ dep,
15
+ enabled
16
+ ]);
17
+ };
18
+ export { useFloatingRecomputeOn };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Observes up to three elements with one ResizeObserver and returns a counter
3
+ * that increments on every resize — use as a memo/effect dep to force
4
+ * recompute when a tracked element changes size. Null entries are skipped.
5
+ *
6
+ * Observing a detached element is safe: ResizeObserver simply doesn't fire
7
+ * until the element re-attaches and lays out, then resumes — no leak. We do
8
+ * NOT filter detached nodes so re-attach is picked up without ref churn.
9
+ */
10
+ export declare const useResizeTracker: (el1: HTMLElement | null, el2?: HTMLElement | null, el3?: HTMLElement | null) => number;
@@ -0,0 +1,21 @@
1
+ import { useEffect, useReducer } from "react";
2
+ const useResizeTracker = (el1, el2, el3)=>{
3
+ const [tick, bump] = useReducer((x)=>x + 1, 0);
4
+ useEffect(()=>{
5
+ const targets = [
6
+ el1,
7
+ el2,
8
+ el3
9
+ ].filter((el)=>null != el);
10
+ if (0 === targets.length) return;
11
+ const observer = new ResizeObserver(()=>bump());
12
+ for (const el of targets)observer.observe(el);
13
+ return ()=>observer.disconnect();
14
+ }, [
15
+ el1,
16
+ el2,
17
+ el3
18
+ ]);
19
+ return tick;
20
+ };
21
+ export { useResizeTracker };
@@ -1,7 +1,6 @@
1
1
  /**
2
- * Strip characters from `text` that fail the field's `acceptChar` predicate.
3
- * Commas and spaces always pass through so multi-select delimiters keep
4
- * working. Returns the original string unchanged when no filtering was
5
- * needed, so callers can cheaply compare identity to detect a no-op.
2
+ * Strip chars failing `acceptChar`. Commas/spaces pass through (multi-select
3
+ * delimiters). Returns the same string when no filtering happens, so callers
4
+ * can identity-compare to detect a no-op.
6
5
  */
7
6
  export declare const applyAcceptChar: (text: string, acceptChar: (c: string) => boolean) => string;
@@ -1,34 +1,22 @@
1
1
  import type { FieldMetadata } from '../types';
2
2
  /**
3
- * Decorate `fields` in place with design-system helpers for known field names.
4
- * `FilterInput` calls this on the `fields` prop before rendering.
3
+ * Decorate `fields` with design-system helpers for reserved names. DS-supplied
4
+ * callbacks **override** consumer values for the same slot the field
5
+ * semantics (mask range, accepted chars, backend form) are fixed by DS.
5
6
  *
6
- * Reserved names and what the design system owns:
7
+ * Reserved names:
8
+ * | `name` | DS owns |
9
+ * | ------------- | -------------------------------------------------------- |
10
+ * | `status_code` | acceptChar, normalize, getSuggestions, validate, serializeValue |
7
11
  *
8
- * | `name` | DS owns |
9
- * | ------------- | ------------------------------------------------------------------------------------------ |
10
- * | `status_code` | HTTP status code: `acceptChar`, `normalize`, `getSuggestions`, `validate`, `serializeValue` |
11
- *
12
- * For reserved names, DS-supplied callbacks **override** any consumer-supplied
13
- * value for the same slot. This is intentional: the field semantics (mask
14
- * range `1XX..5XX`, accepted characters, backend form) are fixed by the
15
- * design system. Consumer-supplied `options`/`getSuggestions` would otherwise
16
- * fight the canonical mask UX.
17
- *
18
- * If the backend uses a different name (e.g. `http_status_code`), the helpers
19
- * are NOT applied — the consumer must either rename the field to match or
20
- * wire the factories (`createStatusCode*`) manually.
21
- *
22
- * The returned array has **reference-stable identity** when no field matches,
23
- * so downstream `useMemo` that depends on it does not invalidate unnecessarily.
12
+ * Backend with a different name (e.g. `http_status_code`) must either rename
13
+ * or wire factories (`createStatusCode*`) manually. Returns the input array
14
+ * by reference when no field matches (stable identity for downstream memos).
24
15
  */
25
16
  export declare const applyKnownFieldHelpers: (fields: FieldMetadata[]) => FieldMetadata[];
26
17
  /**
27
- * Look up the backend-form serializer for a reserved field name. Returns
28
- * `undefined` for unknown names. Useful for consumers that hold their own
29
- * expression shape (not DS `ExprNode`) but need to apply the same backend
30
- * transform that the FilterInput's `serializeValue` slot would produce — so
31
- * they can drive the lookup off the field name without hard-coding which
32
- * names are reserved.
18
+ * Look up the backend-form serializer for a reserved field name; returns
19
+ * undefined for unknown names. For consumers that hold their own expression
20
+ * shape but want the same transform as FilterInput's `serializeValue`.
33
21
  */
34
22
  export declare const getKnownFieldSerializer: (fieldName: string) => NonNullable<FieldMetadata["serializeValue"]> | undefined;
@@ -1,45 +1,27 @@
1
1
  import type { FieldType, FilterInputChipVariant, FilterOperator } from '../types';
2
- /**
3
- * Operators that require no value (unary)
4
- */
2
+ /** Operators that require no value (unary). */
5
3
  export declare const NO_VALUE_OPERATORS: readonly FilterOperator[];
6
- /**
7
- * Operators that support multi-select values
8
- */
4
+ /** Operators that support multi-select values. */
9
5
  export declare const MULTI_SELECT_OPERATORS: readonly FilterOperator[];
10
- /**
11
- * Pattern to extract condition index from chip ID (e.g. "chip-2" → 2)
12
- */
6
+ /** Extract condition index from chip ID (e.g. "chip-2" → 2). */
13
7
  export declare const CHIP_ID_PATTERN: RegExp;
14
- /**
15
- * Pattern to extract condition index from connector ID (e.g. "connector-2" → 2)
16
- */
8
+ /** Extract condition index from connector ID. */
17
9
  export declare const CONNECTOR_ID_PATTERN: RegExp;
18
- /**
19
- * DOM selector for the FilterInput root element
20
- */
10
+ /** DOM selector for the FilterInput root element. */
21
11
  export declare const QUERY_BAR_SELECTOR = "[data-slot=\"filter-input\"]";
22
- /**
23
- * Labels for non-chip filter chip variants (connectors, brackets)
24
- */
12
+ /** Gap between the dropdown and the field border in the empty/initial state. */
13
+ export declare const MENU_BASE_GUTTER = 4;
14
+ /** Extra vertical offset added to the anchor's bottom when the dropdown is
15
+ * anchored to a chip / input — total visual gap becomes
16
+ * MENU_BASE_GUTTER + MENU_CHIP_GUTTER_OFFSET (12). */
17
+ export declare const MENU_CHIP_GUTTER_OFFSET = 8;
18
+ /** Labels for non-chip filter chip variants (connectors, brackets). */
25
19
  export declare const VARIANT_LABELS: Partial<Record<FilterInputChipVariant, string>>;
26
- /**
27
- * Operator Symbol Mapping
28
- * Maps operators to their raw symbol displayed on the right side of menus
29
- */
20
+ /** Raw operator symbols shown on the right side of menus. */
30
21
  export declare const OPERATOR_SYMBOLS: Record<FilterOperator, string>;
31
- /**
32
- * Operator Label Mapping
33
- * Maps operator symbols to human-readable labels
34
- */
22
+ /** Human-readable labels for operator symbols. */
35
23
  export declare const OPERATOR_LABELS: Record<FilterOperator, string>;
36
- /**
37
- * Field type-specific operator labels
38
- * Some operators have different labels depending on field type
39
- */
24
+ /** Field-type-specific operator labels (some override the generic ones). */
40
25
  export declare const OPERATOR_LABELS_BY_TYPE: Record<FieldType, Partial<Record<FilterOperator, string>>>;
41
- /**
42
- * Operators by Field Type Mapping (with groups for separators)
43
- * Maps field types to their available operators, grouped logically
44
- */
26
+ /** Operators per field type, grouped for menu separators. */
45
27
  export declare const OPERATORS_BY_TYPE: Record<FieldType, FilterOperator[][]>;
@@ -9,6 +9,8 @@ const MULTI_SELECT_OPERATORS = [
9
9
  const CHIP_ID_PATTERN = /^chip-(\d+)$/;
10
10
  const CONNECTOR_ID_PATTERN = /^connector-(\d+)$/;
11
11
  const QUERY_BAR_SELECTOR = '[data-slot="filter-input"]';
12
+ const MENU_BASE_GUTTER = 4;
13
+ const MENU_CHIP_GUTTER_OFFSET = 8;
12
14
  const VARIANT_LABELS = {
13
15
  and: 'AND',
14
16
  or: 'OR',
@@ -163,4 +165,4 @@ const OPERATORS_BY_TYPE = {
163
165
  ]
164
166
  ]
165
167
  };
166
- export { CHIP_ID_PATTERN, CONNECTOR_ID_PATTERN, MULTI_SELECT_OPERATORS, NO_VALUE_OPERATORS, OPERATORS_BY_TYPE, OPERATOR_LABELS, OPERATOR_LABELS_BY_TYPE, OPERATOR_SYMBOLS, QUERY_BAR_SELECTOR, VARIANT_LABELS };
168
+ export { CHIP_ID_PATTERN, CONNECTOR_ID_PATTERN, MENU_BASE_GUTTER, MENU_CHIP_GUTTER_OFFSET, MULTI_SELECT_OPERATORS, NO_VALUE_OPERATORS, OPERATORS_BY_TYPE, OPERATOR_LABELS, OPERATOR_LABELS_BY_TYPE, OPERATOR_SYMBOLS, QUERY_BAR_SELECTOR, VARIANT_LABELS };
@@ -1,19 +1,23 @@
1
1
  /**
2
- * Check if an element belongs to a FilterInput-owned menu/portal overlay.
3
- *
4
- * Menus are marked with `data-filter-input-menu` on their `DropdownMenuContent`
5
- * root. Generic Ark UI selectors (`[role="menu"]`, `[data-part="content"]`,
6
- * `[data-scope="date-picker"]`) intentionally DO NOT match — otherwise blur
7
- * handlers mistake unrelated page popups (tenant switcher, other dropdowns)
8
- * for FilterInput's own menu and refuse to close. See AS-882.
2
+ * True if element belongs to a FilterInput-owned menu overlay. Marked by
3
+ * `data-filter-input-menu` on DropdownMenuContent — generic Ark UI selectors
4
+ * are intentionally NOT used so blur handlers don't confuse unrelated page
5
+ * popups (tenant switcher etc.) for FilterInput's own menu. AS-882.
9
6
  */
10
7
  export declare const isMenuRelated: (el: HTMLElement | null) => boolean;
8
+ export interface AnchorBounds {
9
+ top: number;
10
+ bottom: number;
11
+ left: number;
12
+ }
13
+ /** Extract anchor bounds from a DOMRect (right edge is computed at build time). */
14
+ export declare const toAnchorBounds: (rect: DOMRect) => AnchorBounds;
11
15
  /**
12
- * Build a DOMRect-compatible object anchored vertically to the container
13
- * and horizontally to the given left position. Used by all FilterInput dropdowns
14
- * so they share the same vertical gap from the container bottom edge.
16
+ * Build a DOMRect-compatible object from the anchor's vertical bounds + left
17
+ * edge; right edge stays at the container's right so the dropdown can expand
18
+ * to full container width below the actual interaction target.
15
19
  */
16
- export declare const buildContainerAnchoredRect: (containerRect: DOMRect, anchorLeft: number, anchorRight?: number) => {
20
+ export declare const buildAnchoredRect: (anchor: AnchorBounds, containerRect: DOMRect, anchorRight?: number) => {
17
21
  x: number;
18
22
  y: number;
19
23
  width: number;
@@ -1,12 +1,17 @@
1
1
  const isMenuRelated = (el)=>!!el?.closest('[data-filter-input-menu]');
2
- const buildContainerAnchoredRect = (containerRect, anchorLeft, anchorRight = containerRect.right)=>({
3
- x: anchorLeft,
4
- y: containerRect.top,
5
- width: anchorRight - anchorLeft,
6
- height: containerRect.height,
7
- top: containerRect.top,
8
- bottom: containerRect.bottom,
9
- left: anchorLeft,
2
+ const toAnchorBounds = (rect)=>({
3
+ top: rect.top,
4
+ bottom: rect.bottom,
5
+ left: rect.left
6
+ });
7
+ const buildAnchoredRect = (anchor, containerRect, anchorRight = containerRect.right)=>({
8
+ x: anchor.left,
9
+ y: anchor.top,
10
+ width: anchorRight - anchor.left,
11
+ height: anchor.bottom - anchor.top,
12
+ top: anchor.top,
13
+ bottom: anchor.bottom,
14
+ left: anchor.left,
10
15
  right: anchorRight
11
16
  });
12
- export { buildContainerAnchoredRect, isMenuRelated };
17
+ export { buildAnchoredRect, isMenuRelated, toAnchorBounds };
@@ -1,34 +1,25 @@
1
1
  import type { FieldMetadata, FieldValueOption } from '../types';
2
2
  /**
3
- * Find an option in `field.values` matching the given value, using stringified
4
- * comparison. Loose-match is required because parser/serializer round-trip
5
- * coerces typed primitives to strings (e.g. integer field value `5` string
6
- * `"5"` after `(field = "5")` parses back), and strict `===` would miss the
7
- * canonical option. Returns undefined when there is no match or the field
8
- * has no `values` allowlist.
3
+ * Find an option in `field.values` matching the value (stringified compare).
4
+ * Loose-match needed because parser/serializer round-trip stringifies typed
5
+ * primitives (5 "5") and strict === would miss the canonical option.
9
6
  */
10
7
  export declare const findOptionByValue: (field: FieldMetadata | undefined, value: string | number | boolean | null | undefined) => FieldValueOption | undefined;
11
8
  /**
12
- * Get value options for a field.
13
- * Priority: `getSuggestions(inputText, context)` > `values` > `options` (converted to `{value, label}`).
14
- *
15
- * `context.selectedValues` is forwarded to `getSuggestions` so helpers can
16
- * include the currently-committed values in their output (e.g. to preserve a
17
- * badge style on a concrete code once suggestions have narrowed to masks).
9
+ * Get value options for a field — priority: getSuggestions > values > options.
10
+ * `context.selectedValues` lets helpers preserve a committed value's badge
11
+ * style once suggestions have narrowed.
18
12
  */
19
13
  export declare const getFieldValues: (field: FieldMetadata, inputText?: string, context?: {
20
14
  selectedValues?: Array<string | number | boolean>;
21
15
  }) => FieldValueOption[];
22
16
  /**
23
- * Check whether a field has a source of value suggestions dynamic callback, static
24
- * `values`, or `options`. Used to decide whether to render a value dropdown at all.
25
- * Fields with `getSuggestions` always get a dropdown (empty list is still a list).
17
+ * True if a field has any value suggestions (dynamic, values, or options).
18
+ * Decides whether to render a value dropdown. getSuggestions always yields one.
26
19
  */
27
20
  export declare const hasFieldValues: (field: FieldMetadata) => boolean;
28
21
  /**
29
- * Whether the field has an exhaustive static allowlist of accepted values.
30
- * Used by validation code to decide whether to reject values outside the list.
31
- * Fields with `getSuggestions` return false — their suggestion list is a hint,
32
- * not an allowlist (consumer may accept freeform values that aren't currently suggested).
22
+ * True if the field has an exhaustive static allowlist. getSuggestions
23
+ * fields return false their list is a hint, not a strict allowlist.
33
24
  */
34
25
  export declare const hasStaticAllowlist: (field: FieldMetadata) => boolean;
@@ -4,12 +4,14 @@ export { applyAcceptChar } from './applyAcceptChar';
4
4
  export { applyFieldValueTransforms } from './applyFieldValueTransforms';
5
5
  export { applyKnownFieldHelpers, getKnownFieldSerializer } from './applyKnownFieldHelpers';
6
6
  export { chipIdToConditionIndex, findChipSplitIndex } from './conditions';
7
- export { CONNECTOR_ID_PATTERN, NO_VALUE_OPERATORS, OPERATOR_LABELS, OPERATOR_LABELS_BY_TYPE, OPERATOR_SYMBOLS, OPERATORS_BY_TYPE, QUERY_BAR_SELECTOR, VARIANT_LABELS, } from './constants';
8
- export { buildContainerAnchoredRect, isMenuRelated } from './dom';
7
+ 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
+ export { type AnchorBounds, buildAnchoredRect, isMenuRelated, toAnchorBounds } from './dom';
9
9
  export { findOptionByValue, getFieldValues, hasFieldValues, hasStaticAllowlist } from './fields';
10
10
  export { filterAndSort } from './filterSort';
11
11
  export { getCurrentValueTokenText, getValueFilterText } from './menuFilterText';
12
12
  export { getFieldOperators, getOperatorFromLabel, getOperatorLabel, isBetweenOperator, isBuildingComplete, isMultiSelectOperator, isNoValueOperator, isOperatorAllowedForField, isValueShapeCompatible, NO_VALUE_PLACEHOLDER, nextBuildingMenu, } from './operators';
13
13
  export { type FilterParseError, isFilterParseError, parseExpression } from './parseExpression';
14
+ export { SEGMENT_TO_MENU } from './segmentMenu';
14
15
  export { serializeExpression } from './serializeExpression';
15
16
  export { createStatusCodeInputFilter, createStatusCodeNormalizer, createStatusCodeSerializer, createStatusCodeSuggestions, createStatusCodeValidator, } from './statusCode';
17
+ export { findMatchingFieldValue, getInvalidValueIndices, isValidFieldValue, validateValueForField, } from './validation';
@@ -3,13 +3,15 @@ import { applyAcceptChar } from "./applyAcceptChar.js";
3
3
  import { applyFieldValueTransforms } from "./applyFieldValueTransforms.js";
4
4
  import { applyKnownFieldHelpers, getKnownFieldSerializer } from "./applyKnownFieldHelpers.js";
5
5
  import { chipIdToConditionIndex, findChipSplitIndex } from "./conditions.js";
6
- import { CONNECTOR_ID_PATTERN, NO_VALUE_OPERATORS, OPERATORS_BY_TYPE, OPERATOR_LABELS, OPERATOR_LABELS_BY_TYPE, OPERATOR_SYMBOLS, QUERY_BAR_SELECTOR, VARIANT_LABELS } from "./constants.js";
7
- import { buildContainerAnchoredRect, isMenuRelated } from "./dom.js";
6
+ import { 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
+ import { buildAnchoredRect, isMenuRelated, toAnchorBounds } from "./dom.js";
8
8
  import { findOptionByValue, getFieldValues, hasFieldValues, hasStaticAllowlist } from "./fields.js";
9
9
  import { filterAndSort } from "./filterSort.js";
10
10
  import { getCurrentValueTokenText, getValueFilterText } from "./menuFilterText.js";
11
11
  import { NO_VALUE_PLACEHOLDER, getFieldOperators, getOperatorFromLabel, getOperatorLabel, isBetweenOperator, isBuildingComplete, isMultiSelectOperator, isNoValueOperator, isOperatorAllowedForField, isValueShapeCompatible, nextBuildingMenu } from "./operators.js";
12
12
  import { isFilterParseError, parseExpression } from "./parseExpression/index.js";
13
+ import { SEGMENT_TO_MENU } from "./segmentMenu.js";
13
14
  import { serializeExpression } from "./serializeExpression.js";
14
15
  import { createStatusCodeInputFilter, createStatusCodeNormalizer, createStatusCodeSerializer, createStatusCodeSuggestions, createStatusCodeValidator } from "./statusCode/index.js";
15
- export { CONNECTOR_ID_PATTERN, DATE_PRESETS, NO_VALUE_OPERATORS, NO_VALUE_PLACEHOLDER, OPERATORS_BY_TYPE, OPERATOR_LABELS, OPERATOR_LABELS_BY_TYPE, OPERATOR_SYMBOLS, QUERY_BAR_SELECTOR, VARIANT_LABELS, applyAcceptChar, applyFieldValueTransforms, applyKnownFieldHelpers, buildContainerAnchoredRect, chipIdToConditionIndex, createStatusCodeInputFilter, createStatusCodeNormalizer, createStatusCodeSerializer, createStatusCodeSuggestions, createStatusCodeValidator, filterAndSort, findChipSplitIndex, findOptionByValue, formatDateForChip, getCurrentValueTokenText, getDateDisplayLabel, getFieldOperators, getFieldValues, getKnownFieldSerializer, getOperatorFromLabel, getOperatorLabel, getValueFilterText, hasFieldValues, hasStaticAllowlist, isBetweenOperator, isBuildingComplete, isDatePreset, isFilterParseError, isMenuRelated, isMultiSelectOperator, isNoValueOperator, isOperatorAllowedForField, isValueShapeCompatible, nextBuildingMenu, parseExpression, serializeExpression };
16
+ import { findMatchingFieldValue, getInvalidValueIndices, isValidFieldValue, validateValueForField } from "./validation.js";
17
+ export { CONNECTOR_ID_PATTERN, DATE_PRESETS, MENU_BASE_GUTTER, MENU_CHIP_GUTTER_OFFSET, NO_VALUE_OPERATORS, NO_VALUE_PLACEHOLDER, OPERATORS_BY_TYPE, OPERATOR_LABELS, OPERATOR_LABELS_BY_TYPE, OPERATOR_SYMBOLS, QUERY_BAR_SELECTOR, SEGMENT_TO_MENU, VARIANT_LABELS, applyAcceptChar, applyFieldValueTransforms, applyKnownFieldHelpers, buildAnchoredRect, chipIdToConditionIndex, createStatusCodeInputFilter, createStatusCodeNormalizer, createStatusCodeSerializer, createStatusCodeSuggestions, createStatusCodeValidator, filterAndSort, findChipSplitIndex, findMatchingFieldValue, findOptionByValue, formatDateForChip, getCurrentValueTokenText, getDateDisplayLabel, getFieldOperators, getFieldValues, getInvalidValueIndices, getKnownFieldSerializer, getOperatorFromLabel, getOperatorLabel, getValueFilterText, hasFieldValues, hasStaticAllowlist, isBetweenOperator, isBuildingComplete, isDatePreset, isFilterParseError, isMenuRelated, isMultiSelectOperator, isNoValueOperator, isOperatorAllowedForField, isValidFieldValue, isValueShapeCompatible, nextBuildingMenu, parseExpression, serializeExpression, toAnchorBounds, validateValueForField };
@@ -1,24 +1,14 @@
1
+ import { type ChipSegment } from '../FilterInputField/FilterInputChip';
1
2
  import type { FieldValueOption, FilterOperator } from '../types';
2
3
  /**
3
- * Derive the "current value token" — the substring the user is actively typing.
4
- *
5
- * For multi-select operators (like `in` / `any of`), the field input may contain
6
- * a comma-separated list such as `"2XX, 3XX, 4"`. Only the last token (`"4"`)
7
- * represents the value currently being composed; prior tokens are already
8
- * committed as checked items. Callers use this to feed both `getSuggestions`
9
- * and the dropdown's filter/sort so the active token drives the menu.
10
- *
11
- * For single-value operators the raw input is returned unchanged.
4
+ * The substring the user is actively typing. For multi-select operators with
5
+ * comma-separated input ("2XX, 3XX, 4"), returns only the last token ("4").
6
+ * Single-value operators get the raw input.
12
7
  */
13
- export declare const getCurrentValueTokenText: (editingSegment: string | null, inputText: string, segmentMenuFilterText: string, selectedOperator: FilterOperator | null) => string;
8
+ export declare const getCurrentValueTokenText: (editingSegment: ChipSegment | null, inputText: string, segmentMenuFilterText: string, selectedOperator: FilterOperator | null) => string;
14
9
  /**
15
- * Derive the filter text for the value menu.
16
- *
17
- * For multi-select operators, uses the current value token (the one the user
18
- * is actively typing). If that token already matches a known value, returns
19
- * `''` so the dropdown shows all options — the user just finished a selection
20
- * and is about to start the next one.
21
- *
22
- * For single-value operators, returns the token as-is.
10
+ * Filter text for the value menu. Multi-select: returns the current token, or
11
+ * '' when it already matches a known value (just-completed selection).
12
+ * Single-value: returns token as-is.
23
13
  */
24
14
  export declare const getValueFilterText: (currentTokenText: string, selectedOperator: FilterOperator | null, fieldValues: FieldValueOption[]) => string;
@@ -1,18 +1,13 @@
1
1
  import type { FieldMetadata, FieldType, FilterOperator, MenuState } from '../types';
2
2
  /**
3
- * Filler text shown in the value slot of no-value operator chips so every
4
- * chip visually has three segments. Kept here next to `isNoValueOperator`
5
- * so committed (buildChips) and building-preview (deriveAutocompleteValues)
6
- * paths can never drift.
3
+ * Placeholder in no-value operator chips so every chip visually has 3
4
+ * segments. Co-located with isNoValueOperator so committed and
5
+ * building-preview paths can't drift.
7
6
  */
8
7
  export declare const NO_VALUE_PLACEHOLDER = "\u2014";
9
- /**
10
- * Helper to get operator label for specific field type
11
- */
8
+ /** Get operator label for a specific field type. */
12
9
  export declare const getOperatorLabel: (operator: FilterOperator, fieldType: FieldType) => string;
13
- /**
14
- * Reverse lookup: get raw FilterOperator from its display label and field type
15
- */
10
+ /** Reverse lookup: FilterOperator from display label and field type. */
16
11
  export declare const getOperatorFromLabel: (label: string, fieldType: FieldType) => FilterOperator | null;
17
12
  /** Check if operator supports multi-select */
18
13
  export declare const isMultiSelectOperator: (op: FilterOperator | null) => op is FilterOperator;
@@ -25,22 +20,17 @@ export declare const getFieldOperators: (field: FieldMetadata) => FilterOperator
25
20
  /** Check whether an operator is supported by a field's type/override list */
26
21
  export declare const isOperatorAllowedForField: (field: FieldMetadata, operator: FilterOperator) => boolean;
27
22
  /**
28
- * The menu that should open to continue building a chip from its current
29
- * state. Returns null when the chip is fully built and nothing should open.
30
- * Reused by the refocus path (useFocusManagement) and the main-input click
31
- * path (useInputHandlers) so both stay in sync.
23
+ * Next menu to open to continue building a chip; null when fully built.
24
+ * Shared by useFocusManagement (refocus) and useInputHandlers (click).
32
25
  */
33
26
  export declare const nextBuildingMenu: (field: FieldMetadata | null, operator: FilterOperator | null) => MenuState | null;
34
27
  /**
35
- * Decide whether the in-progress (field, operator, value) triple is fully
36
- * built i.e. has all the segments the chip needs. No-value operators
37
- * (is_null / is_not_null) are complete without a value: the chip renders a
38
- * value-placeholder in that slot so it still visually has three segments.
28
+ * True if the in-progress (field, operator, value) triple has all segments.
29
+ * No-value operators (is_null/is_not_null) are complete without a value.
39
30
  */
40
31
  export declare const isBuildingComplete: (field: FieldMetadata | null, operator: FilterOperator | null, value: string | number | boolean | Array<string | number | boolean> | null | undefined) => boolean;
41
32
  /**
42
- * Check whether two operators handle values in compatible shapes
43
- * (multi-select / between / no-value categories match), meaning a value
44
- * preview built for `a` can be reused as-is for `b`.
33
+ * True when two operators share value shape (multi-select/between/no-value
34
+ * categories match) a value preview built for `a` is reusable for `b`.
45
35
  */
46
36
  export declare const isValueShapeCompatible: (a: FilterOperator | null, b: FilterOperator | null) => boolean;
@@ -0,0 +1,4 @@
1
+ import { type SegmentVariant } from '../FilterInputField/FilterInputChip/segmentVariant';
2
+ import type { MenuState } from '../types';
3
+ /** Open-menu state for each chip segment (segment click, Backspace cascade). */
4
+ export declare const SEGMENT_TO_MENU: Record<SegmentVariant, MenuState>;
@@ -0,0 +1,7 @@
1
+ import { SEGMENT_VARIANT } from "../FilterInputField/FilterInputChip/segmentVariant.js";
2
+ const SEGMENT_TO_MENU = {
3
+ [SEGMENT_VARIANT.attribute]: 'field',
4
+ [SEGMENT_VARIANT.operator]: 'operator',
5
+ [SEGMENT_VARIANT.value]: 'value'
6
+ };
7
+ export { SEGMENT_TO_MENU };
@@ -1,16 +1,9 @@
1
1
  import type { ExprNode, FieldMetadata } from '../types';
2
2
  /**
3
- * Serialize an expression tree to a canonical text string.
4
- * Top-level conditions are sorted alphabetically by field name.
5
- *
6
- * **Pass `fields` when the output targets the backend.** Per-field
7
- * `serializeValue` hooks run first, so values like the status-code mask
8
- * `"2XX"` become `"2"` in the emitted string. Omitting `fields` keeps the
9
- * UI-facing values verbatim — useful for clipboard round-trip, debug
10
- * display, or any case where the output feeds `parseExpression` back. If
11
- * you forget `fields` on the path to the backend, the placeholder `X`s
12
- * ride through silently — name the backend call-site helper explicitly
13
- * (e.g. `const query = serializeExpression(expr, fields)`) to make the
14
- * intent obvious at callsite.
3
+ * Serialize an expression tree to canonical text. Top-level conditions sort
4
+ * by field name. Pass `fields` for backend output — per-field `serializeValue`
5
+ * runs first (e.g. `"2XX"` → `"2"`). Omitting `fields` keeps UI-facing values
6
+ * verbatim (clipboard round-trip, parseExpression input). Forgetting `fields`
7
+ * on the backend path silently emits placeholder Xs.
15
8
  */
16
9
  export declare const serializeExpression: (expr: ExprNode | null, fields?: FieldMetadata[]) => string;
@@ -0,0 +1,9 @@
1
+ import type { Condition, FieldMetadata, FieldValueOption } from '../types';
2
+ /** Find a field value option matching by label or value (case-insensitive) */
3
+ export declare const findMatchingFieldValue: (fieldValues: FieldValueOption[], text: string) => FieldValueOption | undefined;
4
+ /** Check if a single value matches any option in the field's values list */
5
+ export declare const isValidFieldValue: (fieldValues: FieldValueOption[], v: string | number | boolean) => boolean;
6
+ /** Return indices of values that don't match any field option. Empty array = all valid. */
7
+ export declare const getInvalidValueIndices: (field: FieldMetadata, values: Array<string | number | boolean>) => number[];
8
+ /** Check if condition value(s) are valid for the given field. Returns true if error. */
9
+ export declare const validateValueForField: (field: FieldMetadata, value: Condition["value"]) => boolean;
@@ -0,0 +1,24 @@
1
+ import { getFieldValues, hasStaticAllowlist } from "./fields.js";
2
+ const findMatchingFieldValue = (fieldValues, text)=>fieldValues.find((v)=>v.label.toLowerCase() === text.toLowerCase() || String(v.value).toLowerCase() === text.toLowerCase());
3
+ const isValidFieldValue = (fieldValues, v)=>fieldValues.some((opt)=>opt.value === v || String(opt.value).toLowerCase() === String(v).toLowerCase());
4
+ const getInvalidValueIndices = (field, values)=>{
5
+ if (field.validate) return values.reduce((acc, v, idx)=>{
6
+ if (field.validate(v)) acc.push(idx);
7
+ return acc;
8
+ }, []);
9
+ if (!hasStaticAllowlist(field)) return [];
10
+ const fv = getFieldValues(field);
11
+ if (0 === fv.length) return [];
12
+ return values.reduce((acc, v, idx)=>{
13
+ if (!isValidFieldValue(fv, v)) acc.push(idx);
14
+ return acc;
15
+ }, []);
16
+ };
17
+ const validateValueForField = (field, value)=>{
18
+ if (null == value) return false;
19
+ const values = Array.isArray(value) ? value : [
20
+ value
21
+ ];
22
+ return getInvalidValueIndices(field, values).length > 0;
23
+ };
24
+ export { findMatchingFieldValue, getInvalidValueIndices, isValidFieldValue, validateValueForField };