@wallarm-org/design-system 0.40.0-rc-feature-AS-982.2 → 0.40.0-rc-feature-AS-982.4

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 (62) hide show
  1. package/dist/components/FilterInput/FilterInputContext/types.d.ts +2 -2
  2. package/dist/components/FilterInput/FilterInputContext/useFilterInputContextValue.d.ts +2 -2
  3. package/dist/components/FilterInput/FilterInputErrors/parseFilterInputErrors.js +1 -2
  4. package/dist/components/FilterInput/FilterInputField/ChipsWithGaps.d.ts +1 -1
  5. package/dist/components/FilterInput/FilterInputField/ChipsWithGaps.js +1 -1
  6. package/dist/components/FilterInput/FilterInputField/FilterInputChip/FilterInputChip.d.ts +1 -1
  7. package/dist/components/FilterInput/FilterInputField/FilterInputChip/FilterInputChip.js +2 -2
  8. package/dist/components/FilterInput/FilterInputField/hooks/useSegmentEditKeyboard.d.ts +2 -1
  9. package/dist/components/FilterInput/FilterInputMenu/hooks/useKeyboardNav.js +5 -2
  10. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{deriveAutocompleteValues.d.ts → lib/deriveAutocompleteValues.d.ts} +2 -2
  11. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{deriveAutocompleteValues.js → lib/deriveAutocompleteValues.js} +1 -1
  12. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{getInitialSegmentText.d.ts → lib/getInitialSegmentText.d.ts} +2 -2
  13. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{getInitialSegmentText.js → lib/getInitialSegmentText.js} +2 -2
  14. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/lib/index.d.ts +3 -0
  15. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/lib/index.js +4 -0
  16. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{valueCommitHelpers.d.ts → lib/valueResolution.d.ts} +1 -7
  17. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{valueCommitHelpers.js → lib/valueResolution.js} +3 -25
  18. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useAutocompleteState.d.ts +41 -0
  19. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useAutocompleteState.js +51 -0
  20. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useChipActions.d.ts +2 -2
  21. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useChipActions.js +5 -5
  22. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useChipCascade.js +1 -1
  23. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useChipEditing.d.ts +3 -5
  24. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useChipEditing.js +4 -6
  25. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFilterInputAutocomplete.d.ts +7 -8
  26. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFilterInputAutocomplete.js +26 -82
  27. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFocusManagement.d.ts +2 -2
  28. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFocusManagement.js +41 -5
  29. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useInputHandlers.d.ts +2 -2
  30. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useInputHandlers.js +15 -6
  31. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/index.d.ts +1 -0
  32. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/index.js +2 -0
  33. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{useMenuFlow.d.ts → useMenuFlow/types.d.ts} +8 -17
  34. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/types.js +0 -0
  35. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useFieldFlow.d.ts +11 -0
  36. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useFieldFlow.js +90 -0
  37. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useMenuFlow.d.ts +20 -0
  38. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useMenuFlow.js +45 -0
  39. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useOperatorFlow.d.ts +11 -0
  40. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useOperatorFlow.js +82 -0
  41. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useValueFlow.d.ts +14 -0
  42. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useValueFlow.js +105 -0
  43. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuPositioning.d.ts +15 -7
  44. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuPositioning.js +17 -20
  45. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useResetState.d.ts +2 -2
  46. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useResetState.js +3 -3
  47. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useSegmentEditFlow.d.ts +35 -0
  48. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useSegmentEditFlow.js +67 -0
  49. package/dist/components/FilterInput/hooks/useFilterInputExpression/buildChips.js +1 -2
  50. package/dist/components/FilterInput/hooks/useFilterInputPositioning.d.ts +7 -4
  51. package/dist/components/FilterInput/hooks/useFilterInputPositioning.js +5 -5
  52. package/dist/components/FilterInput/hooks/useResizeTracker.d.ts +11 -0
  53. package/dist/components/FilterInput/hooks/useResizeTracker.js +21 -0
  54. package/dist/components/FilterInput/lib/dom.d.ts +13 -4
  55. package/dist/components/FilterInput/lib/dom.js +14 -9
  56. package/dist/components/FilterInput/lib/index.d.ts +2 -1
  57. package/dist/components/FilterInput/lib/index.js +3 -2
  58. package/dist/components/FilterInput/lib/validation.d.ts +9 -0
  59. package/dist/components/FilterInput/lib/validation.js +24 -0
  60. package/dist/metadata/components.json +1 -1
  61. package/package.json +1 -1
  62. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow.js +0 -275
@@ -22,10 +22,10 @@ export interface FilterInputContextValue {
22
22
  onInputKeyDown: (e: KeyboardEvent<HTMLInputElement>) => void;
23
23
  onInputClick: () => void;
24
24
  onGapClick: (conditionIndex: number, afterConnector: boolean) => void;
25
- onChipClick: (chipId: string, segment: ChipSegment, anchorRect: DOMRect) => void;
25
+ onChipClick: (chipId: string, segment: ChipSegment, anchorEl: HTMLElement) => void;
26
26
  /** Click on a segment of the *building* (in-progress) chip — re-opens the
27
27
  * corresponding menu and enters inline-edit without committing the chip. */
28
- onBuildingChipClick: (segment: ChipSegment, anchorRect: DOMRect) => void;
28
+ onBuildingChipClick: (segment: ChipSegment, anchorEl: HTMLElement) => void;
29
29
  /** Switch the inline-edit to a different segment within the chip currently
30
30
  * being edited — used by Backspace-on-empty to walk back through segments. */
31
31
  onSwitchEditSegment: (targetSegment: ChipSegment) => boolean;
@@ -9,8 +9,8 @@ interface AutocompleteForContext {
9
9
  handleInputChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
10
10
  handleKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void;
11
11
  handleInputClick: () => void;
12
- handleChipClick: (chipId: string, segment: ChipSegment, anchorRect: DOMRect) => void;
13
- handleBuildingChipClick: (segment: ChipSegment, anchorRect: DOMRect) => void;
12
+ handleChipClick: (chipId: string, segment: ChipSegment, anchorEl: HTMLElement) => void;
13
+ handleBuildingChipClick: (segment: ChipSegment, anchorEl: HTMLElement) => void;
14
14
  switchEditSegment: (targetSegment: ChipSegment) => boolean;
15
15
  removeEditingChip: () => void;
16
16
  handleConnectorChange: (chipId: string, value: 'and' | 'or') => void;
@@ -1,6 +1,5 @@
1
1
  import { SEGMENT_VARIANT } from "../FilterInputField/FilterInputChip/index.js";
2
- import { isValidFieldValue } from "../hooks/useFilterInputAutocomplete/valueCommitHelpers.js";
3
- import { getFieldValues, hasStaticAllowlist } from "../lib/index.js";
2
+ import { getFieldValues, hasStaticAllowlist, isValidFieldValue } from "../lib/index.js";
4
3
  const parseFilterInputErrors = (conditions, fields)=>{
5
4
  const errors = [];
6
5
  for (const condition of conditions){
@@ -5,7 +5,7 @@ interface ChipsWithGapsProps {
5
5
  chips: FilterInputChipData[];
6
6
  hideLeadingGap?: boolean;
7
7
  hideTrailingGap?: boolean;
8
- onChipClick: (chipId: string, segment: ChipSegment, anchorRect: DOMRect) => void;
8
+ onChipClick: (chipId: string, segment: ChipSegment, anchorEl: HTMLElement) => void;
9
9
  onConnectorChange: (chipId: string, value: 'and' | 'or') => void;
10
10
  onChipRemove: (chipId: string) => void;
11
11
  onGapClick: (conditionIndex: number, afterConnector: boolean) => void;
@@ -30,7 +30,7 @@ const ChipsWithGaps = ({ chips, hideLeadingGap, hideTrailingGap, onChipClick, on
30
30
  errorValueIndices: chip.errorValueIndices,
31
31
  disabled: chip.disabled,
32
32
  onRemove: chip.disabled ? void 0 : ()=>onChipRemove(chip.id),
33
- onSegmentClick: chip.disabled ? void 0 : (segment, anchorRect)=>onChipClick(chip.id, segment, anchorRect)
33
+ onSegmentClick: chip.disabled ? void 0 : (segment, anchorEl)=>onChipClick(chip.id, segment, anchorEl)
34
34
  })
35
35
  }, chip.id));
36
36
  else if (isConnector) {
@@ -16,6 +16,6 @@ export interface FilterInputChipProps extends Omit<HTMLAttributes<HTMLDivElement
16
16
  /** When true, the chip cannot be edited or removed (dimmed appearance) */
17
17
  disabled?: boolean;
18
18
  onRemove?: () => void;
19
- onSegmentClick?: (segment: ChipSegment, anchorRect: DOMRect) => void;
19
+ onSegmentClick?: (segment: ChipSegment, anchorEl: HTMLElement) => void;
20
20
  }
21
21
  export declare const FilterInputChip: FC<FilterInputChipProps>;
@@ -18,9 +18,9 @@ const FilterInputChip = ({ ref, chipId, attribute, operator, value, error = fals
18
18
  if (!onSegmentClick) return;
19
19
  if (activeSegment === segment) return;
20
20
  e.stopPropagation();
21
- const anchorEl = segment === SEGMENT_VARIANT.attribute ? internalRef.current : e.currentTarget;
21
+ const anchorEl = internalRef.current;
22
22
  if (!anchorEl) return;
23
- onSegmentClick(segment, anchorEl.getBoundingClientRect());
23
+ onSegmentClick(segment, anchorEl);
24
24
  }, [
25
25
  onSegmentClick,
26
26
  activeSegment
@@ -24,7 +24,8 @@ interface UseSegmentEditKeyboardOptions {
24
24
  * attribute) and, if the attribute is empty with no operator/value left,
25
25
  * removes the chip.
26
26
  * - Enter commits the typed text via the segment-specific commit callback.
27
- * - ArrowDown moves focus into the open menu.
27
+ * - ArrowDown is intercepted (preventDefault) but focus stays on the input
28
+ * highlight navigation runs through useKeyboardNav's window-capture listener.
28
29
  *
29
30
  * Returns the keydown + blur handlers fed to `EditingProvider` so every
30
31
  * segment input dispatches through the same logic.
@@ -141,7 +141,11 @@ const useKeyboardNav = ({ items, open, onSelect, onClose, onArrowRight, onPendin
141
141
  return;
142
142
  }
143
143
  const isSegmentInput = e.target?.closest?.('[data-slot^="segment-"]');
144
- if (isSegmentInput && 'Escape' !== e.key && 'ArrowDown' !== e.key && 'ArrowUp' !== e.key) return;
144
+ if (isSegmentInput) {
145
+ const isEnterWithHighlight = 'Enter' === e.key && activeIndexRef.current >= 0;
146
+ const isNavOrClose = 'Escape' === e.key || 'ArrowDown' === e.key || 'ArrowUp' === e.key;
147
+ if (!isNavOrClose && !isEnterWithHighlight) return;
148
+ }
145
149
  const { items: list, onSelect: select, onClose: close, onArrowRight: arrowRight } = stateRef.current;
146
150
  if (0 === list.length) return;
147
151
  switch(e.key){
@@ -154,7 +158,6 @@ const useKeyboardNav = ({ items, open, onSelect, onClose, onArrowRight, onPendin
154
158
  e.preventDefault();
155
159
  e.stopPropagation();
156
160
  navigate('ArrowDown' === e.key ? 1 : -1);
157
- stateRef.current.menuRef?.current?.focus();
158
161
  break;
159
162
  case 'Enter':
160
163
  {
@@ -1,5 +1,5 @@
1
- import type { BuildingChipData } from '../../FilterInputContext/types';
2
- import type { Condition, FieldMetadata, FilterOperator } from '../../types';
1
+ import type { BuildingChipData } from '../../../FilterInputContext/types';
2
+ import type { Condition, FieldMetadata, FilterOperator } from '../../../types';
3
3
  interface DeriveOptions {
4
4
  editingChipId: string | null;
5
5
  selectedField: FieldMetadata | null;
@@ -1,4 +1,4 @@
1
- import { NO_VALUE_PLACEHOLDER, chipIdToConditionIndex, getDateDisplayLabel, getFieldValues, getOperatorLabel, hasStaticAllowlist, isMultiSelectOperator, isNoValueOperator } from "../../lib/index.js";
1
+ import { NO_VALUE_PLACEHOLDER, chipIdToConditionIndex, getDateDisplayLabel, getFieldValues, getOperatorLabel, hasStaticAllowlist, isMultiSelectOperator, isNoValueOperator } from "../../../lib/index.js";
2
2
  const getEditingCondition = (editingChipId, conditions)=>{
3
3
  if (!editingChipId) return null;
4
4
  const idx = chipIdToConditionIndex(editingChipId);
@@ -1,5 +1,5 @@
1
- import { type ChipSegment } from '../../FilterInputField/FilterInputChip';
2
- import type { FieldMetadata, FilterOperator } from '../../types';
1
+ import { type ChipSegment } from '../../../FilterInputField/FilterInputChip';
2
+ import type { FieldMetadata, FilterOperator } from '../../../types';
3
3
  /**
4
4
  * Initial text shown in a building chip's inline-edit input for the given
5
5
  * segment. Mirrors what the chip is currently displaying so the user can
@@ -1,5 +1,5 @@
1
- import { SEGMENT_VARIANT } from "../../FilterInputField/FilterInputChip/index.js";
2
- import { getOperatorLabel } from "../../lib/index.js";
1
+ import { SEGMENT_VARIANT } from "../../../FilterInputField/FilterInputChip/index.js";
2
+ import { getOperatorLabel } from "../../../lib/index.js";
3
3
  const getInitialSegmentText = (segment, selectedField, selectedOperator, buildingMultiValue)=>{
4
4
  if (segment === SEGMENT_VARIANT.attribute) return selectedField.label;
5
5
  if (segment === SEGMENT_VARIANT.operator) return selectedOperator ? getOperatorLabel(selectedOperator, selectedField.type) : '';
@@ -0,0 +1,3 @@
1
+ export { deriveAutocompleteValues } from './deriveAutocompleteValues';
2
+ export { getInitialSegmentText } from './getInitialSegmentText';
3
+ export { displayDateToIso, resolveDateRangeValue, resolveDateValue, resolveFieldValue, resolveMultiValues, resolveSingleValue, } from './valueResolution';
@@ -0,0 +1,4 @@
1
+ import { deriveAutocompleteValues } from "./deriveAutocompleteValues.js";
2
+ import { getInitialSegmentText } from "./getInitialSegmentText.js";
3
+ import { displayDateToIso, resolveDateRangeValue, resolveDateValue, resolveFieldValue, resolveMultiValues, resolveSingleValue } from "./valueResolution.js";
4
+ export { deriveAutocompleteValues, displayDateToIso, getInitialSegmentText, resolveDateRangeValue, resolveDateValue, resolveFieldValue, resolveMultiValues, resolveSingleValue };
@@ -1,10 +1,4 @@
1
- import type { Condition, FieldMetadata, FieldValueOption } from '../../types';
2
- /** Check if a single value matches any option in the field's values list */
3
- export declare const isValidFieldValue: (fieldValues: FieldValueOption[], v: string | number | boolean) => boolean;
4
- /** Return indices of values that don't match any field option. Empty array = all valid. */
5
- export declare const getInvalidValueIndices: (field: FieldMetadata, values: Array<string | number | boolean>) => number[];
6
- /** Check if condition value(s) are valid for the given field. Returns true if error. */
7
- export declare const validateValueForField: (field: FieldMetadata, value: Condition["value"]) => boolean;
1
+ import type { Condition, FieldMetadata } from '../../../types';
8
2
  /** Resolve a text input to the actual field value (e.g. label "Active" → value "active") */
9
3
  export declare const resolveFieldValue: (field: FieldMetadata, text: string) => string | number | boolean;
10
4
  /** Resolve and validate a single-select value from text */
@@ -1,27 +1,5 @@
1
- import { MIN_DATE_STRING_LENGTH } from "../../FilterInputMenu/FilterInputDateValueMenu/constants.js";
2
- import { chipIdToConditionIndex, getFieldValues, hasStaticAllowlist, isDatePreset } from "../../lib/index.js";
3
- const findMatchingFieldValue = (fieldValues, text)=>fieldValues.find((v)=>v.label.toLowerCase() === text.toLowerCase() || String(v.value).toLowerCase() === text.toLowerCase());
4
- const isValidFieldValue = (fieldValues, v)=>fieldValues.some((opt)=>opt.value === v || String(opt.value).toLowerCase() === String(v).toLowerCase());
5
- const getInvalidValueIndices = (field, values)=>{
6
- if (field.validate) return values.reduce((acc, v, idx)=>{
7
- if (field.validate(v)) acc.push(idx);
8
- return acc;
9
- }, []);
10
- if (!hasStaticAllowlist(field)) return [];
11
- const fv = getFieldValues(field);
12
- if (0 === fv.length) return [];
13
- return values.reduce((acc, v, idx)=>{
14
- if (!isValidFieldValue(fv, v)) acc.push(idx);
15
- return acc;
16
- }, []);
17
- };
18
- const validateValueForField = (field, value)=>{
19
- if (null == value) return false;
20
- const values = Array.isArray(value) ? value : [
21
- value
22
- ];
23
- return getInvalidValueIndices(field, values).length > 0;
24
- };
1
+ import { MIN_DATE_STRING_LENGTH } from "../../../FilterInputMenu/FilterInputDateValueMenu/constants.js";
2
+ import { chipIdToConditionIndex, findMatchingFieldValue, getFieldValues, getInvalidValueIndices, hasStaticAllowlist, isDatePreset } from "../../../lib/index.js";
25
3
  const resolveFieldValue = (field, text)=>{
26
4
  const match = findMatchingFieldValue(getFieldValues(field), text);
27
5
  return match ? match.value : text;
@@ -90,4 +68,4 @@ const resolveDateValue = (trimmed, editingChipId, conditions)=>{
90
68
  dateOrigin
91
69
  };
92
70
  };
93
- export { displayDateToIso, getInvalidValueIndices, isValidFieldValue, resolveDateRangeValue, resolveDateValue, resolveFieldValue, resolveMultiValues, resolveSingleValue, validateValueForField };
71
+ export { displayDateToIso, resolveDateRangeValue, resolveDateValue, resolveFieldValue, resolveMultiValues, resolveSingleValue };
@@ -0,0 +1,41 @@
1
+ import type { Condition, FieldMetadata, FilterOperator, MenuState } from '../../types';
2
+ interface UseAutocompleteStateOptions {
3
+ conditions: Condition[];
4
+ }
5
+ /**
6
+ * Owns the entire useState / useRef surface of the autocomplete hook. Splitting
7
+ * this out of the orchestrator keeps `useFilterInputAutocomplete` focused on
8
+ * wiring sub-hooks together rather than reading 30 lines of declarations.
9
+ *
10
+ * Each ref intentionally mirrors a piece of state — sub-hooks read the ref
11
+ * synchronously to avoid re-creating callbacks on every keystroke that mutates
12
+ * conditions / insertIndex / etc.
13
+ */
14
+ export declare const useAutocompleteState: ({ conditions }: UseAutocompleteStateOptions) => {
15
+ inputText: string;
16
+ setInputText: import("react").Dispatch<import("react").SetStateAction<string>>;
17
+ menuState: MenuState;
18
+ setMenuState: import("react").Dispatch<import("react").SetStateAction<MenuState>>;
19
+ selectedField: FieldMetadata | null;
20
+ setSelectedField: import("react").Dispatch<import("react").SetStateAction<FieldMetadata | null>>;
21
+ selectedOperator: FilterOperator | null;
22
+ setSelectedOperator: import("react").Dispatch<import("react").SetStateAction<FilterOperator | null>>;
23
+ isFocused: boolean;
24
+ setIsFocused: import("react").Dispatch<import("react").SetStateAction<boolean>>;
25
+ buildingMultiValue: string | undefined;
26
+ setBuildingMultiValue: import("react").Dispatch<import("react").SetStateAction<string | undefined>>;
27
+ insertIndex: number | null;
28
+ setInsertIndex: import("react").Dispatch<import("react").SetStateAction<number | null>>;
29
+ insertAfterConnector: boolean;
30
+ setInsertAfterConnector: import("react").Dispatch<import("react").SetStateAction<boolean>>;
31
+ effectiveInsertIndex: number;
32
+ effectiveInsertIndexRef: import("react").RefObject<number>;
33
+ conditionsRef: import("react").RefObject<Condition[]>;
34
+ conditionsLengthRef: import("react").RefObject<number>;
35
+ blurCommitRef: import("react").RefObject<(() => boolean) | null>;
36
+ segmentAttributeInputRef: import("react").RefObject<HTMLInputElement | null>;
37
+ segmentOperatorInputRef: import("react").RefObject<HTMLInputElement | null>;
38
+ segmentValueInputRef: import("react").RefObject<HTMLInputElement | null>;
39
+ commitBuildingOnBlurRef: import("react").RefObject<() => boolean>;
40
+ };
41
+ export {};
@@ -0,0 +1,51 @@
1
+ import { useRef, useState } from "react";
2
+ const useAutocompleteState = ({ conditions })=>{
3
+ const [inputText, setInputText] = useState('');
4
+ const [menuState, setMenuState] = useState('closed');
5
+ const [selectedField, setSelectedField] = useState(null);
6
+ const [selectedOperator, setSelectedOperator] = useState(null);
7
+ const [isFocused, setIsFocused] = useState(false);
8
+ const [buildingMultiValue, setBuildingMultiValue] = useState(void 0);
9
+ const [insertIndex, setInsertIndex] = useState(null);
10
+ const [insertAfterConnector, setInsertAfterConnector] = useState(false);
11
+ const effectiveInsertIndex = insertIndex ?? conditions.length;
12
+ const effectiveInsertIndexRef = useRef(effectiveInsertIndex);
13
+ effectiveInsertIndexRef.current = effectiveInsertIndex;
14
+ const conditionsRef = useRef(conditions);
15
+ conditionsRef.current = conditions;
16
+ const conditionsLengthRef = useRef(conditions.length);
17
+ conditionsLengthRef.current = conditions.length;
18
+ const blurCommitRef = useRef(null);
19
+ const segmentAttributeInputRef = useRef(null);
20
+ const segmentOperatorInputRef = useRef(null);
21
+ const segmentValueInputRef = useRef(null);
22
+ const commitBuildingOnBlurRef = useRef(()=>false);
23
+ return {
24
+ inputText,
25
+ setInputText,
26
+ menuState,
27
+ setMenuState,
28
+ selectedField,
29
+ setSelectedField,
30
+ selectedOperator,
31
+ setSelectedOperator,
32
+ isFocused,
33
+ setIsFocused,
34
+ buildingMultiValue,
35
+ setBuildingMultiValue,
36
+ insertIndex,
37
+ setInsertIndex,
38
+ insertAfterConnector,
39
+ setInsertAfterConnector,
40
+ effectiveInsertIndex,
41
+ effectiveInsertIndexRef,
42
+ conditionsRef,
43
+ conditionsLengthRef,
44
+ blurCommitRef,
45
+ segmentAttributeInputRef,
46
+ segmentOperatorInputRef,
47
+ segmentValueInputRef,
48
+ commitBuildingOnBlurRef
49
+ };
50
+ };
51
+ export { useAutocompleteState };
@@ -5,7 +5,7 @@ interface UseChipActionsDeps {
5
5
  inputRef: RefObject<HTMLInputElement | null>;
6
6
  removeCondition: (chipId: string) => void;
7
7
  clearAll: () => void;
8
- resetMenuOffset: () => void;
8
+ resetMenuAnchor: () => void;
9
9
  resetState: () => void;
10
10
  setInsertIndex: Dispatch<SetStateAction<number | null>>;
11
11
  setInsertAfterConnector: Dispatch<SetStateAction<boolean>>;
@@ -18,7 +18,7 @@ interface UseChipActionsDeps {
18
18
  * - clicking a gap between chips to insert a new condition there
19
19
  * - closing the menu (used by external consumers like the connector chip)
20
20
  */
21
- export declare const useChipActions: ({ effectiveInsertIndexRef, inputRef, removeCondition, clearAll, resetMenuOffset, resetState, setInsertIndex, setInsertAfterConnector, setMenuState, }: UseChipActionsDeps) => {
21
+ export declare const useChipActions: ({ effectiveInsertIndexRef, inputRef, removeCondition, clearAll, resetMenuAnchor, resetState, setInsertIndex, setInsertAfterConnector, setMenuState, }: UseChipActionsDeps) => {
22
22
  handleChipRemove: (chipId: string) => void;
23
23
  handleClear: () => void;
24
24
  handleGapClick: (conditionIndex: number, afterConnector: boolean) => void;
@@ -1,17 +1,17 @@
1
1
  import { useCallback } from "react";
2
2
  import { flushSync } from "react-dom";
3
3
  import { chipIdToConditionIndex } from "../../lib/index.js";
4
- const useChipActions = ({ effectiveInsertIndexRef, inputRef, removeCondition, clearAll, resetMenuOffset, resetState, setInsertIndex, setInsertAfterConnector, setMenuState })=>{
4
+ const useChipActions = ({ effectiveInsertIndexRef, inputRef, removeCondition, clearAll, resetMenuAnchor, resetState, setInsertIndex, setInsertAfterConnector, setMenuState })=>{
5
5
  const handleChipRemove = useCallback((chipId)=>{
6
6
  const chipCondIdx = chipIdToConditionIndex(chipId);
7
7
  if (null !== chipCondIdx && chipCondIdx < effectiveInsertIndexRef.current) setInsertIndex((prev)=>null != prev ? prev - 1 : prev);
8
8
  removeCondition(chipId);
9
- resetMenuOffset();
9
+ resetMenuAnchor();
10
10
  setMenuState('closed');
11
11
  inputRef.current?.focus();
12
12
  }, [
13
13
  removeCondition,
14
- resetMenuOffset,
14
+ resetMenuAnchor,
15
15
  inputRef,
16
16
  effectiveInsertIndexRef,
17
17
  setInsertIndex,
@@ -29,14 +29,14 @@ const useChipActions = ({ effectiveInsertIndexRef, inputRef, removeCondition, cl
29
29
  flushSync(()=>{
30
30
  setInsertIndex(conditionIndex);
31
31
  setInsertAfterConnector(afterConnector);
32
- resetMenuOffset();
32
+ resetMenuAnchor();
33
33
  setMenuState('closed');
34
34
  });
35
35
  setMenuState('field');
36
36
  inputRef.current?.focus();
37
37
  }, [
38
38
  resetState,
39
- resetMenuOffset,
39
+ resetMenuAnchor,
40
40
  inputRef,
41
41
  setInsertIndex,
42
42
  setInsertAfterConnector,
@@ -1,7 +1,7 @@
1
1
  import { useCallback } from "react";
2
2
  import { SEGMENT_VARIANT } from "../../FilterInputField/FilterInputChip/index.js";
3
3
  import { SEGMENT_TO_MENU, chipIdToConditionIndex } from "../../lib/index.js";
4
- import { getInitialSegmentText } from "./getInitialSegmentText.js";
4
+ import { getInitialSegmentText } from "./lib/index.js";
5
5
  const useChipCascade = ({ editing, chips, fields, conditionsRef, effectiveInsertIndexRef, selectedField, selectedOperator, buildingMultiValue, upsertCondition, removeCondition, resetState, setInputText, setMenuState, setSelectedOperator, setBuildingMultiValue, setInsertIndex })=>{
6
6
  const switchEditSegment = useCallback((targetSegment)=>{
7
7
  const sourceSegment = editing.editingSegment;
@@ -1,12 +1,10 @@
1
- import type { RefObject } from 'react';
2
1
  import { type ChipSegment } from '../../FilterInputField/FilterInputChip';
3
2
  import type { Condition, FieldMetadata, FilterInputChipData, FilterOperator, MenuState, UpsertCondition } from '../../types';
4
3
  interface UseChipEditingOptions {
5
4
  conditions: Condition[];
6
5
  chips: FilterInputChipData[];
7
6
  fields: FieldMetadata[];
8
- containerRef: RefObject<HTMLElement | null>;
9
- setMenuOffset: (offset: number) => void;
7
+ setMenuAnchor: (el: HTMLElement | null) => void;
10
8
  setSelectedField: (field: FieldMetadata | null) => void;
11
9
  setSelectedOperator: (op: FilterOperator | null) => void;
12
10
  setMenuState: (state: MenuState) => void;
@@ -17,7 +15,7 @@ interface UseChipEditingOptions {
17
15
  * Handles chip click → open appropriate menu based on segment,
18
16
  * then advances through the full flow (field → operator → value).
19
17
  */
20
- export declare const useChipEditing: ({ conditions, chips, fields, containerRef, setMenuOffset, setSelectedField, setSelectedOperator, setMenuState, upsertCondition, }: UseChipEditingOptions) => {
18
+ export declare const useChipEditing: ({ conditions, chips, fields, setMenuAnchor, setSelectedField, setSelectedOperator, setMenuState, upsertCondition, }: UseChipEditingOptions) => {
21
19
  editingChipId: string | null;
22
20
  editingSegment: import("../../FilterInputField/FilterInputChip").SegmentVariant | null;
23
21
  setEditingSegment: import("react").Dispatch<import("react").SetStateAction<import("../../FilterInputField/FilterInputChip").SegmentVariant | null>>;
@@ -25,7 +23,7 @@ export declare const useChipEditing: ({ conditions, chips, fields, containerRef,
25
23
  segmentMenuFilterText: string;
26
24
  setSegmentFilterText: (text: string) => void;
27
25
  resetSegmentTyping: () => void;
28
- handleChipClick: (chipId: string, segment: ChipSegment, anchorRect: DOMRect) => void;
26
+ handleChipClick: (chipId: string, segment: ChipSegment, anchorEl: HTMLElement) => void;
29
27
  startBuildingEdit: (segment: ChipSegment, currentText: string) => void;
30
28
  switchEditSegment: (segment: ChipSegment, currentText: string) => void;
31
29
  clearEditing: () => void;
@@ -12,7 +12,7 @@ const getFirstIncompleteSegment = (condition, fields)=>{
12
12
  if (null === condition.value || '' === condition.value || condition.error === SEGMENT_VARIANT.value) return SEGMENT_VARIANT.value;
13
13
  return null;
14
14
  };
15
- const useChipEditing = ({ conditions, chips, fields, containerRef, setMenuOffset, setSelectedField, setSelectedOperator, setMenuState, upsertCondition })=>{
15
+ const useChipEditing = ({ conditions, chips, fields, setMenuAnchor, setSelectedField, setSelectedOperator, setMenuState, upsertCondition })=>{
16
16
  const [editingChipId, setEditingChipId] = useState(null);
17
17
  const [editingSegment, setEditingSegment] = useState(null);
18
18
  const [segmentFilterText, setSegmentFilterText] = useState('');
@@ -23,7 +23,7 @@ const useChipEditing = ({ conditions, chips, fields, containerRef, setMenuOffset
23
23
  chipsRef.current = chips;
24
24
  const fieldsRef = useRef(fields);
25
25
  fieldsRef.current = fields;
26
- const handleChipClick = useCallback((chipId, segment, anchorRect)=>{
26
+ const handleChipClick = useCallback((chipId, segment, anchorEl)=>{
27
27
  const condition = getConditionByChipId(chipId, conditionsRef.current);
28
28
  if (!condition) return;
29
29
  const field = fieldsRef.current.find((f)=>f.name === condition.field);
@@ -34,8 +34,7 @@ const useChipEditing = ({ conditions, chips, fields, containerRef, setMenuOffset
34
34
  const targetSegment = incompleteSegment ?? (isPlaceholderValueClick ? SEGMENT_VARIANT.operator : segment);
35
35
  if (!field && targetSegment !== SEGMENT_VARIANT.attribute) return;
36
36
  if (incompleteSegment && field) upsertCondition(field, condition.operator, condition.value, chipId);
37
- const containerRect = containerRef.current?.getBoundingClientRect();
38
- setMenuOffset(containerRect ? anchorRect.left - containerRect.left : 0);
37
+ setMenuAnchor(anchorEl);
39
38
  setEditingChipId(chipId);
40
39
  setSelectedField(field ?? null);
41
40
  const rawOperator = targetSegment === SEGMENT_VARIANT.value || targetSegment === SEGMENT_VARIANT.operator ? getOperatorFromLabel(chip.operator || '', field?.type ?? 'string') ?? condition.operator : null;
@@ -50,8 +49,7 @@ const useChipEditing = ({ conditions, chips, fields, containerRef, setMenuOffset
50
49
  setUserHasTyped(false);
51
50
  setMenuState(SEGMENT_TO_MENU[targetSegment]);
52
51
  }, [
53
- containerRef,
54
- setMenuOffset,
52
+ setMenuAnchor,
55
53
  setSelectedField,
56
54
  setSelectedOperator,
57
55
  setMenuState,
@@ -1,6 +1,5 @@
1
1
  import type { RefObject } from 'react';
2
- import { type ChipSegment } from '../../FilterInputField/FilterInputChip';
3
- import type { Condition, FieldMetadata, FilterInputChipData, FilterOperator, MenuState, UpsertCondition } from '../../types';
2
+ import type { Condition, FieldMetadata, FilterInputChipData, UpsertCondition } from '../../types';
4
3
  interface UseFilterInputAutocompleteOptions {
5
4
  fields: FieldMetadata[];
6
5
  conditions: Condition[];
@@ -16,9 +15,9 @@ interface UseFilterInputAutocompleteOptions {
16
15
  }
17
16
  export declare const useFilterInputAutocomplete: ({ fields, conditions, chips, upsertCondition, removeCondition, removeConditionAtIndex, clearAll, setConnectorValue, containerRef, buildingChipRef, inputRef, }: UseFilterInputAutocompleteOptions) => {
18
17
  inputText: string;
19
- menuState: MenuState;
18
+ menuState: import("../../types").MenuState;
20
19
  selectedField: FieldMetadata | null;
21
- selectedOperator: FilterOperator | null;
20
+ selectedOperator: import("../..").FilterOperator | null;
22
21
  isBuilding: boolean;
23
22
  buildingChipData: import("../../FilterInputContext").BuildingChipData | null;
24
23
  menuPositioning: {
@@ -41,7 +40,7 @@ export declare const useFilterInputAutocomplete: ({ fields, conditions, chips, u
41
40
  inputRef: RefObject<HTMLInputElement | null>;
42
41
  handleInputChange: (e: import("react").ChangeEvent<HTMLInputElement>) => void;
43
42
  handleFieldSelect: (field: FieldMetadata) => void;
44
- handleOperatorSelect: (operator: FilterOperator) => void;
43
+ handleOperatorSelect: (operator: import("../..").FilterOperator) => void;
45
44
  handleValueSelect: (val: string | number | boolean) => void;
46
45
  handleMultiCommit: (values: Array<string | number | boolean>) => void;
47
46
  handleBuildingValueChange: (preview: string | undefined) => void;
@@ -52,9 +51,9 @@ export declare const useFilterInputAutocomplete: ({ fields, conditions, chips, u
52
51
  * the conditions array is replaced and any in-progress building must be
53
52
  * scrapped, regardless of inline-edit mode. */
54
53
  resetAutocompleteState: (continueBuilding?: boolean) => void;
55
- handleChipClick: (chipId: string, segment: ChipSegment, anchorRect: DOMRect) => void;
56
- handleBuildingChipClick: (segment: ChipSegment, anchorRect: DOMRect) => void;
57
- switchEditSegment: (targetSegment: ChipSegment) => boolean;
54
+ handleChipClick: (chipId: string, segment: import("../../FilterInputField").ChipSegment, anchorEl: HTMLElement) => void;
55
+ handleBuildingChipClick: (segment: import("../../FilterInputField").ChipSegment, anchorEl: HTMLElement) => void;
56
+ switchEditSegment: (targetSegment: import("../../FilterInputField").ChipSegment) => boolean;
58
57
  removeEditingChip: () => void;
59
58
  handleConnectorChange: (connectorId: string, value: "and" | "or") => void;
60
59
  handleChipRemove: (chipId: string) => void;