@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.
- package/dist/components/FilterInput/FilterInputContext/types.d.ts +2 -2
- package/dist/components/FilterInput/FilterInputContext/useFilterInputContextValue.d.ts +2 -2
- package/dist/components/FilterInput/FilterInputErrors/parseFilterInputErrors.js +1 -2
- package/dist/components/FilterInput/FilterInputField/ChipsWithGaps.d.ts +1 -1
- package/dist/components/FilterInput/FilterInputField/ChipsWithGaps.js +1 -1
- package/dist/components/FilterInput/FilterInputField/FilterInputChip/FilterInputChip.d.ts +1 -1
- package/dist/components/FilterInput/FilterInputField/FilterInputChip/FilterInputChip.js +2 -2
- package/dist/components/FilterInput/FilterInputField/hooks/useSegmentEditKeyboard.d.ts +2 -1
- package/dist/components/FilterInput/FilterInputMenu/hooks/useKeyboardNav.js +5 -2
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{deriveAutocompleteValues.d.ts → lib/deriveAutocompleteValues.d.ts} +2 -2
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{deriveAutocompleteValues.js → lib/deriveAutocompleteValues.js} +1 -1
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{getInitialSegmentText.d.ts → lib/getInitialSegmentText.d.ts} +2 -2
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{getInitialSegmentText.js → lib/getInitialSegmentText.js} +2 -2
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/lib/index.d.ts +3 -0
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/lib/index.js +4 -0
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{valueCommitHelpers.d.ts → lib/valueResolution.d.ts} +1 -7
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{valueCommitHelpers.js → lib/valueResolution.js} +3 -25
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useAutocompleteState.d.ts +41 -0
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useAutocompleteState.js +51 -0
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useChipActions.d.ts +2 -2
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useChipActions.js +5 -5
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useChipCascade.js +1 -1
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useChipEditing.d.ts +3 -5
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useChipEditing.js +4 -6
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFilterInputAutocomplete.d.ts +7 -8
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFilterInputAutocomplete.js +26 -82
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFocusManagement.d.ts +2 -2
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFocusManagement.js +41 -5
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useInputHandlers.d.ts +2 -2
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useInputHandlers.js +15 -6
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/index.d.ts +1 -0
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/index.js +2 -0
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{useMenuFlow.d.ts → useMenuFlow/types.d.ts} +8 -17
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/types.js +0 -0
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useFieldFlow.d.ts +11 -0
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useFieldFlow.js +90 -0
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useMenuFlow.d.ts +20 -0
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useMenuFlow.js +45 -0
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useOperatorFlow.d.ts +11 -0
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useOperatorFlow.js +82 -0
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useValueFlow.d.ts +14 -0
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useValueFlow.js +105 -0
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuPositioning.d.ts +15 -7
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuPositioning.js +17 -20
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useResetState.d.ts +2 -2
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useResetState.js +3 -3
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useSegmentEditFlow.d.ts +35 -0
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useSegmentEditFlow.js +67 -0
- package/dist/components/FilterInput/hooks/useFilterInputExpression/buildChips.js +1 -2
- package/dist/components/FilterInput/hooks/useFilterInputPositioning.d.ts +7 -4
- package/dist/components/FilterInput/hooks/useFilterInputPositioning.js +5 -5
- package/dist/components/FilterInput/hooks/useResizeTracker.d.ts +11 -0
- package/dist/components/FilterInput/hooks/useResizeTracker.js +21 -0
- package/dist/components/FilterInput/lib/dom.d.ts +13 -4
- package/dist/components/FilterInput/lib/dom.js +14 -9
- package/dist/components/FilterInput/lib/index.d.ts +2 -1
- package/dist/components/FilterInput/lib/index.js +3 -2
- package/dist/components/FilterInput/lib/validation.d.ts +9 -0
- package/dist/components/FilterInput/lib/validation.js +24 -0
- package/dist/metadata/components.json +1 -1
- package/package.json +1 -1
- 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,
|
|
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,
|
|
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,
|
|
13
|
-
handleBuildingChipClick: (segment: ChipSegment,
|
|
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 "../
|
|
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,
|
|
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,
|
|
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,
|
|
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 =
|
|
21
|
+
const anchorEl = internalRef.current;
|
|
22
22
|
if (!anchorEl) return;
|
|
23
|
-
onSegmentClick(segment, anchorEl
|
|
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
|
|
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
|
|
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 '
|
|
2
|
-
import type { Condition, FieldMetadata, FilterOperator } from '
|
|
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 "
|
|
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 '
|
|
2
|
-
import type { FieldMetadata, FilterOperator } from '
|
|
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 "
|
|
2
|
-
import { getOperatorLabel } from "
|
|
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
|
|
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 "
|
|
2
|
-
import { chipIdToConditionIndex, getFieldValues, hasStaticAllowlist, isDatePreset } from "
|
|
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,
|
|
71
|
+
export { displayDateToIso, resolveDateRangeValue, resolveDateValue, resolveFieldValue, resolveMultiValues, resolveSingleValue };
|
package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useAutocompleteState.d.ts
ADDED
|
@@ -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
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
9
|
+
resetMenuAnchor();
|
|
10
10
|
setMenuState('closed');
|
|
11
11
|
inputRef.current?.focus();
|
|
12
12
|
}, [
|
|
13
13
|
removeCondition,
|
|
14
|
-
|
|
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
|
-
|
|
32
|
+
resetMenuAnchor();
|
|
33
33
|
setMenuState('closed');
|
|
34
34
|
});
|
|
35
35
|
setMenuState('field');
|
|
36
36
|
inputRef.current?.focus();
|
|
37
37
|
}, [
|
|
38
38
|
resetState,
|
|
39
|
-
|
|
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 "./
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
54
|
-
setMenuOffset,
|
|
52
|
+
setMenuAnchor,
|
|
55
53
|
setSelectedField,
|
|
56
54
|
setSelectedOperator,
|
|
57
55
|
setMenuState,
|
package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFilterInputAutocomplete.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { RefObject } from 'react';
|
|
2
|
-
import {
|
|
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,
|
|
56
|
-
handleBuildingChipClick: (segment: ChipSegment,
|
|
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;
|