@wallarm-org/design-system 0.40.0-rc-feature-AS-982.7 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/DropdownMenu/DropdownMenuCheckboxItem.d.ts +15 -0
- package/dist/components/DropdownMenu/DropdownMenuCheckboxItem.js +32 -0
- package/dist/components/DropdownMenu/DropdownMenuContent.js +6 -2
- package/dist/components/DropdownMenu/DropdownMenuItemIndicator.d.ts +2 -0
- package/dist/components/DropdownMenu/DropdownMenuItemIndicator.js +14 -0
- package/dist/components/DropdownMenu/DropdownMenuRadioGroup.d.ts +9 -0
- package/dist/components/DropdownMenu/DropdownMenuRadioGroup.js +17 -0
- package/dist/components/DropdownMenu/DropdownMenuRadioItem.d.ts +13 -0
- package/dist/components/DropdownMenu/DropdownMenuRadioItem.js +28 -0
- package/dist/components/DropdownMenu/classes.d.ts +1 -0
- package/dist/components/DropdownMenu/classes.js +2 -1
- package/dist/components/DropdownMenu/index.d.ts +3 -0
- package/dist/components/DropdownMenu/index.js +4 -1
- package/dist/components/FilterInput/FilterInput.d.ts +8 -5
- package/dist/components/FilterInput/FilterInputContext/types.d.ts +9 -12
- package/dist/components/FilterInput/FilterInputContext/useFilterInputContextValue.d.ts +2 -4
- package/dist/components/FilterInput/FilterInputContext/useFilterInputContextValue.js +0 -4
- package/dist/components/FilterInput/FilterInputErrors/parseFilterInputErrors.js +2 -1
- 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/FilterInputField.js +40 -11
- package/dist/components/FilterInput/FilterInputMenu/FilterInputDateValueMenu/constants.d.ts +2 -2
- package/dist/components/FilterInput/FilterInputMenu/FilterInputFieldMenu/FilterInputFieldMenu.d.ts +1 -1
- package/dist/components/FilterInput/FilterInputMenu/FilterInputMenu.d.ts +1 -1
- package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/FilterInputValueMenu.d.ts +6 -5
- package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/useValueMenuDisplayValues.d.ts +14 -4
- package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/useValueMenuState.d.ts +5 -3
- package/dist/components/FilterInput/FilterInputMenu/hooks/useKeyboardNav.d.ts +1 -1
- package/dist/components/FilterInput/FilterInputMenu/hooks/useKeyboardNav.js +2 -5
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{lib/deriveAutocompleteValues.d.ts → deriveAutocompleteValues.d.ts} +3 -3
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{lib/deriveAutocompleteValues.js → deriveAutocompleteValues.js} +1 -1
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useBlurCommit.d.ts +16 -5
- 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/useChipEditing.d.ts +8 -7
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useChipEditing.js +12 -15
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFilterInputAutocomplete.d.ts +10 -9
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFilterInputAutocomplete.js +83 -52
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFocusManagement.d.ts +11 -9
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFocusManagement.js +20 -47
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useInputHandlers.d.ts +4 -6
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useInputHandlers.js +15 -32
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{useMenuFlow/types.d.ts → useMenuFlow.d.ts} +17 -14
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow.js +260 -0
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuPositioning.d.ts +8 -25
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuPositioning.js +22 -39
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useResetState.d.ts +19 -10
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useResetState.js +3 -3
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{lib/valueResolution.d.ts → valueCommitHelpers.d.ts} +7 -1
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/{lib/valueResolution.js → valueCommitHelpers.js} +25 -3
- package/dist/components/FilterInput/hooks/useFilterInputExpression/buildChips.js +2 -1
- package/dist/components/FilterInput/hooks/useFilterInputPositioning.d.ts +4 -9
- package/dist/components/FilterInput/hooks/useFilterInputPositioning.js +6 -7
- package/dist/components/FilterInput/hooks/useFilterInputSelection/lib/dom.d.ts +4 -4
- package/dist/components/FilterInput/hooks/useFilterInputSelection/useFilterInputSelection.d.ts +2 -2
- package/dist/components/FilterInput/hooks/useFilterInputSelection/useSelectionClipboard.d.ts +5 -2
- package/dist/components/FilterInput/lib/applyAcceptChar.d.ts +4 -3
- package/dist/components/FilterInput/lib/applyKnownFieldHelpers.d.ts +25 -13
- package/dist/components/FilterInput/lib/constants.d.ts +34 -10
- package/dist/components/FilterInput/lib/dom.d.ts +11 -15
- package/dist/components/FilterInput/lib/dom.js +9 -14
- package/dist/components/FilterInput/lib/fields.d.ts +19 -10
- package/dist/components/FilterInput/lib/index.d.ts +1 -3
- package/dist/components/FilterInput/lib/index.js +2 -4
- package/dist/components/FilterInput/lib/menuFilterText.d.ts +17 -6
- package/dist/components/FilterInput/lib/operators.d.ts +21 -11
- package/dist/components/FilterInput/lib/serializeExpression.d.ts +12 -5
- package/dist/components/SimpleCharts/LineChart/LineChartLine.js +2 -6
- package/dist/components/SimpleCharts/LineChart/LineChartTooltip.js +3 -3
- package/dist/components/SimpleCharts/LineChart/LineChartXAxis.js +12 -3
- package/dist/components/SimpleCharts/LineChart/LineChartYAxis.js +6 -15
- package/dist/components/SimpleCharts/LineChart/LineChartZoomBrush.js +19 -8
- package/dist/components/SimpleCharts/LineChart/classes.js +1 -1
- package/dist/components/SimpleCharts/LineChart/constants.d.ts +1 -1
- package/dist/components/SimpleCharts/LineChart/constants.js +2 -2
- package/dist/components/SimpleCharts/LineChart/lib/formatRange.d.ts +5 -9
- package/dist/components/SimpleCharts/LineChart/lib/formatRange.js +1 -6
- package/dist/components/SimpleCharts/LineChart/lib/renderAxisTick.d.ts +13 -0
- package/dist/components/SimpleCharts/LineChart/lib/renderAxisTick.js +20 -0
- package/dist/components/SimpleCharts/LineChart/lib/sampleData.js +3 -3
- package/dist/components/SimpleCharts/hooks/useChartTimeFormatters.d.ts +0 -5
- package/dist/components/SimpleCharts/hooks/useChartTimeFormatters.js +1 -2
- package/dist/metadata/components.json +901 -9
- package/package.json +1 -1
- package/dist/components/FilterInput/FilterInputField/hooks/useSegmentEditKeyboard.d.ts +0 -37
- package/dist/components/FilterInput/FilterInputField/hooks/useSegmentEditKeyboard.js +0 -78
- package/dist/components/FilterInput/hooks/useAutoCleanupDetachedElement.d.ts +0 -12
- package/dist/components/FilterInput/hooks/useAutoCleanupDetachedElement.js +0 -22
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/lib/getInitialSegmentText.d.ts +0 -9
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/lib/getInitialSegmentText.js +0 -8
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/lib/index.d.ts +0 -3
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/lib/index.js +0 -4
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useAutocompleteState.d.ts +0 -36
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useAutocompleteState.js +0 -51
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useChipCascade.d.ts +0 -46
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useChipCascade.js +0 -103
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/index.d.ts +0 -1
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/index.js +0 -2
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/types.js +0 -0
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useFieldFlow.d.ts +0 -11
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useFieldFlow.js +0 -95
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useMenuFlow.d.ts +0 -20
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useMenuFlow.js +0 -45
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useOperatorFlow.d.ts +0 -11
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useOperatorFlow.js +0 -87
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useValueFlow.d.ts +0 -14
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useMenuFlow/useValueFlow.js +0 -107
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useSegmentEditFlow.d.ts +0 -36
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useSegmentEditFlow.js +0 -69
- package/dist/components/FilterInput/hooks/useFloatingRecomputeOn.d.ts +0 -14
- package/dist/components/FilterInput/hooks/useFloatingRecomputeOn.js +0 -18
- package/dist/components/FilterInput/hooks/useResizeTracker.d.ts +0 -10
- package/dist/components/FilterInput/hooks/useResizeTracker.js +0 -21
- package/dist/components/FilterInput/lib/segmentMenu.d.ts +0 -4
- package/dist/components/FilterInput/lib/segmentMenu.js +0 -7
- package/dist/components/FilterInput/lib/validation.d.ts +0 -9
- package/dist/components/FilterInput/lib/validation.js +0 -24
|
@@ -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);
|
|
@@ -9,14 +9,25 @@ interface UseBlurCommitDeps {
|
|
|
9
9
|
handleCustomValueCommit: (text: string) => void;
|
|
10
10
|
upsertCondition: UpsertCondition;
|
|
11
11
|
resetState: () => void;
|
|
12
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Indirection ref consumed by useMenuFlow to break the circular dependency
|
|
14
|
+
* useMenuFlow ↔ useBlurCommit. The hook writes the latest commit fn here
|
|
15
|
+
* each render; useMenuFlow calls through it via `() => ref.current()`.
|
|
16
|
+
*/
|
|
13
17
|
commitBuildingOnBlurRef: RefObject<() => boolean>;
|
|
14
18
|
}
|
|
15
19
|
/**
|
|
16
|
-
* Commit an incomplete building chip on blur
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
+
* Commit logic for an incomplete "building" chip on blur or menu close.
|
|
21
|
+
*
|
|
22
|
+
* Instead of discarding the in-progress chip when the user blurs or the menu
|
|
23
|
+
* closes, this either commits the typed text as a custom value (when there's an
|
|
24
|
+
* operator + text) or persists it as an error chip (so it remains visible and
|
|
25
|
+
* editable). Uses fresh refs to avoid stale closures.
|
|
26
|
+
*
|
|
27
|
+
* Re-entry guard: snapshots and clears the refs synchronously so concurrent
|
|
28
|
+
* callers (two `onOpenChange(false)` from Ark UI menus during a state transition,
|
|
29
|
+
* plus a blur in the same tick) short-circuit on re-entry instead of creating
|
|
30
|
+
* duplicate error chips.
|
|
20
31
|
*/
|
|
21
32
|
export declare const useBlurCommit: ({ selectedField, selectedOperator, inputText, editingChipId, effectiveInsertIndexRef, handleCustomValueCommit, upsertCondition, resetState, commitBuildingOnBlurRef, }: UseBlurCommitDeps) => {
|
|
22
33
|
commitBuildingOnBlur: () => boolean;
|
|
@@ -5,7 +5,7 @@ interface UseChipActionsDeps {
|
|
|
5
5
|
inputRef: RefObject<HTMLInputElement | null>;
|
|
6
6
|
removeCondition: (chipId: string) => void;
|
|
7
7
|
clearAll: () => void;
|
|
8
|
-
|
|
8
|
+
resetMenuOffset: () => 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, resetMenuOffset, 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, resetMenuOffset, 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
|
+
resetMenuOffset();
|
|
10
10
|
setMenuState('closed');
|
|
11
11
|
inputRef.current?.focus();
|
|
12
12
|
}, [
|
|
13
13
|
removeCondition,
|
|
14
|
-
|
|
14
|
+
resetMenuOffset,
|
|
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
|
+
resetMenuOffset();
|
|
33
33
|
setMenuState('closed');
|
|
34
34
|
});
|
|
35
35
|
setMenuState('field');
|
|
36
36
|
inputRef.current?.focus();
|
|
37
37
|
}, [
|
|
38
38
|
resetState,
|
|
39
|
-
|
|
39
|
+
resetMenuOffset,
|
|
40
40
|
inputRef,
|
|
41
41
|
setInsertIndex,
|
|
42
42
|
setInsertAfterConnector,
|
|
@@ -1,31 +1,32 @@
|
|
|
1
|
+
import type { RefObject } from 'react';
|
|
1
2
|
import { type ChipSegment } from '../../FilterInputField/FilterInputChip';
|
|
2
3
|
import type { Condition, FieldMetadata, FilterInputChipData, FilterOperator, MenuState, UpsertCondition } from '../../types';
|
|
3
4
|
interface UseChipEditingOptions {
|
|
4
5
|
conditions: Condition[];
|
|
5
6
|
chips: FilterInputChipData[];
|
|
6
7
|
fields: FieldMetadata[];
|
|
7
|
-
|
|
8
|
+
containerRef: RefObject<HTMLElement | null>;
|
|
9
|
+
setMenuOffset: (offset: number) => void;
|
|
8
10
|
setSelectedField: (field: FieldMetadata | null) => void;
|
|
9
11
|
setSelectedOperator: (op: FilterOperator | null) => void;
|
|
10
12
|
setMenuState: (state: MenuState) => void;
|
|
11
13
|
upsertCondition: UpsertCondition;
|
|
12
14
|
}
|
|
13
15
|
/**
|
|
14
|
-
* Manages editing of existing filter chips.
|
|
15
|
-
*
|
|
16
|
+
* Manages editing of existing filter chips.
|
|
17
|
+
* Handles chip click → open appropriate menu based on segment,
|
|
18
|
+
* then advances through the full flow (field → operator → value).
|
|
16
19
|
*/
|
|
17
|
-
export declare const useChipEditing: ({ conditions, chips, fields,
|
|
20
|
+
export declare const useChipEditing: ({ conditions, chips, fields, containerRef, setMenuOffset, setSelectedField, setSelectedOperator, setMenuState, upsertCondition, }: UseChipEditingOptions) => {
|
|
18
21
|
editingChipId: string | null;
|
|
19
22
|
editingSegment: import("../../FilterInputField/FilterInputChip").SegmentVariant | null;
|
|
20
|
-
isBuildingEdit: boolean;
|
|
21
23
|
setEditingSegment: import("react").Dispatch<import("react").SetStateAction<import("../../FilterInputField/FilterInputChip").SegmentVariant | null>>;
|
|
22
24
|
segmentFilterText: string;
|
|
23
25
|
segmentMenuFilterText: string;
|
|
24
26
|
setSegmentFilterText: (text: string) => void;
|
|
25
27
|
resetSegmentTyping: () => void;
|
|
26
|
-
handleChipClick: (chipId: string, segment: ChipSegment,
|
|
28
|
+
handleChipClick: (chipId: string, segment: ChipSegment, anchorRect: DOMRect) => void;
|
|
27
29
|
startBuildingEdit: (segment: ChipSegment, currentText: string) => void;
|
|
28
|
-
switchEditSegment: (segment: ChipSegment, currentText: string) => void;
|
|
29
30
|
clearEditing: () => void;
|
|
30
31
|
};
|
|
31
32
|
export {};
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { useCallback, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { SEGMENT_VARIANT } from "../../FilterInputField/FilterInputChip/index.js";
|
|
3
|
-
import {
|
|
3
|
+
import { chipIdToConditionIndex, getOperatorFromLabel, isNoValueOperator } from "../../lib/index.js";
|
|
4
4
|
const getConditionByChipId = (chipId, conditions)=>{
|
|
5
5
|
const idx = chipIdToConditionIndex(chipId);
|
|
6
6
|
return null !== idx ? conditions[idx] ?? null : null;
|
|
7
7
|
};
|
|
8
|
+
const SEGMENT_TO_MENU = {
|
|
9
|
+
attribute: 'field',
|
|
10
|
+
operator: 'operator',
|
|
11
|
+
value: 'value'
|
|
12
|
+
};
|
|
8
13
|
const getFirstIncompleteSegment = (condition, fields)=>{
|
|
9
14
|
const field = fields.find((f)=>f.name === condition.field);
|
|
10
15
|
if (!field || condition.error === SEGMENT_VARIANT.attribute) return SEGMENT_VARIANT.attribute;
|
|
@@ -12,7 +17,7 @@ const getFirstIncompleteSegment = (condition, fields)=>{
|
|
|
12
17
|
if (null === condition.value || '' === condition.value || condition.error === SEGMENT_VARIANT.value) return SEGMENT_VARIANT.value;
|
|
13
18
|
return null;
|
|
14
19
|
};
|
|
15
|
-
const useChipEditing = ({ conditions, chips, fields,
|
|
20
|
+
const useChipEditing = ({ conditions, chips, fields, containerRef, setMenuOffset, setSelectedField, setSelectedOperator, setMenuState, upsertCondition })=>{
|
|
16
21
|
const [editingChipId, setEditingChipId] = useState(null);
|
|
17
22
|
const [editingSegment, setEditingSegment] = useState(null);
|
|
18
23
|
const [segmentFilterText, setSegmentFilterText] = useState('');
|
|
@@ -23,7 +28,7 @@ const useChipEditing = ({ conditions, chips, fields, setMenuAnchor, setSelectedF
|
|
|
23
28
|
chipsRef.current = chips;
|
|
24
29
|
const fieldsRef = useRef(fields);
|
|
25
30
|
fieldsRef.current = fields;
|
|
26
|
-
const handleChipClick = useCallback((chipId, segment,
|
|
31
|
+
const handleChipClick = useCallback((chipId, segment, anchorRect)=>{
|
|
27
32
|
const condition = getConditionByChipId(chipId, conditionsRef.current);
|
|
28
33
|
if (!condition) return;
|
|
29
34
|
const field = fieldsRef.current.find((f)=>f.name === condition.field);
|
|
@@ -34,7 +39,8 @@ const useChipEditing = ({ conditions, chips, fields, setMenuAnchor, setSelectedF
|
|
|
34
39
|
const targetSegment = incompleteSegment ?? (isPlaceholderValueClick ? SEGMENT_VARIANT.operator : segment);
|
|
35
40
|
if (!field && targetSegment !== SEGMENT_VARIANT.attribute) return;
|
|
36
41
|
if (incompleteSegment && field) upsertCondition(field, condition.operator, condition.value, chipId);
|
|
37
|
-
|
|
42
|
+
const containerRect = containerRef.current?.getBoundingClientRect();
|
|
43
|
+
setMenuOffset(containerRect ? anchorRect.left - containerRect.left : 0);
|
|
38
44
|
setEditingChipId(chipId);
|
|
39
45
|
setSelectedField(field ?? null);
|
|
40
46
|
const rawOperator = targetSegment === SEGMENT_VARIANT.value || targetSegment === SEGMENT_VARIANT.operator ? getOperatorFromLabel(chip.operator || '', field?.type ?? 'string') ?? condition.operator : null;
|
|
@@ -49,7 +55,8 @@ const useChipEditing = ({ conditions, chips, fields, setMenuAnchor, setSelectedF
|
|
|
49
55
|
setUserHasTyped(false);
|
|
50
56
|
setMenuState(SEGMENT_TO_MENU[targetSegment]);
|
|
51
57
|
}, [
|
|
52
|
-
|
|
58
|
+
containerRef,
|
|
59
|
+
setMenuOffset,
|
|
53
60
|
setSelectedField,
|
|
54
61
|
setSelectedOperator,
|
|
55
62
|
setMenuState,
|
|
@@ -67,11 +74,6 @@ const useChipEditing = ({ conditions, chips, fields, setMenuAnchor, setSelectedF
|
|
|
67
74
|
setSegmentFilterText(currentText);
|
|
68
75
|
setUserHasTyped(false);
|
|
69
76
|
}, []);
|
|
70
|
-
const switchEditSegment = useCallback((segment, currentText)=>{
|
|
71
|
-
setEditingSegment(segment);
|
|
72
|
-
setSegmentFilterText(currentText);
|
|
73
|
-
setUserHasTyped(false);
|
|
74
|
-
}, []);
|
|
75
77
|
const handleSegmentFilterChange = useCallback((text)=>{
|
|
76
78
|
setSegmentFilterText(text);
|
|
77
79
|
setUserHasTyped(true);
|
|
@@ -81,11 +83,9 @@ const useChipEditing = ({ conditions, chips, fields, setMenuAnchor, setSelectedF
|
|
|
81
83
|
}, []);
|
|
82
84
|
const segmentDisplayText = segmentFilterText;
|
|
83
85
|
const segmentMenuFilterText = userHasTyped ? segmentFilterText : '';
|
|
84
|
-
const isBuildingEdit = null === editingChipId && null !== editingSegment;
|
|
85
86
|
return useMemo(()=>({
|
|
86
87
|
editingChipId,
|
|
87
88
|
editingSegment,
|
|
88
|
-
isBuildingEdit,
|
|
89
89
|
setEditingSegment,
|
|
90
90
|
segmentFilterText: segmentDisplayText,
|
|
91
91
|
segmentMenuFilterText,
|
|
@@ -93,19 +93,16 @@ const useChipEditing = ({ conditions, chips, fields, setMenuAnchor, setSelectedF
|
|
|
93
93
|
resetSegmentTyping,
|
|
94
94
|
handleChipClick,
|
|
95
95
|
startBuildingEdit,
|
|
96
|
-
switchEditSegment,
|
|
97
96
|
clearEditing
|
|
98
97
|
}), [
|
|
99
98
|
editingChipId,
|
|
100
99
|
editingSegment,
|
|
101
|
-
isBuildingEdit,
|
|
102
100
|
segmentDisplayText,
|
|
103
101
|
segmentMenuFilterText,
|
|
104
102
|
handleSegmentFilterChange,
|
|
105
103
|
resetSegmentTyping,
|
|
106
104
|
handleChipClick,
|
|
107
105
|
startBuildingEdit,
|
|
108
|
-
switchEditSegment,
|
|
109
106
|
clearEditing
|
|
110
107
|
]);
|
|
111
108
|
};
|
package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFilterInputAutocomplete.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { RefObject } from 'react';
|
|
2
|
-
import
|
|
2
|
+
import { type ChipSegment } from '../../FilterInputField/FilterInputChip';
|
|
3
|
+
import type { Condition, FieldMetadata, FilterInputChipData, FilterOperator, MenuState, UpsertCondition } from '../../types';
|
|
3
4
|
interface UseFilterInputAutocompleteOptions {
|
|
4
5
|
fields: FieldMetadata[];
|
|
5
6
|
conditions: Condition[];
|
|
@@ -15,9 +16,9 @@ interface UseFilterInputAutocompleteOptions {
|
|
|
15
16
|
}
|
|
16
17
|
export declare const useFilterInputAutocomplete: ({ fields, conditions, chips, upsertCondition, removeCondition, removeConditionAtIndex, clearAll, setConnectorValue, containerRef, buildingChipRef, inputRef, }: UseFilterInputAutocompleteOptions) => {
|
|
17
18
|
inputText: string;
|
|
18
|
-
menuState:
|
|
19
|
+
menuState: MenuState;
|
|
19
20
|
selectedField: FieldMetadata | null;
|
|
20
|
-
selectedOperator:
|
|
21
|
+
selectedOperator: FilterOperator | null;
|
|
21
22
|
isBuilding: boolean;
|
|
22
23
|
buildingChipData: import("../../FilterInputContext").BuildingChipData | null;
|
|
23
24
|
menuPositioning: {
|
|
@@ -40,19 +41,19 @@ export declare const useFilterInputAutocomplete: ({ fields, conditions, chips, u
|
|
|
40
41
|
inputRef: RefObject<HTMLInputElement | null>;
|
|
41
42
|
handleInputChange: (e: import("react").ChangeEvent<HTMLInputElement>) => void;
|
|
42
43
|
handleFieldSelect: (field: FieldMetadata) => void;
|
|
43
|
-
handleOperatorSelect: (operator:
|
|
44
|
+
handleOperatorSelect: (operator: FilterOperator) => void;
|
|
44
45
|
handleValueSelect: (val: string | number | boolean) => void;
|
|
45
46
|
handleMultiCommit: (values: Array<string | number | boolean>) => void;
|
|
46
47
|
handleBuildingValueChange: (preview: string | undefined) => void;
|
|
47
48
|
handleMultiSelectToggle: () => void;
|
|
48
49
|
handleMenuClose: () => void;
|
|
49
50
|
handleMenuDiscard: () => void;
|
|
50
|
-
/** Hard reset
|
|
51
|
+
/** Hard reset of autocomplete state — used by paste/clipboard flows where
|
|
52
|
+
* the conditions array is replaced and any in-progress building must be
|
|
53
|
+
* scrapped, regardless of inline-edit mode. */
|
|
51
54
|
resetAutocompleteState: (continueBuilding?: boolean) => void;
|
|
52
|
-
handleChipClick: (chipId: string, segment:
|
|
53
|
-
handleBuildingChipClick: (segment:
|
|
54
|
-
switchEditSegment: (targetSegment: import("../../FilterInputField").ChipSegment) => boolean;
|
|
55
|
-
removeEditingChip: () => void;
|
|
55
|
+
handleChipClick: (chipId: string, segment: ChipSegment, anchorRect: DOMRect) => void;
|
|
56
|
+
handleBuildingChipClick: (segment: ChipSegment, anchorRect: DOMRect) => void;
|
|
56
57
|
handleConnectorChange: (connectorId: string, value: "and" | "or") => void;
|
|
57
58
|
handleChipRemove: (chipId: string) => void;
|
|
58
59
|
handleClear: () => void;
|
package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFilterInputAutocomplete.js
CHANGED
|
@@ -1,36 +1,50 @@
|
|
|
1
|
+
import { useCallback, useRef, useState } from "react";
|
|
1
2
|
import { SEGMENT_VARIANT } from "../../FilterInputField/FilterInputChip/index.js";
|
|
2
3
|
import { useDateRange } from "../../FilterInputMenu/FilterInputDateValueMenu/hooks.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
4
|
+
import { applyAcceptChar, getOperatorLabel } from "../../lib/index.js";
|
|
5
|
+
import { deriveAutocompleteValues } from "./deriveAutocompleteValues.js";
|
|
5
6
|
import { useBlurCommit } from "./useBlurCommit.js";
|
|
6
7
|
import { useChipActions } from "./useChipActions.js";
|
|
7
|
-
import { useChipCascade } from "./useChipCascade.js";
|
|
8
8
|
import { useChipEditing } from "./useChipEditing.js";
|
|
9
9
|
import { useFocusManagement } from "./useFocusManagement.js";
|
|
10
10
|
import { useInputHandlers } from "./useInputHandlers.js";
|
|
11
|
-
import { useMenuFlow } from "./useMenuFlow
|
|
11
|
+
import { useMenuFlow } from "./useMenuFlow.js";
|
|
12
12
|
import { useMenuPositioning } from "./useMenuPositioning.js";
|
|
13
13
|
import { useResetState } from "./useResetState.js";
|
|
14
|
-
import { useSegmentEditFlow } from "./useSegmentEditFlow.js";
|
|
15
14
|
const useFilterInputAutocomplete = ({ fields, conditions, chips, upsertCondition, removeCondition, removeConditionAtIndex, clearAll, setConnectorValue, containerRef, buildingChipRef, inputRef })=>{
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
const
|
|
15
|
+
const [inputText, setInputText] = useState('');
|
|
16
|
+
const [menuState, setMenuState] = useState('closed');
|
|
17
|
+
const [selectedField, setSelectedField] = useState(null);
|
|
18
|
+
const [selectedOperator, setSelectedOperator] = useState(null);
|
|
19
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
20
|
+
const [buildingMultiValue, setBuildingMultiValue] = useState(void 0);
|
|
21
|
+
const [insertIndex, setInsertIndex] = useState(null);
|
|
22
|
+
const [insertAfterConnector, setInsertAfterConnector] = useState(false);
|
|
23
|
+
const effectiveInsertIndex = insertIndex ?? conditions.length;
|
|
24
|
+
const effectiveInsertIndexRef = useRef(effectiveInsertIndex);
|
|
25
|
+
effectiveInsertIndexRef.current = effectiveInsertIndex;
|
|
26
|
+
const conditionsRef = useRef(conditions);
|
|
27
|
+
conditionsRef.current = conditions;
|
|
28
|
+
const conditionsLengthRef = useRef(conditions.length);
|
|
29
|
+
conditionsLengthRef.current = conditions.length;
|
|
30
|
+
const blurCommitRef = useRef(null);
|
|
31
|
+
const segmentAttributeInputRef = useRef(null);
|
|
32
|
+
const segmentOperatorInputRef = useRef(null);
|
|
33
|
+
const segmentValueInputRef = useRef(null);
|
|
34
|
+
const commitBuildingOnBlurRef = useRef(()=>false);
|
|
35
|
+
const { menuPositioning, setMenuOffset, resetMenuOffset } = useMenuPositioning({
|
|
21
36
|
containerRef,
|
|
22
37
|
buildingChipRef,
|
|
23
38
|
inputRef,
|
|
24
39
|
isBuilding: null !== selectedField,
|
|
25
|
-
insertIndex: effectiveInsertIndex
|
|
26
|
-
chipsCount: chips.length,
|
|
27
|
-
isMenuOpen: 'closed' !== menuState
|
|
40
|
+
insertIndex: effectiveInsertIndex
|
|
28
41
|
});
|
|
29
42
|
const editing = useChipEditing({
|
|
30
43
|
conditions,
|
|
31
44
|
chips,
|
|
32
45
|
fields,
|
|
33
|
-
|
|
46
|
+
containerRef,
|
|
47
|
+
setMenuOffset,
|
|
34
48
|
setSelectedField,
|
|
35
49
|
setSelectedOperator,
|
|
36
50
|
setMenuState,
|
|
@@ -42,7 +56,7 @@ const useFilterInputAutocomplete = ({ fields, conditions, chips, upsertCondition
|
|
|
42
56
|
dateRange,
|
|
43
57
|
containerRef,
|
|
44
58
|
inputRef,
|
|
45
|
-
|
|
59
|
+
resetMenuOffset,
|
|
46
60
|
setInputText,
|
|
47
61
|
setSelectedField,
|
|
48
62
|
setSelectedOperator,
|
|
@@ -69,24 +83,6 @@ const useFilterInputAutocomplete = ({ fields, conditions, chips, upsertCondition
|
|
|
69
83
|
setMenuState,
|
|
70
84
|
setBuildingMultiValue
|
|
71
85
|
});
|
|
72
|
-
const { switchEditSegment, removeEditingChip, stepBackBuildingMenu } = useChipCascade({
|
|
73
|
-
editing,
|
|
74
|
-
chips,
|
|
75
|
-
fields,
|
|
76
|
-
conditionsRef,
|
|
77
|
-
effectiveInsertIndexRef,
|
|
78
|
-
selectedField,
|
|
79
|
-
selectedOperator,
|
|
80
|
-
buildingMultiValue,
|
|
81
|
-
upsertCondition,
|
|
82
|
-
removeCondition,
|
|
83
|
-
resetState,
|
|
84
|
-
setInputText,
|
|
85
|
-
setMenuState,
|
|
86
|
-
setSelectedOperator,
|
|
87
|
-
setBuildingMultiValue,
|
|
88
|
-
setInsertIndex
|
|
89
|
-
});
|
|
90
86
|
const { handleInputChange, handleInputClick, handleKeyDown, menuRef } = useInputHandlers({
|
|
91
87
|
inputText,
|
|
92
88
|
menuState,
|
|
@@ -101,12 +97,11 @@ const useFilterInputAutocomplete = ({ fields, conditions, chips, upsertCondition
|
|
|
101
97
|
setInputText,
|
|
102
98
|
setMenuState,
|
|
103
99
|
setInsertIndex,
|
|
104
|
-
|
|
100
|
+
resetMenuOffset,
|
|
105
101
|
removeConditionAtIndex,
|
|
106
102
|
handleFieldSelect,
|
|
107
103
|
handleOperatorSelect,
|
|
108
|
-
handleCustomValueCommit
|
|
109
|
-
stepBackBuildingMenu
|
|
104
|
+
handleCustomValueCommit
|
|
110
105
|
});
|
|
111
106
|
const { commitBuildingOnBlur, hasIncompleteBuilding } = useBlurCommit({
|
|
112
107
|
selectedField,
|
|
@@ -137,7 +132,7 @@ const useFilterInputAutocomplete = ({ fields, conditions, chips, upsertCondition
|
|
|
137
132
|
hasIncompleteBuilding,
|
|
138
133
|
setIsFocused,
|
|
139
134
|
setMenuState,
|
|
140
|
-
|
|
135
|
+
resetMenuOffset,
|
|
141
136
|
resetState
|
|
142
137
|
});
|
|
143
138
|
const { handleChipRemove, handleClear, handleGapClick, closeAutocompleteMenu } = useChipActions({
|
|
@@ -145,24 +140,12 @@ const useFilterInputAutocomplete = ({ fields, conditions, chips, upsertCondition
|
|
|
145
140
|
inputRef,
|
|
146
141
|
removeCondition,
|
|
147
142
|
clearAll,
|
|
148
|
-
|
|
143
|
+
resetMenuOffset,
|
|
149
144
|
resetState,
|
|
150
145
|
setInsertIndex,
|
|
151
146
|
setInsertAfterConnector,
|
|
152
147
|
setMenuState
|
|
153
148
|
});
|
|
154
|
-
const { handleSegmentFilterChange, cancelSegmentEdit, handleMenuDiscard, handleBuildingChipClick } = useSegmentEditFlow({
|
|
155
|
-
editing,
|
|
156
|
-
selectedField,
|
|
157
|
-
selectedOperator,
|
|
158
|
-
buildingMultiValue,
|
|
159
|
-
resetState,
|
|
160
|
-
setSelectedField,
|
|
161
|
-
setSelectedOperator,
|
|
162
|
-
setInputText,
|
|
163
|
-
setMenuState,
|
|
164
|
-
setMenuAnchor
|
|
165
|
-
});
|
|
166
149
|
const { isBuilding, buildingChipData, editingMultiValues, editingSingleValue, editingDateRange } = deriveAutocompleteValues({
|
|
167
150
|
editingChipId: editing.editingChipId,
|
|
168
151
|
selectedField,
|
|
@@ -172,6 +155,56 @@ const useFilterInputAutocomplete = ({ fields, conditions, chips, upsertCondition
|
|
|
172
155
|
dateRangeFromValue: dateRange.fromValue,
|
|
173
156
|
segmentFilterText: editing.editingSegment === SEGMENT_VARIANT.value ? editing.segmentMenuFilterText : void 0
|
|
174
157
|
});
|
|
158
|
+
const handleSegmentFilterChange = useCallback((text)=>{
|
|
159
|
+
const accept = selectedField?.acceptChar;
|
|
160
|
+
const next = editing.editingSegment === SEGMENT_VARIANT.value && accept ? applyAcceptChar(text, accept) : text;
|
|
161
|
+
editing.setSegmentFilterText(next);
|
|
162
|
+
}, [
|
|
163
|
+
selectedField,
|
|
164
|
+
editing
|
|
165
|
+
]);
|
|
166
|
+
const cancelSegmentEdit = useCallback(()=>{
|
|
167
|
+
const isBuildingEdit = !editing.editingChipId && null !== editing.editingSegment;
|
|
168
|
+
if (isBuildingEdit) {
|
|
169
|
+
editing.clearEditing();
|
|
170
|
+
setMenuState('closed');
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
setSelectedField(null);
|
|
174
|
+
setSelectedOperator(null);
|
|
175
|
+
editing.clearEditing();
|
|
176
|
+
setMenuState('closed');
|
|
177
|
+
}, [
|
|
178
|
+
editing
|
|
179
|
+
]);
|
|
180
|
+
const handleMenuDiscard = useCallback(()=>{
|
|
181
|
+
const isBuildingEdit = !editing.editingChipId && null !== editing.editingSegment;
|
|
182
|
+
if (isBuildingEdit) {
|
|
183
|
+
editing.clearEditing();
|
|
184
|
+
setMenuState('closed');
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
resetState();
|
|
188
|
+
}, [
|
|
189
|
+
editing,
|
|
190
|
+
resetState
|
|
191
|
+
]);
|
|
192
|
+
const handleBuildingChipClick = useCallback((segment, anchorRect)=>{
|
|
193
|
+
if (!selectedField) return;
|
|
194
|
+
const containerRect = containerRef.current?.getBoundingClientRect();
|
|
195
|
+
setMenuOffset(containerRect ? anchorRect.left - containerRect.left : 0);
|
|
196
|
+
const initialText = segment === SEGMENT_VARIANT.attribute ? selectedField.label : segment === SEGMENT_VARIANT.operator ? selectedOperator ? getOperatorLabel(selectedOperator, selectedField.type) : '' : buildingMultiValue ?? '';
|
|
197
|
+
editing.startBuildingEdit(segment, initialText);
|
|
198
|
+
setInputText('');
|
|
199
|
+
setMenuState(segment === SEGMENT_VARIANT.attribute ? 'field' : segment === SEGMENT_VARIANT.operator ? 'operator' : 'value');
|
|
200
|
+
}, [
|
|
201
|
+
selectedField,
|
|
202
|
+
selectedOperator,
|
|
203
|
+
buildingMultiValue,
|
|
204
|
+
containerRef,
|
|
205
|
+
setMenuOffset,
|
|
206
|
+
editing
|
|
207
|
+
]);
|
|
175
208
|
return {
|
|
176
209
|
inputText,
|
|
177
210
|
menuState,
|
|
@@ -196,8 +229,6 @@ const useFilterInputAutocomplete = ({ fields, conditions, chips, upsertCondition
|
|
|
196
229
|
resetAutocompleteState: resetState,
|
|
197
230
|
handleChipClick: editing.handleChipClick,
|
|
198
231
|
handleBuildingChipClick,
|
|
199
|
-
switchEditSegment,
|
|
200
|
-
removeEditingChip,
|
|
201
232
|
handleConnectorChange: setConnectorValue,
|
|
202
233
|
handleChipRemove,
|
|
203
234
|
handleClear,
|
package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFocusManagement.d.ts
CHANGED
|
@@ -6,30 +6,32 @@ interface UseFocusManagementDeps {
|
|
|
6
6
|
isFocused: boolean;
|
|
7
7
|
conditionsLength: number;
|
|
8
8
|
inputText: string;
|
|
9
|
-
/** In-progress building-chip state — refocus resumes at next
|
|
9
|
+
/** In-progress building-chip state — needed so refocus resumes at the next
|
|
10
|
+
* missing segment instead of (incorrectly) reopening the field menu. */
|
|
10
11
|
selectedField: FieldMetadata | null;
|
|
11
12
|
selectedOperator: FilterOperator | null;
|
|
12
13
|
containerRef: RefObject<HTMLElement | null>;
|
|
13
14
|
inputRef: RefObject<HTMLInputElement | null>;
|
|
14
15
|
editingSegment: ChipSegment | null;
|
|
15
|
-
/** Direct ref to the attribute segment input when editing. */
|
|
16
|
+
/** Direct ref to the attribute segment <input> when editing — avoids querySelector. */
|
|
16
17
|
segmentAttributeInputRef: RefObject<HTMLInputElement | null>;
|
|
17
|
-
/** Direct ref to the operator segment input when editing. */
|
|
18
|
+
/** Direct ref to the operator segment <input> when editing — avoids querySelector. */
|
|
18
19
|
segmentOperatorInputRef: RefObject<HTMLInputElement | null>;
|
|
19
|
-
/** Direct ref to the value segment input when editing. */
|
|
20
|
+
/** Direct ref to the value segment <input> when editing — avoids querySelector. */
|
|
20
21
|
segmentValueInputRef: RefObject<HTMLInputElement | null>;
|
|
21
|
-
/**
|
|
22
|
+
/** Ref set by FilterInputValueMenu — calls commitChecked() for multi-select before blur reset. Returns true if committed. */
|
|
22
23
|
blurCommitRef: RefObject<(() => boolean) | null>;
|
|
23
|
-
/**
|
|
24
|
+
/** Tries to commit a building chip's freeform value on blur. Returns true if committed. */
|
|
24
25
|
commitBuildingOnBlur: () => boolean;
|
|
25
|
-
/**
|
|
26
|
+
/** True if there's an in-progress building chip that the blur/close path
|
|
27
|
+
* must preserve (skip resetState). */
|
|
26
28
|
hasIncompleteBuilding: () => boolean;
|
|
27
29
|
setIsFocused: (focused: boolean) => void;
|
|
28
30
|
setMenuState: (state: MenuState) => void;
|
|
29
|
-
|
|
31
|
+
resetMenuOffset: () => void;
|
|
30
32
|
resetState: (continueBuilding?: boolean) => void;
|
|
31
33
|
}
|
|
32
|
-
export declare const useFocusManagement: ({ menuState, isFocused, conditionsLength, inputText, selectedField, selectedOperator, containerRef, inputRef, editingSegment, segmentAttributeInputRef, segmentOperatorInputRef, segmentValueInputRef, blurCommitRef, commitBuildingOnBlur, hasIncompleteBuilding, setIsFocused, setMenuState,
|
|
34
|
+
export declare const useFocusManagement: ({ menuState, isFocused, conditionsLength, inputText, selectedField, selectedOperator, containerRef, inputRef, editingSegment, segmentAttributeInputRef, segmentOperatorInputRef, segmentValueInputRef, blurCommitRef, commitBuildingOnBlur, hasIncompleteBuilding, setIsFocused, setMenuState, resetMenuOffset, resetState, }: UseFocusManagementDeps) => {
|
|
33
35
|
handleFocus: (e: FocusEvent) => void;
|
|
34
36
|
handleBlur: (e: FocusEvent) => void;
|
|
35
37
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { useCallback, useEffect,
|
|
1
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
2
2
|
import { SEGMENT_VARIANT } from "../../FilterInputField/FilterInputChip/index.js";
|
|
3
3
|
import { isMenuRelated, nextBuildingMenu } from "../../lib/index.js";
|
|
4
|
-
const useFocusManagement = ({ menuState, isFocused, conditionsLength, inputText, selectedField, selectedOperator, containerRef, inputRef, editingSegment, segmentAttributeInputRef, segmentOperatorInputRef, segmentValueInputRef, blurCommitRef, commitBuildingOnBlur, hasIncompleteBuilding, setIsFocused, setMenuState,
|
|
4
|
+
const useFocusManagement = ({ menuState, isFocused, conditionsLength, inputText, selectedField, selectedOperator, containerRef, inputRef, editingSegment, segmentAttributeInputRef, segmentOperatorInputRef, segmentValueInputRef, blurCommitRef, commitBuildingOnBlur, hasIncompleteBuilding, setIsFocused, setMenuState, resetMenuOffset, resetState })=>{
|
|
5
5
|
const handleFocus = useCallback((e)=>{
|
|
6
6
|
if (e.target?.closest?.('[data-slot="filter-input-connector-chip"]')) return;
|
|
7
7
|
setIsFocused(true);
|
|
@@ -46,10 +46,10 @@ const useFocusManagement = ({ menuState, isFocused, conditionsLength, inputText,
|
|
|
46
46
|
return;
|
|
47
47
|
}
|
|
48
48
|
if (selectedField) {
|
|
49
|
-
|
|
49
|
+
resetMenuOffset();
|
|
50
50
|
setMenuState(nextBuildingMenu(selectedField, selectedOperator));
|
|
51
51
|
} else if (0 === conditionsLength && '' === inputText) {
|
|
52
|
-
|
|
52
|
+
resetMenuOffset();
|
|
53
53
|
setMenuState('field');
|
|
54
54
|
}
|
|
55
55
|
prevFocusedRef.current = isFocused;
|
|
@@ -60,18 +60,9 @@ const useFocusManagement = ({ menuState, isFocused, conditionsLength, inputText,
|
|
|
60
60
|
selectedField,
|
|
61
61
|
selectedOperator,
|
|
62
62
|
editingSegment,
|
|
63
|
-
|
|
63
|
+
resetMenuOffset,
|
|
64
64
|
setMenuState
|
|
65
65
|
]);
|
|
66
|
-
const segmentInputRefsMap = useMemo(()=>({
|
|
67
|
-
[SEGMENT_VARIANT.attribute]: segmentAttributeInputRef,
|
|
68
|
-
[SEGMENT_VARIANT.operator]: segmentOperatorInputRef,
|
|
69
|
-
[SEGMENT_VARIANT.value]: segmentValueInputRef
|
|
70
|
-
}), [
|
|
71
|
-
segmentAttributeInputRef,
|
|
72
|
-
segmentOperatorInputRef,
|
|
73
|
-
segmentValueInputRef
|
|
74
|
-
]);
|
|
75
66
|
useEffect(()=>{
|
|
76
67
|
if ('closed' === menuState) return;
|
|
77
68
|
if (!isFocused) return;
|
|
@@ -83,11 +74,18 @@ const useFocusManagement = ({ menuState, isFocused, conditionsLength, inputText,
|
|
|
83
74
|
if (!container) return;
|
|
84
75
|
const active = document.activeElement;
|
|
85
76
|
if (active && !container.contains(active) && !isMenuRelated(active)) return;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
77
|
+
if (editingSegment) {
|
|
78
|
+
const segmentInputRefs = {
|
|
79
|
+
[SEGMENT_VARIANT.attribute]: segmentAttributeInputRef,
|
|
80
|
+
[SEGMENT_VARIANT.operator]: segmentOperatorInputRef,
|
|
81
|
+
[SEGMENT_VARIANT.value]: segmentValueInputRef
|
|
82
|
+
};
|
|
83
|
+
const segmentInput = segmentInputRefs[editingSegment]?.current ?? null;
|
|
84
|
+
if (segmentInput && document.activeElement !== segmentInput) {
|
|
85
|
+
segmentInput.focus();
|
|
86
|
+
segmentInput.select();
|
|
87
|
+
}
|
|
88
|
+
} else if (document.activeElement !== inputRef.current) inputRef.current?.focus();
|
|
91
89
|
});
|
|
92
90
|
});
|
|
93
91
|
return ()=>{
|
|
@@ -100,34 +98,9 @@ const useFocusManagement = ({ menuState, isFocused, conditionsLength, inputText,
|
|
|
100
98
|
inputRef,
|
|
101
99
|
editingSegment,
|
|
102
100
|
containerRef,
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if ('closed' === menuState) return;
|
|
107
|
-
if (!isFocused) return;
|
|
108
|
-
const handleFocusIn = (e)=>{
|
|
109
|
-
const targetEl = e.target;
|
|
110
|
-
if (!targetEl) return;
|
|
111
|
-
const menu = targetEl.closest('[data-filter-input-menu]');
|
|
112
|
-
if (!menu) return;
|
|
113
|
-
if (menu.querySelector('[data-scope="date-picker"]')) return;
|
|
114
|
-
const tag = targetEl.tagName;
|
|
115
|
-
if ('BUTTON' === tag || 'INPUT' === tag || 'TEXTAREA' === tag || 'SELECT' === tag) return;
|
|
116
|
-
const dest = editingSegment ? segmentInputRefsMap[editingSegment]?.current : inputRef.current;
|
|
117
|
-
if (!dest) return;
|
|
118
|
-
if (document.activeElement === dest) return;
|
|
119
|
-
dest.focus({
|
|
120
|
-
preventScroll: true
|
|
121
|
-
});
|
|
122
|
-
};
|
|
123
|
-
document.addEventListener('focusin', handleFocusIn);
|
|
124
|
-
return ()=>document.removeEventListener('focusin', handleFocusIn);
|
|
125
|
-
}, [
|
|
126
|
-
menuState,
|
|
127
|
-
isFocused,
|
|
128
|
-
editingSegment,
|
|
129
|
-
inputRef,
|
|
130
|
-
segmentInputRefsMap
|
|
101
|
+
segmentAttributeInputRef,
|
|
102
|
+
segmentOperatorInputRef,
|
|
103
|
+
segmentValueInputRef
|
|
131
104
|
]);
|
|
132
105
|
return {
|
|
133
106
|
handleFocus,
|