@homecode/ui 4.30.8 → 4.30.10

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.
@@ -0,0 +1,44 @@
1
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:handleFocus","message":"popup opening (focus)","data":{"scrollTop":0},"hypothesisId":"C","timestamp":1771711527049}
2
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":true,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":true},"hypothesisId":"B","timestamp":1771711527054}
3
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:fetchOptionsCore","message":"setScrollTop(0) initial items","data":{"filter":"","offset":0,"totalCount":0},"hypothesisId":"B","timestamp":1771711527555}
4
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":true,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711527556}
5
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:fetchOptionsCore-RAF","message":"setScrollTop(undefined) clear","data":{"filter":"","offset":0},"hypothesisId":"E","timestamp":1771711527557}
6
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:handleBlur","message":"popup closing (blur)","data":{},"hypothesisId":"A","timestamp":1771711528848}
7
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711528850}
8
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:handleSelect","message":"select","data":{"selectable":true,"label":"Option 15"},"hypothesisId":"A","timestamp":1771711528971}
9
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:handleFocus","message":"popup opening (focus)","data":{"savedScrollTop":521.1111450195312},"hypothesisId":"C","timestamp":1771711532390}
10
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":true,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711532394}
11
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:handleBlur","message":"popup closing (blur)","data":{},"hypothesisId":"A","timestamp":1771711535314}
12
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711535317}
13
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:handleSelect","message":"select","data":{"selectable":true,"label":"Option 27"},"hypothesisId":"A","timestamp":1771711535455}
14
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:handleFocus","message":"popup opening (focus)","data":{"savedScrollTop":962.2222290039062},"hypothesisId":"C","timestamp":1771711540906}
15
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":true,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711540911}
16
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:handleBlur","message":"popup closing (blur)","data":{},"hypothesisId":"A","timestamp":1771711542255}
17
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711542257}
18
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:handleFocus","message":"popup opening (focus)","data":{"savedScrollTop":962.2222290039062},"hypothesisId":"C","timestamp":1771711543181}
19
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":true,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711543185}
20
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:handleBlur","message":"popup closing (blur)","data":{},"hypothesisId":"A","timestamp":1771711543773}
21
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711543776}
22
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:handleFocus","message":"popup opening (focus)","data":{"savedScrollTop":962.2222290039062},"hypothesisId":"C","timestamp":1771711544455}
23
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":true,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711544459}
24
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:handleBlur","message":"popup closing (blur)","data":{},"hypothesisId":"A","timestamp":1771711545022}
25
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711545023}
26
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-value","message":"setScrollTop(0) value cleared","data":{"value":""},"hypothesisId":"D","timestamp":1771711551359}
27
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711551359}
28
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711551360}
29
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-value","message":"setScrollTop(0) value cleared","data":{"value":""},"hypothesisId":"D","timestamp":1771711552110}
30
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711552111}
31
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-value","message":"setScrollTop(0) value cleared","data":{"value":""},"hypothesisId":"D","timestamp":1771711552853}
32
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711552853}
33
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-value","message":"setScrollTop(0) value cleared","data":{"value":""},"hypothesisId":"D","timestamp":1771711553442}
34
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711553443}
35
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-value","message":"setScrollTop(0) value cleared","data":{"value":""},"hypothesisId":"D","timestamp":1771711553951}
36
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711553951}
37
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-value","message":"setScrollTop(0) value cleared","data":{"value":""},"hypothesisId":"D","timestamp":1771711554564}
38
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711554564}
39
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-value","message":"setScrollTop(0) value cleared","data":{"value":""},"hypothesisId":"D","timestamp":1771711555318}
40
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711555319}
41
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-value","message":"setScrollTop(0) value cleared","data":{"value":""},"hypothesisId":"D","timestamp":1771711555975}
42
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711555975}
43
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711556573}
44
+ {"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711557126}
@@ -73,7 +73,7 @@ const getTotalCount = (total, newItemsCount = 0, offset = 0, pageSize = 20) => {
73
73
  return offset + (newItemsCount === pageSize ? 1 : 0);
74
74
  };
75
75
  function Autocomplete(props) {
76
- const { className, inputWrapperClassName, value, onChange, size = 'm', getOptions, onSelect, items, itemHeight = SIZE_TO_ITEM_HEIGHT[size], pageSize = 20, debounceDelay = 300, round = false, blur = false, selectable = false, inputProps = {}, popupProps = {}, menuProps = {}, scrollProps = {}, loadingPlaceholder, } = props;
76
+ const { className, value, onChange, size = 'm', getOptions, onSelect, items, itemHeight = SIZE_TO_ITEM_HEIGHT[size], pageSize = 20, debounceDelay = 300, round = false, blur = false, selectable = false, defaultSelected, scrollToSelected = false, inputProps = {}, popupProps = {}, menuProps = {}, scrollProps = {}, loadingPlaceholder, isOpen, } = props;
77
77
  const isMounted = useIsMounted();
78
78
  const [filteredItems, setFilteredItems] = useState([]);
79
79
  const [itemsWithoutFilter, setItemsWithoutFilter] = useState(() => items ?? []);
@@ -83,7 +83,6 @@ function Autocomplete(props) {
83
83
  const [scrollTop, setScrollTop] = useState(undefined);
84
84
  const [isLoading, setIsLoading] = useState(false);
85
85
  const [isLoadingMore, setIsLoadingMore] = useState(false);
86
- const [isOpen, setIsOpen] = useState(props.isOpen);
87
86
  const [isFocused, setIsFocused] = useState(isOpen);
88
87
  const [selectedId, setSelectedId] = useState(null);
89
88
  const [selectedLabel, setSelectedLabel] = useState(null);
@@ -95,6 +94,8 @@ function Autocomplete(props) {
95
94
  _setSearchValue(val);
96
95
  };
97
96
  const currentRequest = useRef('');
97
+ const savedScrollTopRef = useRef(undefined);
98
+ const defaultSelectedAppliedRef = useRef(false);
98
99
  // @ts-ignore
99
100
  const inputRef = useRef(null);
100
101
  const inputDisplayValue = selectable && !isFocused && selectedLabel != null
@@ -104,13 +105,20 @@ function Autocomplete(props) {
104
105
  ? filteredItems
105
106
  : itemsWithoutFilter.length
106
107
  ? itemsWithoutFilter
107
- : (items ?? []);
108
+ : items ?? [];
108
109
  const displayCount = displayItems.length;
109
110
  const hasMore = totalCount > 0 && displayCount < totalCount;
110
111
  const classes = cn(S.root, className, popupProps.className);
111
112
  const handleFocus = (e) => {
112
113
  isFocusedRef.current = true;
113
114
  setIsFocused(true);
115
+ if (!scrollToSelected || !selectable || !selectedId) {
116
+ const saved = savedScrollTopRef.current;
117
+ if (saved != null && saved > 0) {
118
+ setScrollTop(saved);
119
+ requestAnimationFrame(() => setScrollTop(undefined));
120
+ }
121
+ }
114
122
  inputProps?.onFocus?.(e);
115
123
  };
116
124
  const handleBlur = (e) => {
@@ -123,6 +131,7 @@ function Autocomplete(props) {
123
131
  setSearchValue(val);
124
132
  onChange(e, val);
125
133
  if (!val) {
134
+ savedScrollTopRef.current = undefined;
126
135
  setCurrentFilter('');
127
136
  setFilteredItems([]);
128
137
  setItemsWithoutFilter(items ?? []);
@@ -131,6 +140,7 @@ function Autocomplete(props) {
131
140
  setScrollTop(0); // Reset scroll when filter is cleared
132
141
  }
133
142
  else {
143
+ savedScrollTopRef.current = undefined;
134
144
  setCurrentFilter(val);
135
145
  setCurrentOffset(0);
136
146
  setScrollTop(0); // Reset scroll when filter changes
@@ -150,7 +160,6 @@ function Autocomplete(props) {
150
160
  setFilteredItems([]);
151
161
  setCurrentOffset(0);
152
162
  setTotalCount(0);
153
- setScrollTop(0);
154
163
  fetchOptionsCore(option.label, 0);
155
164
  onSelect?.(option);
156
165
  // set input caret to the end
@@ -187,6 +196,7 @@ function Autocomplete(props) {
187
196
  const newTotal = getTotalCount(total, newOptions.length, offset + newOptions.length, pageSize);
188
197
  if (filter) {
189
198
  if (offset === 0) {
199
+ savedScrollTopRef.current = undefined;
190
200
  setFilteredItems(newOptions);
191
201
  setScrollTop(0); // Reset scroll when new filter results load
192
202
  }
@@ -198,6 +208,7 @@ function Autocomplete(props) {
198
208
  }
199
209
  else {
200
210
  if (offset === 0) {
211
+ savedScrollTopRef.current = undefined;
201
212
  setItemsWithoutFilter(newOptions);
202
213
  setScrollTop(0); // Reset scroll when loading initial items
203
214
  }
@@ -232,6 +243,9 @@ function Autocomplete(props) {
232
243
  }
233
244
  }, [getOptions, isMounted, pageSize, items]);
234
245
  const fetchOptions = useMemo(() => debounce(fetchOptionsCore, debounceDelay), [fetchOptionsCore, debounceDelay]);
246
+ const handleScroll = useCallback(({ scrollTop: top }) => {
247
+ savedScrollTopRef.current = top;
248
+ }, []);
235
249
  const handleScrollEnd = useCallback(() => {
236
250
  if (!hasMore || isLoading || isLoadingMore)
237
251
  return;
@@ -259,6 +273,7 @@ function Autocomplete(props) {
259
273
  return;
260
274
  setSearchValue(value);
261
275
  if (!value) {
276
+ savedScrollTopRef.current = undefined;
262
277
  setCurrentFilter('');
263
278
  setFilteredItems([]);
264
279
  setItemsWithoutFilter(items ?? []);
@@ -267,6 +282,7 @@ function Autocomplete(props) {
267
282
  setScrollTop(0); // Reset scroll when value is cleared
268
283
  }
269
284
  else if (isFocusedRef.current) {
285
+ savedScrollTopRef.current = undefined;
270
286
  setCurrentFilter(value);
271
287
  setCurrentOffset(0);
272
288
  setScrollTop(0); // Reset scroll when filter changes
@@ -277,8 +293,22 @@ function Autocomplete(props) {
277
293
  if (selectable && !value) {
278
294
  setSelectedId(null);
279
295
  setSelectedLabel(null);
296
+ defaultSelectedAppliedRef.current = false;
280
297
  }
281
298
  }, [selectable, value]);
299
+ useEffect(() => {
300
+ if (selectable &&
301
+ defaultSelected &&
302
+ !defaultSelectedAppliedRef.current &&
303
+ displayItems.length) {
304
+ const item = displayItems.find(o => o.id === defaultSelected);
305
+ if (item) {
306
+ defaultSelectedAppliedRef.current = true;
307
+ setSelectedId(item.id);
308
+ setSelectedLabel(item.label);
309
+ }
310
+ }
311
+ }, [selectable, defaultSelected, displayItems]);
282
312
  useEffect(() => {
283
313
  if (!currentFilter && items?.length) {
284
314
  setItemsWithoutFilter(items);
@@ -330,11 +360,20 @@ function Autocomplete(props) {
330
360
  return !selectable && isLoading ? LoadingPlaceholder : null;
331
361
  }
332
362
  const computedTotalCount = totalCount > 0 ? totalCount : displayItems.length;
333
- return (jsx(ListScroll, { ...(selectable && { id: selectedId ?? 'none' }), className: cn(S.options, menuProps.className), scrollProps: {
363
+ const open = isOpen ?? isFocused;
364
+ let initialScrollTop;
365
+ if (open && scrollToSelected && selectable && selectedId) {
366
+ const idx = displayItems.findIndex(o => o.id === selectedId);
367
+ initialScrollTop =
368
+ idx >= 0 ? Math.max(0, idx * itemHeight - itemHeight) : undefined;
369
+ }
370
+ return (jsx(ListScroll, { ...(selectable && { id: selectedId ?? 'none' }), ...(typeof initialScrollTop === 'number' && {
371
+ initialScrollTop,
372
+ }), className: cn(S.options, menuProps.className), scrollProps: {
334
373
  y: true,
335
374
  ...scrollProps,
336
375
  className: cn(S.scroll, scrollProps?.className),
337
- }, itemHeight: itemHeight, itemsCount: displayItems.length, totalCount: computedTotalCount, overlapCount: 10, pageSize: pageSize, scrollTop: scrollTop, onScrollEnd: handleScrollEnd, renderItem: renderItem, contentAfter: hasMore && LoadingPlaceholder }));
376
+ }, itemHeight: itemHeight, itemsCount: displayItems.length, totalCount: computedTotalCount, overlapCount: 10, pageSize: pageSize, scrollTop: scrollTop, onScroll: handleScroll, onScrollEnd: handleScrollEnd, renderItem: renderItem, contentAfter: hasMore && LoadingPlaceholder }));
338
377
  }, [
339
378
  displayItems,
340
379
  focusedIndex,
@@ -344,6 +383,7 @@ function Autocomplete(props) {
344
383
  isLoadingMore,
345
384
  itemHeight,
346
385
  pageSize,
386
+ handleScroll,
347
387
  handleScrollEnd,
348
388
  renderItem,
349
389
  size,
@@ -353,6 +393,9 @@ function Autocomplete(props) {
353
393
  scrollTop,
354
394
  selectable,
355
395
  selectedId,
396
+ isOpen,
397
+ isFocused,
398
+ scrollToSelected,
356
399
  LoadingPlaceholder,
357
400
  ]);
358
401
  return (jsx(Popup, { className: classes, isOpen: isOpen, focusControl: true, round: round, size: size, blur: blur, direction: "bottom", ...popupProps, trigger: jsx(Input, { ref: inputRef,
@@ -11,7 +11,6 @@ export type Option = {
11
11
  export type Value = string;
12
12
  export type Props = FormControl<Value, HTMLInputElement> & {
13
13
  className?: string;
14
- inputWrapperClassName?: string;
15
14
  size?: Size;
16
15
  value: Value;
17
16
  isOpen?: boolean;
@@ -31,6 +30,8 @@ export type Props = FormControl<Value, HTMLInputElement> & {
31
30
  round?: boolean;
32
31
  blur?: boolean;
33
32
  selectable?: boolean;
33
+ defaultSelected?: string;
34
+ scrollToSelected?: boolean;
34
35
  renderItem?: (props: RenderItemProps) => React.ReactElement;
35
36
  loadingPlaceholder?: React.ReactNode;
36
37
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homecode/ui",
3
- "version": "4.30.8",
3
+ "version": "4.30.10",
4
4
  "description": "React UI components library",
5
5
  "scripts": {
6
6
  "tests": "jest",