@wallarm-org/design-system 0.69.0-rc-feature-AS-1192.1 → 0.69.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/components/FilterInput/FilterInputErrors/parseFilterInputErrors.js +5 -7
  2. package/dist/components/FilterInput/FilterInputField/FilterInputChip/ChipSearchInput.js +1 -2
  3. package/dist/components/FilterInput/FilterInputField/FilterInputChip/FilterInputChip.js +6 -9
  4. package/dist/components/FilterInput/FilterInputField/FilterInputChip/classes.d.ts +1 -3
  5. package/dist/components/FilterInput/FilterInputField/FilterInputChip/classes.js +1 -1
  6. package/dist/components/FilterInput/FilterInputField/FilterInputChip/constants.d.ts +0 -3
  7. package/dist/components/FilterInput/FilterInputField/FilterInputChip/constants.js +1 -2
  8. package/dist/components/FilterInput/FilterInputField/FilterInputChip/model/useSizerWidth.d.ts +2 -5
  9. package/dist/components/FilterInput/FilterInputField/FilterInputChip/model/useSizerWidth.js +4 -5
  10. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/FilterInputValueMenu.d.ts +0 -2
  11. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/FilterInputValueMenu.js +4 -2
  12. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/ValueMenuItem.js +6 -14
  13. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useBlurCommit.d.ts +1 -8
  14. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useBlurCommit.js +3 -40
  15. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFilterInputAutocomplete.d.ts +4 -5
  16. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFilterInputAutocomplete.js +2 -38
  17. package/dist/components/FilterInput/hooks/useFilterInputExpression/buildChips.js +5 -17
  18. package/dist/components/FilterInput/hooks/useFilterInputExpression/useFilterInputExpression.js +0 -5
  19. package/dist/components/FilterInput/lib/conditions.d.ts +1 -9
  20. package/dist/components/FilterInput/lib/conditions.js +1 -5
  21. package/dist/components/FilterInput/lib/index.d.ts +1 -1
  22. package/dist/components/FilterInput/lib/index.js +2 -2
  23. package/dist/components/FilterInput/types.d.ts +0 -8
  24. package/dist/components/Slider/Slider.d.ts +34 -0
  25. package/dist/components/Slider/Slider.figma.d.ts +1 -0
  26. package/dist/components/Slider/Slider.figma.js +123 -0
  27. package/dist/components/Slider/Slider.js +85 -0
  28. package/dist/components/Slider/SliderContext.d.ts +31 -0
  29. package/dist/components/Slider/SliderContext.js +9 -0
  30. package/dist/components/Slider/SliderControl.d.ts +9 -0
  31. package/dist/components/Slider/SliderControl.js +35 -0
  32. package/dist/components/Slider/SliderInput.d.ts +26 -0
  33. package/dist/components/Slider/SliderInput.js +69 -0
  34. package/dist/components/Slider/SliderMarks.d.ts +15 -0
  35. package/dist/components/Slider/SliderMarks.js +58 -0
  36. package/dist/components/Slider/SliderThumb.d.ts +19 -0
  37. package/dist/components/Slider/SliderThumb.js +58 -0
  38. package/dist/components/Slider/SliderValue.d.ts +14 -0
  39. package/dist/components/Slider/SliderValue.js +21 -0
  40. package/dist/components/Slider/classes.d.ts +52 -0
  41. package/dist/components/Slider/classes.js +14 -0
  42. package/dist/components/Slider/index.d.ts +8 -0
  43. package/dist/components/Slider/index.js +8 -0
  44. package/dist/components/Slider/types.d.ts +11 -0
  45. package/dist/components/Slider/types.js +0 -0
  46. package/dist/index.d.ts +1 -0
  47. package/dist/index.js +2 -1
  48. package/dist/metadata/components.json +905 -1
  49. package/package.json +1 -1
  50. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/valueOptionSearchText.d.ts +0 -7
  51. package/dist/components/FilterInput/FilterInputMenu/FilterInputValueMenu/valueOptionSearchText.js +0 -9
  52. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useResumeBuilding.d.ts +0 -31
  53. package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useResumeBuilding.js +0 -76
@@ -1,10 +1,11 @@
1
1
  import { SEGMENT_VARIANT } from "../FilterInputField/FilterInputChip/index.js";
2
- import { getFieldValues, hasStaticAllowlist, incompleteTripletError, isEmptyFilterValue, isNoValueOperator, isValidFieldValue } from "../lib/index.js";
2
+ import { getFieldValues, hasStaticAllowlist, isNoValueOperator, isValidFieldValue } from "../lib/index.js";
3
3
  const isPairValueMissing = (condition)=>{
4
4
  const pair = condition.pair;
5
5
  if (!pair) return true;
6
6
  if (pair.operator && isNoValueOperator(pair.operator)) return false;
7
- return isEmptyFilterValue(pair.value);
7
+ const value = pair.value;
8
+ return null == value || '' === value || Array.isArray(value) && 0 === value.length;
8
9
  };
9
10
  const parseFilterInputErrors = (conditions, fields)=>{
10
11
  const errors = [];
@@ -12,12 +13,9 @@ const parseFilterInputErrors = (conditions, fields)=>{
12
13
  const field = fields.find((f)=>f.name === condition.field);
13
14
  const baseIsNoValue = null != condition.operator && isNoValueOperator(condition.operator);
14
15
  if (field?.pairedField && !baseIsNoValue && isPairValueMissing(condition)) errors.push(`${field.pairedField.label} is required`);
16
+ if (!condition.error) continue;
15
17
  const label = field?.label || condition.field;
16
- if (field && !field.pairedField && !condition.error && incompleteTripletError(condition.operator, condition.value)) {
17
- errors.push(`${label} is incomplete`);
18
- continue;
19
- }
20
- if (condition.error) switch(condition.error){
18
+ switch(condition.error){
21
19
  case SEGMENT_VARIANT.attribute:
22
20
  errors.push(`Unknown field ${condition.field}`);
23
21
  break;
@@ -20,7 +20,6 @@ const ChipSearchInput = ()=>{
20
20
  ref: inputRef,
21
21
  type: "text",
22
22
  role: "combobox",
23
- size: 1,
24
23
  "aria-expanded": menuOpen,
25
24
  "aria-invalid": error,
26
25
  "aria-label": "Filter value",
@@ -32,7 +31,7 @@ const ChipSearchInput = ()=>{
32
31
  style: {
33
32
  width: `${inputWidth}px`
34
33
  },
35
- className: "h-22 min-w-0 border-none bg-transparent p-0 text-sm shadow-none outline-none ring-0"
34
+ className: "h-22 border-none bg-transparent p-0 text-sm shadow-none outline-none ring-0"
36
35
  }),
37
36
  /*#__PURE__*/ jsx("span", {
38
37
  ref: sizerRef,
@@ -10,13 +10,11 @@ import { Segment } from "./Segment.js";
10
10
  import { SEGMENT_VARIANT } from "./segmentVariant.js";
11
11
  const FilterInputChip = ({ ref, chipId, attribute, operator, value, error = false, valueParts, valueSeparator, errorValueIndices, building = false, disabled = false, pair, onRemove, onSegmentClick, onPairSegmentClick, className, ...props })=>{
12
12
  const interactive = !disabled;
13
+ const hasError = !!error;
13
14
  const internalRef = useRef(null);
14
15
  const editing = useEditingContext();
15
16
  const isEditingThisChip = null != editing && null != editing.editingSegment && (building ? null == editing.editingChipId : null != chipId && editing.editingChipId === chipId);
16
17
  const activeSegment = isEditingThisChip ? editing.editingSegment : null;
17
- const effectiveError = isEditingThisChip ? false : error;
18
- const effectivePairError = isEditingThisChip ? void 0 : pair?.error;
19
- const hasError = !!effectiveError || !!effectivePairError;
20
18
  const handleSegmentClick = useCallback((segment, e)=>{
21
19
  if (!onSegmentClick) return;
22
20
  if (activeSegment === segment) return;
@@ -64,7 +62,7 @@ const FilterInputChip = ({ ref, chipId, attribute, operator, value, error = fals
64
62
  interactive,
65
63
  disabled,
66
64
  building
67
- }), pair ? 'max-w-[380px]' : 'max-w-[320px]', className),
65
+ }), 'max-w-[320px]', className),
68
66
  "data-slot": "filter-input-condition-chip",
69
67
  ...building && {
70
68
  'data-building': ''
@@ -74,7 +72,7 @@ const FilterInputChip = ({ ref, chipId, attribute, operator, value, error = fals
74
72
  /*#__PURE__*/ jsx(Segment, {
75
73
  variant: SEGMENT_VARIANT.attribute,
76
74
  className: "shrink-0",
77
- error: true === effectiveError || effectiveError === SEGMENT_VARIANT.attribute,
75
+ error: true === error || error === SEGMENT_VARIANT.attribute,
78
76
  onClick: interactive ? (e)=>handleSegmentClick(SEGMENT_VARIANT.attribute, e) : void 0,
79
77
  onMouseDown: interactive && building ? handleSegmentMouseDown : void 0,
80
78
  ...segmentEditProps(SEGMENT_VARIANT.attribute),
@@ -90,8 +88,8 @@ const FilterInputChip = ({ ref, chipId, attribute, operator, value, error = fals
90
88
  }),
91
89
  (value || baseActiveSegment === SEGMENT_VARIANT.value) && /*#__PURE__*/ jsx(Segment, {
92
90
  variant: SEGMENT_VARIANT.value,
93
- className: pair ? 'max-w-[90px] shrink-0' : 'min-w-0',
94
- error: baseActiveSegment !== SEGMENT_VARIANT.value && (true === effectiveError || effectiveError === SEGMENT_VARIANT.value),
91
+ className: "min-w-0",
92
+ error: baseActiveSegment !== SEGMENT_VARIANT.value && (true === error || error === SEGMENT_VARIANT.value),
95
93
  valueParts: valueParts,
96
94
  valueSeparator: valueSeparator,
97
95
  errorValueIndices: errorValueIndices,
@@ -106,7 +104,6 @@ const FilterInputChip = ({ ref, chipId, attribute, operator, value, error = fals
106
104
  /*#__PURE__*/ jsx(Segment, {
107
105
  variant: SEGMENT_VARIANT.attribute,
108
106
  className: "shrink-0",
109
- onClick: interactive && pair.error ? (e)=>handlePairSegmentClick(SEGMENT_VARIANT.value, e) : void 0,
110
107
  children: pair.attribute
111
108
  }),
112
109
  (pair.operator || pairActiveSegment === SEGMENT_VARIANT.operator) && /*#__PURE__*/ jsx(Segment, {
@@ -119,7 +116,7 @@ const FilterInputChip = ({ ref, chipId, attribute, operator, value, error = fals
119
116
  (null != pair.value || pairActiveSegment === SEGMENT_VARIANT.value) && /*#__PURE__*/ jsx(Segment, {
120
117
  variant: SEGMENT_VARIANT.value,
121
118
  className: "min-w-0",
122
- error: pairActiveSegment !== SEGMENT_VARIANT.value && (true === effectivePairError || effectivePairError === SEGMENT_VARIANT.value),
119
+ error: pairActiveSegment !== SEGMENT_VARIANT.value && (true === pair.error || pair.error === SEGMENT_VARIANT.value),
123
120
  onClick: interactive ? (e)=>handlePairSegmentClick('value', e) : void 0,
124
121
  ...segmentEditProps(SEGMENT_VARIANT.value, 1),
125
122
  children: pair.value ?? ''
@@ -12,9 +12,7 @@ export declare const segmentTextVariants: (props?: ({
12
12
  variant?: "value" | "operator" | "attribute" | null | undefined;
13
13
  error?: boolean | null | undefined;
14
14
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
15
- /** Remove button styles — hidden by default, shown on chip hover or button focus.
16
- * `pointer-events-none` while invisible stops it swallowing clicks meant for the
17
- * chip/input and silently deleting the chip (AS-1179). */
15
+ /** Remove button styles — hidden by default, shown on chip hover or button focus */
18
16
  export declare const removeButtonVariants: (props?: ({
19
17
  error?: boolean | null | undefined;
20
18
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
@@ -68,7 +68,7 @@ const segmentTextVariants = cva('truncate text-sm', {
68
68
  error: false
69
69
  }
70
70
  });
71
- const removeButtonVariants = cva(`absolute -right-[13px] top-[-1px] bottom-[-1px] flex items-center justify-center p-0 cursor-pointer w-[18px] border border-solid border-l-0 rounded-r-8 opacity-0 pointer-events-none group-hover/chip:opacity-100 group-hover/chip:pointer-events-auto focus:opacity-100 focus:pointer-events-auto transition-opacity ${hiddenWhenSelected}`, {
71
+ const removeButtonVariants = cva(`absolute -right-[13px] top-[-1px] bottom-[-1px] flex items-center justify-center p-0 cursor-pointer w-[18px] border border-solid border-l-0 rounded-r-8 opacity-0 group-hover/chip:opacity-100 focus:opacity-100 transition-opacity ${hiddenWhenSelected}`, {
72
72
  variants: {
73
73
  error: {
74
74
  true: 'border-border-danger bg-bg-light-danger text-text-danger',
@@ -1,8 +1,5 @@
1
1
  /** Minimum input width in px */
2
2
  export declare const MIN_INPUT_WIDTH = 4;
3
- /** Maximum input width in px — caps the content-sized input so a long value
4
- * can't grow it past the chip; beyond this it scrolls content natively. */
5
- export declare const MAX_INPUT_WIDTH = 280;
6
3
  /** Extra pixels added to measured width to prevent text clipping */
7
4
  export declare const WIDTH_OFFSET = 1;
8
5
  /** Approximate width of a single character in px (text-sm fallback) */
@@ -1,5 +1,4 @@
1
1
  const MIN_INPUT_WIDTH = 4;
2
- const MAX_INPUT_WIDTH = 280;
3
2
  const WIDTH_OFFSET = 1;
4
3
  const CHAR_WIDTH_PX = 8;
5
- export { CHAR_WIDTH_PX, MAX_INPUT_WIDTH, MIN_INPUT_WIDTH, WIDTH_OFFSET };
4
+ export { CHAR_WIDTH_PX, MIN_INPUT_WIDTH, WIDTH_OFFSET };
@@ -6,14 +6,11 @@ interface UseSizerWidthOptions {
6
6
  text: string;
7
7
  /** Minimum width floor (defaults to MIN_INPUT_WIDTH) */
8
8
  minWidth?: number;
9
- /** Maximum width ceiling (defaults to MAX_INPUT_WIDTH) */
10
- maxWidth?: number;
11
9
  }
12
10
  /**
13
11
  * Measures input width from a hidden sizer span.
14
12
  * Falls back to character count * CHAR_WIDTH_PX when the DOM element is unavailable.
15
- * Returns the measured width + WIDTH_OFFSET to prevent text clipping, clamped to
16
- * [minWidth, maxWidth] so a long value can't widen the input past the chip.
13
+ * Returns the measured width + WIDTH_OFFSET to prevent text clipping.
17
14
  */
18
- export declare const useSizerWidth: ({ sizerRef, text, minWidth, maxWidth, }: UseSizerWidthOptions) => number;
15
+ export declare const useSizerWidth: ({ sizerRef, text, minWidth, }: UseSizerWidthOptions) => number;
19
16
  export {};
@@ -1,14 +1,13 @@
1
1
  import { useEffect, useState } from "react";
2
- import { CHAR_WIDTH_PX, MAX_INPUT_WIDTH, MIN_INPUT_WIDTH, WIDTH_OFFSET } from "../constants.js";
3
- const useSizerWidth = ({ sizerRef, text, minWidth = MIN_INPUT_WIDTH, maxWidth = MAX_INPUT_WIDTH })=>{
2
+ import { CHAR_WIDTH_PX, MIN_INPUT_WIDTH, WIDTH_OFFSET } from "../constants.js";
3
+ const useSizerWidth = ({ sizerRef, text, minWidth = MIN_INPUT_WIDTH })=>{
4
4
  const [width, setWidth] = useState(minWidth);
5
5
  useEffect(()=>{
6
6
  const sizerWidth = sizerRef.current?.getBoundingClientRect().width ?? text.length * CHAR_WIDTH_PX;
7
- setWidth(Math.min(maxWidth, Math.max(minWidth, sizerWidth)));
7
+ setWidth(Math.max(minWidth, sizerWidth));
8
8
  }, [
9
9
  text,
10
- minWidth,
11
- maxWidth
10
+ minWidth
12
11
  ]);
13
12
  return width + WIDTH_OFFSET;
14
13
  };
@@ -7,8 +7,6 @@ export interface ValueOption {
7
7
  color: BadgeColor;
8
8
  text: string;
9
9
  };
10
- /** Muted secondary line rendered beneath the bold `label`. Display-only. */
11
- description?: string;
12
10
  hasSubmenu?: boolean;
13
11
  }
14
12
  type ConditionValue = string | number | boolean;
@@ -8,9 +8,11 @@ import { useValueMenuDisplayValues } from "./useValueMenuDisplayValues.js";
8
8
  import { useValueMenuState } from "./useValueMenuState.js";
9
9
  import { ValueMenuFooter } from "./ValueMenuFooter.js";
10
10
  import { ValueMenuItem } from "./ValueMenuItem.js";
11
- import { valueOptionSearchText } from "./valueOptionSearchText.js";
12
11
  const FilterInputValueMenu = ({ values, onSelect, onCommit, open = false, onOpenChange, onEscape, multiSelect = false, initialValues = [], highlightValue, width = 'standard', positioning, onBuildingValueChange, onItemToggle, inputRef, filterText = '', menuRef, blurCommitRef, className })=>{
13
- const filteredValues = useMemo(()=>filterAndSort(values, filterText, valueOptionSearchText), [
12
+ const filteredValues = useMemo(()=>filterAndSort(values, filterText, (v)=>[
13
+ v.label,
14
+ String(v.value)
15
+ ]), [
14
16
  values,
15
17
  filterText
16
18
  ]);
@@ -15,21 +15,13 @@ const ValueMenuItem = ({ option, isChecked, isPending, multiSelect, onSelect, re
15
15
  type: "secondary",
16
16
  variant: "default",
17
17
  children: option.badge.text
18
- }) : /*#__PURE__*/ jsxs("div", {
18
+ }) : /*#__PURE__*/ jsx("div", {
19
19
  className: "min-w-0",
20
- children: [
21
- /*#__PURE__*/ jsx(Text, {
22
- size: "sm",
23
- truncate: true,
24
- children: option.label
25
- }),
26
- option.description && /*#__PURE__*/ jsx(Text, {
27
- size: "xs",
28
- color: "secondary",
29
- truncate: true,
30
- children: option.description
31
- })
32
- ]
20
+ children: /*#__PURE__*/ jsx(Text, {
21
+ size: "sm",
22
+ truncate: true,
23
+ children: option.label
24
+ })
33
25
  }),
34
26
  multiSelect ? /*#__PURE__*/ jsx("div", {
35
27
  className: "flex shrink-0 items-start justify-end py-2 ml-auto",
@@ -1,6 +1,5 @@
1
1
  import type { RefObject } from 'react';
2
2
  import type { FieldMetadata, FilterOperator, UpsertCondition } from '../../types';
3
- import type { BuildingBase } from './useAutocompleteState';
4
3
  interface UseBlurCommitDeps {
5
4
  selectedField: FieldMetadata | null;
6
5
  selectedOperator: FilterOperator | null;
@@ -10,12 +9,6 @@ interface UseBlurCommitDeps {
10
9
  handleCustomValueCommit: (text: string) => void;
11
10
  upsertCondition: UpsertCondition;
12
11
  resetState: () => void;
13
- /** Which triplet is being built: 0 = base, 1 = paired second. */
14
- buildingSide: 0 | 1;
15
- setBuildingSide: (side: 0 | 1) => void;
16
- /** Base triplet stashed while building a paired chip's second value. */
17
- buildingBase: BuildingBase | null;
18
- setBuildingBase: (base: BuildingBase | null) => void;
19
12
  /** Indirection ref breaking the useMenuFlow ↔ useBlurCommit cycle. */
20
13
  commitBuildingOnBlurRef: RefObject<() => boolean>;
21
14
  /** Same indirection for force-commit (area-click → incomplete becomes error). */
@@ -27,7 +20,7 @@ interface UseBlurCommitDeps {
27
20
  * editable. Re-entry-guarded: refs cleared synchronously so concurrent callers
28
21
  * (multiple onOpenChange + blur in one tick) don't create duplicate chips.
29
22
  */
30
- export declare const useBlurCommit: ({ selectedField, selectedOperator, inputText, editingChipId, effectiveInsertIndexRef, handleCustomValueCommit, upsertCondition, resetState, buildingSide, setBuildingSide, buildingBase, setBuildingBase, commitBuildingOnBlurRef, commitBuildingForceRef, }: UseBlurCommitDeps) => {
23
+ export declare const useBlurCommit: ({ selectedField, selectedOperator, inputText, editingChipId, effectiveInsertIndexRef, handleCustomValueCommit, upsertCondition, resetState, commitBuildingOnBlurRef, commitBuildingForceRef, }: UseBlurCommitDeps) => {
31
24
  commitBuildingOnBlur: () => boolean;
32
25
  hasIncompleteBuilding: () => boolean;
33
26
  };
@@ -1,34 +1,16 @@
1
1
  import { useCallback, useLayoutEffect, useRef } from "react";
2
2
  import { SEGMENT_VARIANT } from "../../FilterInputField/FilterInputChip/index.js";
3
3
  import { isBuildingComplete, isNoValueOperator } from "../../lib/index.js";
4
- const useBlurCommit = ({ selectedField, selectedOperator, inputText, editingChipId, effectiveInsertIndexRef, handleCustomValueCommit, upsertCondition, resetState, buildingSide, setBuildingSide, buildingBase, setBuildingBase, commitBuildingOnBlurRef, commitBuildingForceRef })=>{
4
+ const useBlurCommit = ({ selectedField, selectedOperator, inputText, editingChipId, effectiveInsertIndexRef, handleCustomValueCommit, upsertCondition, resetState, commitBuildingOnBlurRef, commitBuildingForceRef })=>{
5
5
  const selectedFieldRef = useRef(selectedField);
6
6
  const selectedOperatorRef = useRef(selectedOperator);
7
7
  const inputTextRef = useRef(inputText);
8
- const buildingSideRef = useRef(buildingSide);
9
- const buildingBaseRef = useRef(buildingBase);
10
8
  useLayoutEffect(()=>{
11
9
  selectedFieldRef.current = selectedField;
12
10
  selectedOperatorRef.current = selectedOperator;
13
11
  inputTextRef.current = inputText;
14
- buildingSideRef.current = buildingSide;
15
- buildingBaseRef.current = buildingBase;
16
12
  });
17
13
  const committingRef = useRef(false);
18
- const commitPairedBaseWithErroredValue = useCallback((base, field, operator)=>{
19
- upsertCondition(base.field, base.operator, base.value, null, effectiveInsertIndexRef.current);
20
- const pairError = operator ? SEGMENT_VARIANT.value : true;
21
- upsertCondition(field, operator ?? void 0, null, void 0, void 0, pairError, void 0, 1);
22
- setBuildingBase(null);
23
- setBuildingSide(0);
24
- resetState();
25
- }, [
26
- upsertCondition,
27
- resetState,
28
- effectiveInsertIndexRef,
29
- setBuildingBase,
30
- setBuildingSide
31
- ]);
32
14
  const commitBuildingOnBlur = useCallback(()=>{
33
15
  if (committingRef.current) return false;
34
16
  const field = selectedFieldRef.current;
@@ -37,19 +19,6 @@ const useBlurCommit = ({ selectedField, selectedOperator, inputText, editingChip
37
19
  if (!field) return false;
38
20
  if (editingChipId) return false;
39
21
  const hasTypedValue = !!operator && !isNoValueOperator(operator) && text.length > 0;
40
- if (!hasTypedValue && 1 === buildingSideRef.current && buildingBaseRef.current) {
41
- committingRef.current = true;
42
- try {
43
- const base = buildingBaseRef.current;
44
- selectedFieldRef.current = null;
45
- selectedOperatorRef.current = null;
46
- inputTextRef.current = '';
47
- commitPairedBaseWithErroredValue(base, field, operator);
48
- return true;
49
- } finally{
50
- committingRef.current = false;
51
- }
52
- }
53
22
  if (!isBuildingComplete(field, operator, null) && !hasTypedValue) return false;
54
23
  committingRef.current = true;
55
24
  try {
@@ -71,8 +40,7 @@ const useBlurCommit = ({ selectedField, selectedOperator, inputText, editingChip
71
40
  handleCustomValueCommit,
72
41
  upsertCondition,
73
42
  resetState,
74
- effectiveInsertIndexRef,
75
- commitPairedBaseWithErroredValue
43
+ effectiveInsertIndexRef
76
44
  ]);
77
45
  useLayoutEffect(()=>{
78
46
  commitBuildingOnBlurRef.current = commitBuildingOnBlur;
@@ -100,10 +68,6 @@ const useBlurCommit = ({ selectedField, selectedOperator, inputText, editingChip
100
68
  handleCustomValueCommit(text);
101
69
  return true;
102
70
  }
103
- if (1 === buildingSideRef.current && buildingBaseRef.current) {
104
- commitPairedBaseWithErroredValue(buildingBaseRef.current, field, operator);
105
- return true;
106
- }
107
71
  if (isBuildingComplete(field, operator, null)) {
108
72
  upsertCondition(field, operator, null, void 0, effectiveInsertIndexRef.current);
109
73
  resetState();
@@ -121,8 +85,7 @@ const useBlurCommit = ({ selectedField, selectedOperator, inputText, editingChip
121
85
  handleCustomValueCommit,
122
86
  upsertCondition,
123
87
  resetState,
124
- effectiveInsertIndexRef,
125
- commitPairedBaseWithErroredValue
88
+ effectiveInsertIndexRef
126
89
  ]);
127
90
  useLayoutEffect(()=>{
128
91
  commitBuildingForceRef.current = commitBuildingForce;
@@ -1,5 +1,4 @@
1
1
  import type { RefObject } from 'react';
2
- import { type ChipSegment } from '../../FilterInputField/FilterInputChip';
3
2
  import type { Condition, FieldMetadata, FilterInputChipData, UpsertCondition } from '../../types';
4
3
  interface UseFilterInputAutocompleteOptions {
5
4
  fields: FieldMetadata[];
@@ -50,10 +49,10 @@ export declare const useFilterInputAutocomplete: ({ fields, conditions, chips, u
50
49
  handleMenuDiscard: () => void;
51
50
  /** Hard reset for paste/clipboard flows — scraps in-progress building. */
52
51
  resetAutocompleteState: (continueBuilding?: boolean) => void;
53
- handleChipClick: (chipId: string, segment: ChipSegment, anchorEl: HTMLElement) => void;
54
- handlePairChipClick: (chipId: string, segment: ChipSegment, anchorEl: HTMLElement) => void;
55
- handleBuildingChipClick: (segment: ChipSegment, anchorEl: HTMLElement) => void;
56
- switchEditSegment: (targetSegment: ChipSegment) => boolean;
52
+ handleChipClick: (chipId: string, segment: import("../../FilterInputField").ChipSegment, anchorEl: HTMLElement) => void;
53
+ handlePairChipClick: (chipId: string, segment: import("../../FilterInputField").ChipSegment, anchorEl: HTMLElement) => void;
54
+ handleBuildingChipClick: (segment: import("../../FilterInputField").ChipSegment, anchorEl: HTMLElement) => void;
55
+ switchEditSegment: (targetSegment: import("../../FilterInputField").ChipSegment) => boolean;
57
56
  removeEditingChip: () => void;
58
57
  handleConnectorChange: (connectorId: string, value: "and" | "or") => void;
59
58
  handleChipRemove: (chipId: string) => void;
@@ -1,4 +1,3 @@
1
- import { useCallback } from "react";
2
1
  import { SEGMENT_VARIANT } from "../../FilterInputField/FilterInputChip/index.js";
3
2
  import { useDateRange } from "../../FilterInputMenu/FilterInputDateValueMenu/hooks.js";
4
3
  import { deriveAutocompleteValues } from "./lib/index.js";
@@ -12,7 +11,6 @@ import { useInputHandlers } from "./useInputHandlers.js";
12
11
  import { useMenuFlow } from "./useMenuFlow/index.js";
13
12
  import { useMenuPositioning } from "./useMenuPositioning.js";
14
13
  import { useResetState } from "./useResetState.js";
15
- import { useResumeBuilding } from "./useResumeBuilding.js";
16
14
  import { useSegmentEditFlow } from "./useSegmentEditFlow.js";
17
15
  const useFilterInputAutocomplete = ({ fields, conditions, chips, upsertCondition, removeCondition, removeConditionAtIndex, clearAll, setConnectorValue, containerRef, buildingChipRef, inputRef })=>{
18
16
  const state = useAutocompleteState({
@@ -125,10 +123,6 @@ const useFilterInputAutocomplete = ({ fields, conditions, chips, upsertCondition
125
123
  handleCustomValueCommit,
126
124
  upsertCondition,
127
125
  resetState,
128
- buildingSide,
129
- setBuildingSide,
130
- buildingBase,
131
- setBuildingBase,
132
126
  commitBuildingOnBlurRef,
133
127
  commitBuildingForceRef
134
128
  });
@@ -176,36 +170,6 @@ const useFilterInputAutocomplete = ({ fields, conditions, chips, upsertCondition
176
170
  setMenuState,
177
171
  setMenuAnchor
178
172
  });
179
- const tryResumeBuilding = useResumeBuilding({
180
- conditions,
181
- fields,
182
- removeConditionAtIndex,
183
- setInsertIndex,
184
- setBuildingBase,
185
- setBuildingSide,
186
- setSelectedField,
187
- setSelectedOperator,
188
- setBuildingMultiValue,
189
- setInputText,
190
- setMenuState,
191
- resetMenuAnchor,
192
- clearEditing: editing.clearEditing,
193
- inputRef
194
- });
195
- const handleChipClick = useCallback((chipId, segment, anchorEl)=>{
196
- if (tryResumeBuilding(chipId)) return;
197
- editing.handleChipClick(chipId, segment, anchorEl);
198
- }, [
199
- tryResumeBuilding,
200
- editing.handleChipClick
201
- ]);
202
- const handlePairChipClick = useCallback((chipId, segment, anchorEl)=>{
203
- if (tryResumeBuilding(chipId)) return;
204
- editing.handlePairChipClick(chipId, segment, anchorEl);
205
- }, [
206
- tryResumeBuilding,
207
- editing.handlePairChipClick
208
- ]);
209
173
  const { isBuilding, buildingChipData, editingMultiValues, editingSingleValue, editingDateRange } = deriveAutocompleteValues({
210
174
  editingChipId: editing.editingChipId,
211
175
  selectedField,
@@ -240,8 +204,8 @@ const useFilterInputAutocomplete = ({ fields, conditions, chips, upsertCondition
240
204
  handleMenuClose,
241
205
  handleMenuDiscard,
242
206
  resetAutocompleteState: resetState,
243
- handleChipClick,
244
- handlePairChipClick,
207
+ handleChipClick: editing.handleChipClick,
208
+ handlePairChipClick: editing.handlePairChipClick,
245
209
  handleBuildingChipClick,
246
210
  switchEditSegment,
247
211
  removeEditingChip,
@@ -1,5 +1,5 @@
1
1
  import { SEGMENT_VARIANT } from "../../FilterInputField/FilterInputChip/index.js";
2
- import { NO_VALUE_PLACEHOLDER, canBorrowCrossFieldLabel, findOptionByValue, findValueLabelInFields, getDateDisplayLabel, getInvalidValueIndices, getOperatorLabel, incompleteTripletError, isEmptyFilterValue, isNoValueOperator } from "../../lib/index.js";
2
+ import { NO_VALUE_PLACEHOLDER, canBorrowCrossFieldLabel, findOptionByValue, findValueLabelInFields, getDateDisplayLabel, getInvalidValueIndices, getOperatorLabel, isNoValueOperator } from "../../lib/index.js";
3
3
  const INVALID_DATE = 'Invalid Date';
4
4
  const DATE_RANGE_SEPARATOR = ' – ';
5
5
  const MULTI_VALUE_SEPARATOR = ', ';
@@ -84,35 +84,23 @@ const buildMultiValueChip = (baseChip, condition, field, fields, chipError)=>{
84
84
  };
85
85
  };
86
86
  const buildPairChip = (condition, field, fields)=>{
87
- if (!field?.pairedField) return;
88
- if (null != condition.operator && isNoValueOperator(condition.operator)) return;
87
+ if (!condition.pair || !field?.pairedField) return;
89
88
  const pf = field.pairedField;
90
- if (!condition.pair) {
91
- const baseComplete = null != condition.operator && !isEmptyFilterValue(condition.value);
92
- if (!baseComplete) return;
93
- return {
94
- attribute: pf.label || pf.name,
95
- value: '',
96
- error: SEGMENT_VARIANT.value
97
- };
98
- }
99
89
  const { operator, value, error } = condition.pair;
100
90
  const displayValue = operator && isNoValueOperator(operator) ? NO_VALUE_PLACEHOLDER : resolveValueLabel(value, pf, fields) ?? String(value ?? '');
101
- const valueRequiredButMissing = !(operator && isNoValueOperator(operator)) && isEmptyFilterValue(value);
102
- const pairError = error || (valueRequiredButMissing ? SEGMENT_VARIANT.value : void 0);
103
91
  return {
104
92
  attribute: pf.label || pf.name,
105
93
  operator: operator ? getOperatorLabel(operator, pf.type || DEFAULT_FIELD_TYPE) : void 0,
106
94
  value: displayValue,
107
- ...pairError && {
108
- error: pairError
95
+ ...error && {
96
+ error
109
97
  }
110
98
  };
111
99
  };
112
100
  const makeConditionChipBase = (i, conditions, fields, error)=>{
113
101
  const condition = conditions[i];
114
102
  if (!condition) return makeEmptyChip(i, error);
115
- const chipError = condition.error || (error ? true : void 0) || incompleteTripletError(condition.operator, condition.value);
103
+ const chipError = condition.error || (error ? true : void 0);
116
104
  const field = fields.find((f)=>f.name === condition.field);
117
105
  const baseChip = buildBaseChip(i, condition, field);
118
106
  if (condition.operator && isNoValueOperator(condition.operator)) return {
@@ -155,11 +155,6 @@ const useFilterInputExpression = ({ fields, value, onChange, error, externalErro
155
155
  return;
156
156
  }
157
157
  const condition = buildCondition(field, operator, val, error, dateOrigin);
158
- if (editingChipId) {
159
- const idx = chipIdToConditionIndex(editingChipId);
160
- const prevCondition = null !== idx ? prev.conditions[idx] : void 0;
161
- if (prevCondition?.pair && prevCondition.field === condition.field) condition.pair = prevCondition.pair;
162
- }
163
158
  const newConditions = applyCondition(prev.conditions, condition, editingChipId, atIndex);
164
159
  const newConnectors = addConnectorIfNeeded(prev.connectors, newConditions.length, editingChipId, atIndex, prev.conditions.length);
165
160
  applyState({
@@ -1,14 +1,6 @@
1
- import type { ChipErrorSegment, Condition, FilterInputChipData, FilterOperator } from '../types';
1
+ import type { FilterInputChipData } from '../types';
2
2
  /** Map a chip ID (e.g. "chip-2") back to condition index */
3
3
  export declare const chipIdToConditionIndex: (chipId: string) => number | null;
4
- /** A filter value is empty when null/undefined, '', or an empty array. */
5
- export declare const isEmptyFilterValue: (value: Condition["value"] | undefined) => boolean;
6
- /**
7
- * Error segment for an incomplete triplet, or `undefined` when complete:
8
- * missing operator → whole triplet (`true`); value-bearing operator with an
9
- * empty value → the value segment; no-value operator ("is set") → complete.
10
- */
11
- export declare const incompleteTripletError: (operator: FilterOperator | null | undefined, value: Condition["value"] | undefined) => ChipErrorSegment | undefined;
12
4
  /**
13
5
  * Convert a condition-level insert index to a position in the chips array.
14
6
  * When `afterConnector` is true, split AFTER the connector preceding the target chip.
@@ -1,12 +1,8 @@
1
- import { SEGMENT_VARIANT } from "../FilterInputField/FilterInputChip/segmentVariant.js";
2
1
  import { CHIP_ID_PATTERN } from "./constants.js";
3
- import { isNoValueOperator } from "./operators.js";
4
2
  const chipIdToConditionIndex = (chipId)=>{
5
3
  const match = chipId.match(CHIP_ID_PATTERN);
6
4
  return match ? Number(match[1]) : null;
7
5
  };
8
- const isEmptyFilterValue = (value)=>null == value || '' === value || Array.isArray(value) && 0 === value.length;
9
- const incompleteTripletError = (operator, value)=>operator ? isNoValueOperator(operator) ? void 0 : isEmptyFilterValue(value) ? SEGMENT_VARIANT.value : void 0 : true;
10
6
  const findChipSplitIndex = (chips, conditionInsertIndex, afterConnector = false)=>{
11
7
  let conditionCount = 0;
12
8
  for(let i = 0; i < chips.length; i++)if ('chip' === chips[i].variant) {
@@ -19,4 +15,4 @@ const findChipSplitIndex = (chips, conditionInsertIndex, afterConnector = false)
19
15
  }
20
16
  return chips.length;
21
17
  };
22
- export { chipIdToConditionIndex, findChipSplitIndex, incompleteTripletError, isEmptyFilterValue };
18
+ export { chipIdToConditionIndex, findChipSplitIndex };
@@ -3,7 +3,7 @@ export { DATE_PRESETS, formatDateForChip, getDateDisplayLabel, isDatePreset, } f
3
3
  export { applyAcceptChar } from './applyAcceptChar';
4
4
  export { applyFieldValueTransforms } from './applyFieldValueTransforms';
5
5
  export { applyKnownFieldHelpers, getKnownFieldSerializer } from './applyKnownFieldHelpers';
6
- export { chipIdToConditionIndex, findChipSplitIndex, incompleteTripletError, isEmptyFilterValue, } from './conditions';
6
+ export { chipIdToConditionIndex, findChipSplitIndex } from './conditions';
7
7
  export { CONNECTOR_ID_PATTERN, MENU_BASE_GUTTER, MENU_CHIP_GUTTER_OFFSET, NO_VALUE_OPERATORS, OPERATOR_LABELS, OPERATOR_LABELS_BY_TYPE, OPERATOR_SYMBOLS, OPERATORS_BY_TYPE, QUERY_BAR_SELECTOR, VARIANT_LABELS, } from './constants';
8
8
  export { COUNTRY_OPTIONS } from './country';
9
9
  export { type AnchorBounds, buildAnchoredRect, isMenuRelated, toAnchorBounds } from './dom';
@@ -2,7 +2,7 @@ import { DATE_PRESETS, formatDateForChip, getDateDisplayLabel, isDatePreset } fr
2
2
  import { applyAcceptChar } from "./applyAcceptChar.js";
3
3
  import { applyFieldValueTransforms } from "./applyFieldValueTransforms.js";
4
4
  import { applyKnownFieldHelpers, getKnownFieldSerializer } from "./applyKnownFieldHelpers.js";
5
- import { chipIdToConditionIndex, findChipSplitIndex, incompleteTripletError, isEmptyFilterValue } from "./conditions.js";
5
+ import { chipIdToConditionIndex, findChipSplitIndex } from "./conditions.js";
6
6
  import { CONNECTOR_ID_PATTERN, MENU_BASE_GUTTER, MENU_CHIP_GUTTER_OFFSET, NO_VALUE_OPERATORS, OPERATORS_BY_TYPE, OPERATOR_LABELS, OPERATOR_LABELS_BY_TYPE, OPERATOR_SYMBOLS, QUERY_BAR_SELECTOR, VARIANT_LABELS } from "./constants.js";
7
7
  import { COUNTRY_OPTIONS } from "./country/index.js";
8
8
  import { buildAnchoredRect, isMenuRelated, toAnchorBounds } from "./dom.js";
@@ -15,4 +15,4 @@ import { SEGMENT_TO_MENU } from "./segmentMenu.js";
15
15
  import { serializeExpression } from "./serializeExpression.js";
16
16
  import { createStatusCodeInputFilter, createStatusCodeNormalizer, createStatusCodeSerializer, createStatusCodeSuggestions, createStatusCodeValidator } from "./statusCode/index.js";
17
17
  import { canBorrowCrossFieldLabel, findMatchingFieldValue, getInvalidValueIndices, isValidFieldValue, validateValueForField } from "./validation.js";
18
- export { CONNECTOR_ID_PATTERN, COUNTRY_OPTIONS, DATE_PRESETS, MENU_BASE_GUTTER, MENU_CHIP_GUTTER_OFFSET, NO_VALUE_OPERATORS, NO_VALUE_PLACEHOLDER, OPERATORS_BY_TYPE, OPERATOR_LABELS, OPERATOR_LABELS_BY_TYPE, OPERATOR_SYMBOLS, QUERY_BAR_SELECTOR, SEGMENT_TO_MENU, VARIANT_LABELS, applyAcceptChar, applyFieldValueTransforms, applyKnownFieldHelpers, buildAnchoredRect, canBorrowCrossFieldLabel, chipIdToConditionIndex, createStatusCodeInputFilter, createStatusCodeNormalizer, createStatusCodeSerializer, createStatusCodeSuggestions, createStatusCodeValidator, filterAndSort, findChipSplitIndex, findMatchingFieldValue, findOptionByValue, findValueLabelInFields, formatDateForChip, getCurrentValueTokenText, getDateDisplayLabel, getFieldOperators, getFieldValues, getInvalidValueIndices, getKnownFieldSerializer, getOperatorFromLabel, getOperatorLabel, getValueFilterText, hasFieldValues, hasStaticAllowlist, incompleteTripletError, isBetweenOperator, isBuildingComplete, isDatePreset, isEmptyFilterValue, isFilterParseError, isMenuRelated, isMultiSelectOperator, isNoValueOperator, isOperatorAllowedForField, isValidFieldValue, isValueShapeCompatible, nextBuildingMenu, parseExpression, serializeExpression, toAnchorBounds, validateValueForField };
18
+ export { CONNECTOR_ID_PATTERN, COUNTRY_OPTIONS, DATE_PRESETS, MENU_BASE_GUTTER, MENU_CHIP_GUTTER_OFFSET, NO_VALUE_OPERATORS, NO_VALUE_PLACEHOLDER, OPERATORS_BY_TYPE, OPERATOR_LABELS, OPERATOR_LABELS_BY_TYPE, OPERATOR_SYMBOLS, QUERY_BAR_SELECTOR, SEGMENT_TO_MENU, VARIANT_LABELS, applyAcceptChar, applyFieldValueTransforms, applyKnownFieldHelpers, buildAnchoredRect, canBorrowCrossFieldLabel, chipIdToConditionIndex, createStatusCodeInputFilter, createStatusCodeNormalizer, createStatusCodeSerializer, createStatusCodeSuggestions, createStatusCodeValidator, filterAndSort, findChipSplitIndex, findMatchingFieldValue, findOptionByValue, findValueLabelInFields, formatDateForChip, getCurrentValueTokenText, getDateDisplayLabel, getFieldOperators, getFieldValues, getInvalidValueIndices, getKnownFieldSerializer, getOperatorFromLabel, getOperatorLabel, getValueFilterText, hasFieldValues, hasStaticAllowlist, isBetweenOperator, isBuildingComplete, isDatePreset, isFilterParseError, isMenuRelated, isMultiSelectOperator, isNoValueOperator, isOperatorAllowedForField, isValidFieldValue, isValueShapeCompatible, nextBuildingMenu, parseExpression, serializeExpression, toAnchorBounds, validateValueForField };
@@ -59,14 +59,6 @@ export interface FieldValueOption {
59
59
  color: BadgeColor;
60
60
  text: string;
61
61
  };
62
- /**
63
- * Optional secondary text rendered as a muted line beneath the bold `label`
64
- * in the value dropdown (e.g. a backend path that explains or disambiguates
65
- * the option). Display-only — never committed as a filter value. Because the
66
- * bold `label` need not be unique, this line is what distinguishes rows that
67
- * share a label (two `request-id` rows with different paths).
68
- */
69
- description?: string;
70
62
  }
71
63
  /**
72
64
  * Field Metadata Interface
@@ -0,0 +1,34 @@
1
+ import { type FC, type ReactNode, type Ref } from 'react';
2
+ import { Slider as ArkSlider } from '@ark-ui/react/slider';
3
+ import { type TestableProps } from '../../utils/testId';
4
+ /** Ark/Zag machine-config props forwarded to the headless `Slider.Root`. */
5
+ type SliderRootConfig = Pick<ArkSlider.RootProps, 'value' | 'defaultValue' | 'min' | 'max' | 'step' | 'disabled' | 'readOnly' | 'getAriaValueText' | 'name' | 'form' | 'minStepsBetweenThumbs' | 'thumbCollisionBehavior'>;
6
+ export interface SliderProps extends SliderRootConfig, TestableProps {
7
+ /** Error state → maps to Ark `invalid` (repaints the handle; the message is the Field's job). */
8
+ error?: boolean;
9
+ className?: string;
10
+ children?: ReactNode;
11
+ /** Fires live during drag with the current value array (`[n]` single, `[low, high]` range). */
12
+ onValueChange?: (value: number[]) => void;
13
+ /** Fires once on drag release with the committed value array. */
14
+ onValueChangeEnd?: (value: number[]) => void;
15
+ /** Ref to the Ark Slider root element. */
16
+ ref?: Ref<HTMLDivElement>;
17
+ }
18
+ /**
19
+ * Slider — pick an approximate, bounded value (or range) by dragging a handle along
20
+ * a track. Built on `@ark-ui/react/slider`.
21
+ *
22
+ * Compose the parts: `SliderControl` (renders the track + range) holds one
23
+ * `SliderThumb` per thumb (the real `role="slider"` node — consumer `data-*` /
24
+ * analytics / `ref` land there) and an optional `SliderMarks`. `SliderInput` and
25
+ * `SliderValue` are optional readouts. Single vs range is driven by the length of
26
+ * `value` / `defaultValue` — render one `SliderThumb` per entry. Thumbs never cross
27
+ * (`thumbCollisionBehavior` defaults to `'none'`); set `minStepsBetweenThumbs` for a gap.
28
+ *
29
+ * It reads `Field` context like `Input`/`Textarea`, so wrapping it in `<Field>` wires
30
+ * label / invalid / disabled. When an exact figure matters, pair with `NumberInput`;
31
+ * for 2–7 fixed options use `SegmentedControl`. See `docs/slider-design-spec.md`.
32
+ */
33
+ export declare const Slider: FC<SliderProps>;
34
+ export {};
@@ -0,0 +1 @@
1
+ export {};