@choice-ui/react 1.9.6 → 1.9.7

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.
@@ -51,6 +51,7 @@ interface NumericInputContextValue {
51
51
  max?: number;
52
52
  min?: number;
53
53
  onChange?: (value: NumericInputValue, detail: NumericChangeDetail) => void;
54
+ onChangeEnd?: (value: NumericInputValue, detail: NumericChangeDetail) => void;
54
55
  onEmpty?: () => void;
55
56
  onIsEditingChange?: (isEditing: boolean) => void;
56
57
  onPressEnd?: PressMoveProps["onPressEnd"];
@@ -74,6 +75,7 @@ interface NumericInputProps extends NumericInputContextValue, Omit<HTMLProps<HTM
74
75
  disabled?: boolean;
75
76
  id?: string;
76
77
  onChange?: (value: NumericInputValue, detail: NumericChangeDetail) => void;
78
+ onChangeEnd?: (value: NumericInputValue, detail: NumericChangeDetail) => void;
77
79
  tooltip?: TooltipProps;
78
80
  triggerRef?: React__default.RefObject<HTMLDivElement> | ((el: HTMLDivElement | null) => void);
79
81
  }
@@ -1,5 +1,5 @@
1
1
  import { Tooltip } from "../../tooltip/dist/index.js";
2
- import { forwardRef, useRef, useState, useMemo, createContext, cloneElement, memo, useEffect, useCallback, Children, isValidElement, useContext } from "react";
2
+ import { forwardRef, useRef, useState, useMemo, createContext, cloneElement, memo, useCallback, useEffect, Children, isValidElement, useContext } from "react";
3
3
  import { useEventCallback } from "usehooks-ts";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
5
  import { IconButton } from "../../icon-button/dist/index.js";
@@ -919,11 +919,15 @@ function useNumericInput(props) {
919
919
  step = 1,
920
920
  value,
921
921
  onChange,
922
+ onChangeEnd,
922
923
  onEmpty,
923
924
  onPressEnd,
924
925
  onPressStart
925
926
  } = props;
926
927
  const innerRef = useRef(null);
928
+ const dragHasChangedRef = useRef(false);
929
+ const dragEndValueRef = useRef(void 0);
930
+ const dragEndDetailRef = useRef(void 0);
927
931
  const [isFocused, setIsFocused] = useState(false);
928
932
  const [displayValue, setDisplayValue] = useState("");
929
933
  const { shiftPressed, metaPressed } = useModifierKeys(disabled);
@@ -941,6 +945,10 @@ function useNumericInput(props) {
941
945
  defaultValue: defaultValuePre,
942
946
  allowEmpty: true
943
947
  });
948
+ const mapResultToOutputValue = useCallback(
949
+ (result) => typeof value === "string" ? result.string : typeof value === "number" ? result.array[0] : Array.isArray(value) ? result.array : result.object,
950
+ [value]
951
+ );
944
952
  useEffect(() => {
945
953
  if (!innerValue) {
946
954
  setDisplayValue("");
@@ -959,7 +967,7 @@ function useNumericInput(props) {
959
967
  setDisplayValue(valuePre2.string);
960
968
  }, [innerValue, expression, max, min, decimal, setValue]);
961
969
  const updateValue = useCallback(
962
- (updateFn) => {
970
+ (updateFn, options) => {
963
971
  if (disabled || readOnly) return;
964
972
  setValue((prev) => {
965
973
  if (!prev) {
@@ -971,10 +979,13 @@ function useNumericInput(props) {
971
979
  min,
972
980
  decimal
973
981
  });
974
- onChange == null ? void 0 : onChange(
975
- typeof value === "string" ? initialValue.string : typeof value === "number" ? initialValue.array[0] : Array.isArray(value) ? initialValue.array : initialValue.object,
976
- initialValue
977
- );
982
+ const nextValue = mapResultToOutputValue(initialValue);
983
+ onChange == null ? void 0 : onChange(nextValue, initialValue);
984
+ if ((options == null ? void 0 : options.source) === "drag") {
985
+ dragHasChangedRef.current = true;
986
+ dragEndValueRef.current = nextValue;
987
+ dragEndDetailRef.current = initialValue;
988
+ }
978
989
  return initialValue;
979
990
  }
980
991
  const valuePre2 = dealWithNumericInputValue({
@@ -998,15 +1009,18 @@ function useNumericInput(props) {
998
1009
  return true;
999
1010
  })();
1000
1011
  if (hasChanged) {
1001
- onChange == null ? void 0 : onChange(
1002
- typeof value === "string" ? valuePre2.string : typeof value === "number" ? valuePre2.array[0] : Array.isArray(value) ? valuePre2.array : valuePre2.object,
1003
- valuePre2
1004
- );
1012
+ const nextValue = mapResultToOutputValue(valuePre2);
1013
+ onChange == null ? void 0 : onChange(nextValue, valuePre2);
1014
+ if ((options == null ? void 0 : options.source) === "drag") {
1015
+ dragHasChangedRef.current = true;
1016
+ dragEndValueRef.current = nextValue;
1017
+ dragEndDetailRef.current = valuePre2;
1018
+ }
1005
1019
  }
1006
1020
  return valuePre2;
1007
1021
  });
1008
1022
  },
1009
- [disabled, readOnly, setValue, max, min, decimal, onChange, value]
1023
+ [disabled, readOnly, setValue, max, min, decimal, onChange, expressionRef, mapResultToOutputValue]
1010
1024
  );
1011
1025
  const { inputHandlers } = useInputInteractions({
1012
1026
  inputRef: innerRef,
@@ -1031,6 +1045,9 @@ function useNumericInput(props) {
1031
1045
  const { isPressed: handlerPressed, pressMoveProps } = usePressMove({
1032
1046
  disabled,
1033
1047
  onPressStart: (e) => {
1048
+ dragHasChangedRef.current = false;
1049
+ dragEndValueRef.current = void 0;
1050
+ dragEndDetailRef.current = void 0;
1034
1051
  const wasFocused = isFocused;
1035
1052
  if (onPressStart && "nativeEvent" in e) {
1036
1053
  onPressStart(e.nativeEvent);
@@ -1056,12 +1073,18 @@ function useNumericInput(props) {
1056
1073
  onPressEnd(e.nativeEvent);
1057
1074
  }
1058
1075
  onPressEnd == null ? void 0 : onPressEnd(e);
1076
+ if (dragHasChangedRef.current && dragEndValueRef.current !== void 0 && dragEndDetailRef.current !== void 0) {
1077
+ onChangeEnd == null ? void 0 : onChangeEnd(dragEndValueRef.current, dragEndDetailRef.current);
1078
+ }
1079
+ dragHasChangedRef.current = false;
1080
+ dragEndValueRef.current = void 0;
1081
+ dragEndDetailRef.current = void 0;
1059
1082
  },
1060
1083
  onPressMoveLeft: (delta) => {
1061
- updateValue((value2) => value2 - delta * getCurrentStep());
1084
+ updateValue((value2) => value2 - delta * getCurrentStep(), { source: "drag" });
1062
1085
  },
1063
1086
  onPressMoveRight: (delta) => {
1064
- updateValue((value2) => value2 + delta * getCurrentStep());
1087
+ updateValue((value2) => value2 + delta * getCurrentStep(), { source: "drag" });
1065
1088
  }
1066
1089
  });
1067
1090
  const inputProps = {
@@ -1104,6 +1127,7 @@ var NumericInputBase = forwardRef((props, ref) => {
1104
1127
  selected = false,
1105
1128
  tooltip,
1106
1129
  onChange,
1130
+ onChangeEnd,
1107
1131
  onEmpty,
1108
1132
  onPressEnd,
1109
1133
  onPressStart,
@@ -1127,6 +1151,7 @@ var NumericInputBase = forwardRef((props, ref) => {
1127
1151
  step,
1128
1152
  value,
1129
1153
  onChange,
1154
+ onChangeEnd,
1130
1155
  onEmpty,
1131
1156
  onPressEnd,
1132
1157
  onPressStart,
@@ -1167,6 +1192,7 @@ var NumericInputBase = forwardRef((props, ref) => {
1167
1192
  expression,
1168
1193
  // Event handling methods
1169
1194
  onChange,
1195
+ onChangeEnd,
1170
1196
  onEmpty,
1171
1197
  onPressStart,
1172
1198
  onPressEnd,
@@ -1191,6 +1217,7 @@ var NumericInputBase = forwardRef((props, ref) => {
1191
1217
  decimal,
1192
1218
  expression,
1193
1219
  onChange,
1220
+ onChangeEnd,
1194
1221
  onEmpty,
1195
1222
  onPressStart,
1196
1223
  onPressEnd,
@@ -11,6 +11,7 @@ export interface NumericInputContextValue {
11
11
  max?: number;
12
12
  min?: number;
13
13
  onChange?: (value: NumericInputValue, detail: NumericChangeDetail) => void;
14
+ onChangeEnd?: (value: NumericInputValue, detail: NumericChangeDetail) => void;
14
15
  onEmpty?: () => void;
15
16
  onIsEditingChange?: (isEditing: boolean) => void;
16
17
  onPressEnd?: PressMoveProps["onPressEnd"];
@@ -17,7 +17,9 @@ interface UseInputInteractionsProps<T extends NumericInputValue> {
17
17
  setDisplayValue: (value: string) => void;
18
18
  setIsFocused: (focused: boolean) => void;
19
19
  setValue: (value: NumberResult | ((prev: NumberResult | undefined) => NumberResult)) => void;
20
- updateValue: (updateFn?: (value: number) => number) => void;
20
+ updateValue: (updateFn?: (value: number) => number, options?: {
21
+ source?: "drag" | "keyboard";
22
+ }) => void;
21
23
  value?: T;
22
24
  }
23
25
  /**
@@ -10,6 +10,7 @@ interface UseNumericInputProps<T extends NumericInputValue> extends Omit<HTMLPro
10
10
  max?: number;
11
11
  min?: number;
12
12
  onChange?: (value: T, obj: NumberResult) => void;
13
+ onChangeEnd?: (value: T, obj: NumberResult) => void;
13
14
  onEmpty?: () => void;
14
15
  onPressEnd?: PressMoveProps["onPressEnd"];
15
16
  onPressStart?: PressMoveProps["onPressStart"];
@@ -1,4 +1,4 @@
1
- import { useRef, useState, useEffect, useCallback } from "react";
1
+ import { useRef, useState, useCallback, useEffect } from "react";
2
2
  import { dealWithNumericInputValue } from "../utils/numeric-value-processor.js";
3
3
  import { useInputInteractions } from "./use-input-interactions.js";
4
4
  import { useNumericValueProcessing } from "./use-numeric-value-processing.js";
@@ -21,11 +21,15 @@ function useNumericInput(props) {
21
21
  step = 1,
22
22
  value,
23
23
  onChange,
24
+ onChangeEnd,
24
25
  onEmpty,
25
26
  onPressEnd,
26
27
  onPressStart
27
28
  } = props;
28
29
  const innerRef = useRef(null);
30
+ const dragHasChangedRef = useRef(false);
31
+ const dragEndValueRef = useRef(void 0);
32
+ const dragEndDetailRef = useRef(void 0);
29
33
  const [isFocused, setIsFocused] = useState(false);
30
34
  const [displayValue, setDisplayValue] = useState("");
31
35
  const { shiftPressed, metaPressed } = useModifierKeys(disabled);
@@ -43,6 +47,10 @@ function useNumericInput(props) {
43
47
  defaultValue: defaultValuePre,
44
48
  allowEmpty: true
45
49
  });
50
+ const mapResultToOutputValue = useCallback(
51
+ (result) => typeof value === "string" ? result.string : typeof value === "number" ? result.array[0] : Array.isArray(value) ? result.array : result.object,
52
+ [value]
53
+ );
46
54
  useEffect(() => {
47
55
  if (!innerValue) {
48
56
  setDisplayValue("");
@@ -61,7 +69,7 @@ function useNumericInput(props) {
61
69
  setDisplayValue(valuePre2.string);
62
70
  }, [innerValue, expression, max, min, decimal, setValue]);
63
71
  const updateValue = useCallback(
64
- (updateFn) => {
72
+ (updateFn, options) => {
65
73
  if (disabled || readOnly) return;
66
74
  setValue((prev) => {
67
75
  if (!prev) {
@@ -73,10 +81,13 @@ function useNumericInput(props) {
73
81
  min,
74
82
  decimal
75
83
  });
76
- onChange == null ? void 0 : onChange(
77
- typeof value === "string" ? initialValue.string : typeof value === "number" ? initialValue.array[0] : Array.isArray(value) ? initialValue.array : initialValue.object,
78
- initialValue
79
- );
84
+ const nextValue = mapResultToOutputValue(initialValue);
85
+ onChange == null ? void 0 : onChange(nextValue, initialValue);
86
+ if ((options == null ? void 0 : options.source) === "drag") {
87
+ dragHasChangedRef.current = true;
88
+ dragEndValueRef.current = nextValue;
89
+ dragEndDetailRef.current = initialValue;
90
+ }
80
91
  return initialValue;
81
92
  }
82
93
  const valuePre2 = dealWithNumericInputValue({
@@ -100,15 +111,18 @@ function useNumericInput(props) {
100
111
  return true;
101
112
  })();
102
113
  if (hasChanged) {
103
- onChange == null ? void 0 : onChange(
104
- typeof value === "string" ? valuePre2.string : typeof value === "number" ? valuePre2.array[0] : Array.isArray(value) ? valuePre2.array : valuePre2.object,
105
- valuePre2
106
- );
114
+ const nextValue = mapResultToOutputValue(valuePre2);
115
+ onChange == null ? void 0 : onChange(nextValue, valuePre2);
116
+ if ((options == null ? void 0 : options.source) === "drag") {
117
+ dragHasChangedRef.current = true;
118
+ dragEndValueRef.current = nextValue;
119
+ dragEndDetailRef.current = valuePre2;
120
+ }
107
121
  }
108
122
  return valuePre2;
109
123
  });
110
124
  },
111
- [disabled, readOnly, setValue, max, min, decimal, onChange, value]
125
+ [disabled, readOnly, setValue, max, min, decimal, onChange, expressionRef, mapResultToOutputValue]
112
126
  );
113
127
  const { inputHandlers } = useInputInteractions({
114
128
  inputRef: innerRef,
@@ -133,6 +147,9 @@ function useNumericInput(props) {
133
147
  const { isPressed: handlerPressed, pressMoveProps } = usePressMove({
134
148
  disabled,
135
149
  onPressStart: (e) => {
150
+ dragHasChangedRef.current = false;
151
+ dragEndValueRef.current = void 0;
152
+ dragEndDetailRef.current = void 0;
136
153
  const wasFocused = isFocused;
137
154
  if (onPressStart && "nativeEvent" in e) {
138
155
  onPressStart(e.nativeEvent);
@@ -158,12 +175,18 @@ function useNumericInput(props) {
158
175
  onPressEnd(e.nativeEvent);
159
176
  }
160
177
  onPressEnd == null ? void 0 : onPressEnd(e);
178
+ if (dragHasChangedRef.current && dragEndValueRef.current !== void 0 && dragEndDetailRef.current !== void 0) {
179
+ onChangeEnd == null ? void 0 : onChangeEnd(dragEndValueRef.current, dragEndDetailRef.current);
180
+ }
181
+ dragHasChangedRef.current = false;
182
+ dragEndValueRef.current = void 0;
183
+ dragEndDetailRef.current = void 0;
161
184
  },
162
185
  onPressMoveLeft: (delta) => {
163
- updateValue((value2) => value2 - delta * getCurrentStep());
186
+ updateValue((value2) => value2 - delta * getCurrentStep(), { source: "drag" });
164
187
  },
165
188
  onPressMoveRight: (delta) => {
166
- updateValue((value2) => value2 + delta * getCurrentStep());
189
+ updateValue((value2) => value2 + delta * getCurrentStep(), { source: "drag" });
167
190
  }
168
191
  });
169
192
  const inputProps = {
@@ -13,6 +13,7 @@ export interface NumericInputProps extends NumericInputContextValue, Omit<HTMLPr
13
13
  disabled?: boolean;
14
14
  id?: string;
15
15
  onChange?: (value: NumericInputValue, detail: NumericChangeDetail) => void;
16
+ onChangeEnd?: (value: NumericInputValue, detail: NumericChangeDetail) => void;
16
17
  tooltip?: TooltipProps;
17
18
  triggerRef?: React.RefObject<HTMLDivElement> | ((el: HTMLDivElement | null) => void);
18
19
  }
@@ -35,6 +35,7 @@ const NumericInputBase = forwardRef((props, ref) => {
35
35
  selected = false,
36
36
  tooltip,
37
37
  onChange,
38
+ onChangeEnd,
38
39
  onEmpty,
39
40
  onPressEnd,
40
41
  onPressStart,
@@ -58,6 +59,7 @@ const NumericInputBase = forwardRef((props, ref) => {
58
59
  step,
59
60
  value,
60
61
  onChange,
62
+ onChangeEnd,
61
63
  onEmpty,
62
64
  onPressEnd,
63
65
  onPressStart,
@@ -98,6 +100,7 @@ const NumericInputBase = forwardRef((props, ref) => {
98
100
  expression,
99
101
  // Event handling methods
100
102
  onChange,
103
+ onChangeEnd,
101
104
  onEmpty,
102
105
  onPressStart,
103
106
  onPressEnd,
@@ -122,6 +125,7 @@ const NumericInputBase = forwardRef((props, ref) => {
122
125
  decimal,
123
126
  expression,
124
127
  onChange,
128
+ onChangeEnd,
125
129
  onEmpty,
126
130
  onPressStart,
127
131
  onPressEnd,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@choice-ui/react",
3
- "version": "1.9.6",
3
+ "version": "1.9.7",
4
4
  "description": "A desktop-first React UI component library built for professional desktop applications with comprehensive documentation",
5
5
  "sideEffects": false,
6
6
  "type": "module",