@synerise/ds-item-picker 2.0.5 → 2.1.1

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/CHANGELOG.md CHANGED
@@ -3,6 +3,20 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [2.1.1](https://github.com/Synerise/synerise-design/compare/@synerise/ds-item-picker@2.1.0...@synerise/ds-item-picker@2.1.1) (2026-09-18)
7
+
8
+ **Note:** Version bump only for package @synerise/ds-item-picker
9
+
10
+
11
+
12
+
13
+
14
+ # [2.1.0](https://github.com/Synerise/synerise-design/compare/@synerise/ds-item-picker@2.0.5...@synerise/ds-item-picker@2.1.0) (2026-09-16)
15
+
16
+ ### Features
17
+
18
+ - **list-item:** add content-fitting size="auto" ([e269f0a](https://github.com/Synerise/synerise-design/commit/e269f0a48ca7472f4766a50a957e22d7988c5e13))
19
+
6
20
  ## [2.0.5](https://github.com/Synerise/synerise-design/compare/@synerise/ds-item-picker@2.0.4...@synerise/ds-item-picker@2.0.5) (2026-09-10)
7
21
 
8
22
  **Note:** Version bump only for package @synerise/ds-item-picker
@@ -7,12 +7,12 @@ import Dropdown from "@synerise/ds-dropdown";
7
7
  import Icon, { ArrowLeftM } from "@synerise/ds-icon";
8
8
  import { itemSizes, ListContextProvider } from "@synerise/ds-list-item";
9
9
  import { Text } from "@synerise/ds-typography";
10
- import { useCombinedRefs, useScrollContain, useKeyboardShortcuts, focusWithArrowKeys } from "@synerise/ds-utils";
10
+ import { useCombinedRefs, useScrollContain, useMeasuredRowHeights, useKeyboardShortcuts, focusWithArrowKeys } from "@synerise/ds-utils";
11
11
  import { useDefaultTexts } from "../../hooks/useDefaultTexts.js";
12
- import { StyledScrollbar, ScrollContent, StyledList, ListContainer, ListWrapper } from "./ItemPickerList.styles.js";
13
12
  import { EmptyListMessage } from "./components/EmptyListMessage.js";
14
13
  import { ErrorMessage } from "./components/ErrorMessage.js";
15
14
  import "@synerise/ds-inline-alert";
15
+ import { StyledScrollbar, ScrollContent, StyledList, ListContainer, ListWrapper } from "./ItemPickerList.styles.js";
16
16
  import { ItemPickerListFooter } from "./components/ItemPickerListFooter.js";
17
17
  import { ItemPickerListRow } from "./components/ItemPickerListRow.js";
18
18
  import { ItemPickerListSkeleton } from "./components/ItemPickerListSkeleton.js";
@@ -20,9 +20,9 @@ import { ListSearchInput } from "./components/ListSearchInput.js";
20
20
  import { ITEM_SIZE, LIST_STYLE, SECTION_HEADER_HEIGHT, LIST_INNER_PADDING } from "./constants.js";
21
21
  import { useItemsInSections } from "./hooks/useItemsInSections.js";
22
22
  import { useListHeight } from "./hooks/useListHeight.js";
23
- import { isTitle } from "./utils/typeguards.utils.js";
24
- import { isNavKey } from "./utils/isNavKey.js";
25
23
  import { findSectionById } from "./utils/findSectionById.js";
24
+ import { isNavKey } from "./utils/isNavKey.js";
25
+ import { isTitle } from "./utils/typeguards.utils.js";
26
26
  const ItemPickerListInner = ({
27
27
  items,
28
28
  recents,
@@ -52,7 +52,6 @@ const ItemPickerListInner = ({
52
52
  }, forwardedRef) => {
53
53
  const theme = useTheme();
54
54
  const [searchQuery, setSearchQuery] = useState("");
55
- const listRef = useRef(null);
56
55
  const scrollBarRef = useRef(null);
57
56
  const containerRef = useRef(null);
58
57
  const refs = [containerRef];
@@ -150,24 +149,34 @@ const ItemPickerListInner = ({
150
149
  });
151
150
  }
152
151
  };
153
- const getItemSize = useCallback((index) => {
152
+ const getEstimatedItemSize = useCallback((index) => {
154
153
  const item = mergedItemsList && mergedItemsList[index];
155
154
  if (isTitle(item)) {
156
155
  return ITEM_SIZE.title;
157
156
  }
158
157
  return ITEM_SIZE[item.size || itemSizes.DEFAULT];
159
158
  }, [mergedItemsList]);
159
+ const rowKeys = useMemo(() => mergedItemsList.map((item, index) => isTitle(item) ? `title-${index}` : item.itemKey ?? item.key ?? index), [mergedItemsList]);
160
+ const {
161
+ listRef,
162
+ getItemSize,
163
+ measureRow
164
+ } = useMeasuredRowHeights({
165
+ keys: rowKeys,
166
+ estimate: getEstimatedItemSize
167
+ });
160
168
  const itemData = useMemo(() => ({
161
169
  dataSource: mergedItemsList,
162
170
  classNames,
163
171
  getItemSize,
172
+ measureRow,
164
173
  texts: allTexts,
165
174
  infiniteScroll: {
166
175
  isLoading: isLoadingMore,
167
176
  hasMore: !isLoadedAll,
168
177
  hasError: isLoadingMoreError
169
178
  }
170
- }), [mergedItemsList, classNames, getItemSize, allTexts, isLoadingMore, isLoadedAll, isLoadingMoreError]);
179
+ }), [mergedItemsList, classNames, getItemSize, measureRow, allTexts, isLoadingMore, isLoadedAll, isLoadingMoreError]);
171
180
  const handleRefresh = onRefresh || refreshItems ? () => {
172
181
  changeSearchQuery("");
173
182
  setSearchByParamConfig(void 0);
@@ -9,6 +9,7 @@ export type ItemPickerListRowProps = {
9
9
  dataSource: Array<ListItemProps | TitleListItemProps>;
10
10
  classNames: string;
11
11
  getItemSize: (index: number) => number;
12
+ measureRow: (index: number, height: number) => void;
12
13
  texts: ItemPickerListTexts;
13
14
  infiniteScroll?: {
14
15
  isLoading: boolean;
@@ -17,4 +18,4 @@ export type ItemPickerListRowProps = {
17
18
  };
18
19
  };
19
20
  };
20
- export declare const ItemPickerListRow: ({ index, style, data: { dataSource, classNames, getItemSize, infiniteScroll, texts }, }: PropsWithChildren<ItemPickerListRowProps>) => React.JSX.Element;
21
+ export declare const ItemPickerListRow: ({ index, style, data: { dataSource, classNames, getItemSize, measureRow, infiniteScroll, texts, }, }: PropsWithChildren<ItemPickerListRowProps>) => React.JSX.Element;
@@ -1,6 +1,7 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import { useCallback } from "react";
3
3
  import DSListItem from "@synerise/ds-list-item";
4
+ import { useMeasuredRow } from "@synerise/ds-utils";
4
5
  import { InfiniteLoaderItemWrapper, Title } from "../ItemPickerList.styles.js";
5
6
  import { isTitle } from "../utils/typeguards.utils.js";
6
7
  import { InfiniteLoaderItem } from "./InfiniteLoaderItem.js";
@@ -12,11 +13,18 @@ const ItemPickerListRow = ({
12
13
  dataSource,
13
14
  classNames,
14
15
  getItemSize,
16
+ measureRow,
15
17
  infiniteScroll,
16
18
  texts
17
19
  }
18
20
  }) => {
19
21
  const listItem = dataSource[index];
22
+ const rowRef = useMeasuredRow(index, measureRow);
23
+ const rowStyle = {
24
+ ...style,
25
+ height: "auto",
26
+ minHeight: style.height
27
+ };
20
28
  const lastItemHeight = getItemSize(dataSource.length - 1);
21
29
  const infiniteLoaderItem = useCallback(() => {
22
30
  if (infiniteScroll) {
@@ -38,10 +46,10 @@ const ItemPickerListRow = ({
38
46
  return null;
39
47
  }, [infiniteScroll, lastItemHeight, style, texts]);
40
48
  if (isTitle(listItem)) {
41
- return /* @__PURE__ */ jsx(Title, { style, children: listItem.text });
49
+ return /* @__PURE__ */ jsx("div", { ref: rowRef, style: rowStyle, children: /* @__PURE__ */ jsx(Title, { children: listItem.text }) });
42
50
  }
43
51
  return /* @__PURE__ */ jsxs(Fragment, { children: [
44
- /* @__PURE__ */ jsx(DSListItem, { ...listItem, style, className: classNames }),
52
+ /* @__PURE__ */ jsx("div", { ref: rowRef, style: rowStyle, children: /* @__PURE__ */ jsx(DSListItem, { ...listItem, className: classNames }) }),
45
53
  index === dataSource.length - 1 && infiniteLoaderItem()
46
54
  ] });
47
55
  };
@@ -1,9 +1,14 @@
1
1
  import { CSSProperties } from 'react';
2
+ import { ItemSize } from '@synerise/ds-list-item';
2
3
  import { BaseItemType } from '../ItemPickerNew/types/baseItemSectionType.types';
3
4
  export declare const LIST_STYLE: CSSProperties;
4
- export declare const ITEM_SIZE: {
5
- large: number;
6
- default: number;
5
+ /**
6
+ * Row height estimates. Typed exhaustively over `ItemSize` on purpose: a new size must
7
+ * fail the build here rather than silently yield an undefined row offset. `auto` has no
8
+ * fixed height — 32 is its `min-height` floor, and the real height is measured (see
9
+ * `useMeasuredRowHeights` in `ItemPickerList`).
10
+ */
11
+ export declare const ITEM_SIZE: Record<ItemSize, number> & {
7
12
  title: number;
8
13
  };
9
14
  export declare const DEFAULT_HEIGHT = 420;
@@ -6,6 +6,7 @@ const LIST_STYLE = {
6
6
  const ITEM_SIZE = {
7
7
  [itemSizes.LARGE]: 50,
8
8
  [itemSizes.DEFAULT]: 32,
9
+ [itemSizes.AUTO]: 32,
9
10
  title: 32
10
11
  };
11
12
  const DEFAULT_HEIGHT = 420;
@@ -1,3 +1,3 @@
1
+ export * from './useFlattenFolders';
1
2
  export * from './useItemsInSections';
2
3
  export * from './useListHeight';
3
- export * from './useFlattenFolders';
@@ -1,6 +1,6 @@
1
+ import { useFlattenFolders } from "./useFlattenFolders.js";
1
2
  import { useItemsInSections } from "./useItemsInSections.js";
2
3
  import { useListHeight } from "./useListHeight.js";
3
- import { useFlattenFolders } from "./useFlattenFolders.js";
4
4
  export {
5
5
  useFlattenFolders,
6
6
  useItemsInSections,
@@ -1,8 +1,8 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import Icon, { FolderM, ArrowRightCircleM } from "@synerise/ds-icon";
3
3
  import InformationCard from "@synerise/ds-information-card";
4
- import "../../ItemPickerNew/types/actions.types.js";
5
4
  import { createTitleFromTitlePath } from "../utils/createTitleFromTitlePath.js";
5
+ import "../../ItemPickerNew/types/actions.types.js";
6
6
  const getFolderItem = (item, onClick) => {
7
7
  return {
8
8
  prefixel: /* @__PURE__ */ jsx(Icon, { component: /* @__PURE__ */ jsx(FolderM, {}) }),
@@ -1,7 +1,7 @@
1
1
  import { ACTION_TYPES } from "../../ItemPickerNew/types/actions.types.js";
2
2
  import { getTitleItem, matchesSearchQuery } from "../hooks/useItemsInSections.utils.js";
3
- import { isSearchInAction, isSearchByAction, isTruthy } from "./typeguards.utils.js";
4
3
  import "../constants.js";
4
+ import { isSearchInAction, isSearchByAction, isTruthy } from "./typeguards.utils.js";
5
5
  import { getContextAwareActions } from "./getContextAwareActions.js";
6
6
  const getActionItem = (action, searchQuery) => {
7
7
  return {
@@ -1,4 +1,4 @@
1
- export * from './typeguards.utils';
2
- export * from './isNavKey';
3
1
  export * from './createTitleFromTitlePath';
4
2
  export * from './findSectionById';
3
+ export * from './isNavKey';
4
+ export * from './typeguards.utils';
@@ -1,7 +1,7 @@
1
- import { isItems, isItemsConfig, isSearchByAction, isSearchInAction, isTitle, isTruthy, isWithOutSections } from "./typeguards.utils.js";
2
- import { isNavKey } from "./isNavKey.js";
3
1
  import { createTitleFromTitlePath } from "./createTitleFromTitlePath.js";
4
2
  import { findSectionById } from "./findSectionById.js";
3
+ import { isNavKey } from "./isNavKey.js";
4
+ import { isItems, isItemsConfig, isSearchByAction, isSearchInAction, isTitle, isTruthy, isWithOutSections } from "./typeguards.utils.js";
5
5
  export {
6
6
  createTitleFromTitlePath,
7
7
  findSectionById,
@@ -2,8 +2,8 @@ import { jsx } from "react/jsx-runtime";
2
2
  import { forwardRef, useState, useEffect, useMemo } from "react";
3
3
  import Dropdown from "@synerise/ds-dropdown";
4
4
  import FormField from "@synerise/ds-form-field";
5
- import { ItemPickerWrapper } from "../../ItemPicker.styles.js";
6
5
  import { useDefaultTexts } from "../../hooks/useDefaultTexts.js";
6
+ import { ItemPickerWrapper } from "../../ItemPicker.styles.js";
7
7
  import { ItemPickerList } from "../ItemPickerList/ItemPickerList.js";
8
8
  import Trigger from "../ItemPickerTrigger/Trigger.js";
9
9
  const ItemPickerNewInner = ({
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
- export { default } from './ItemPicker';
2
- export type { ItemPickerProps } from './components/ItemPickerLegacy/ItemPickerLegacy.types';
3
1
  export { default as ItemPickerLegacy } from './components/ItemPickerLegacy/ItemPickerLegacy';
4
- export { default as ItemPickerTrigger } from './components/ItemPickerTrigger/Trigger';
2
+ export type { ItemPickerProps } from './components/ItemPickerLegacy/ItemPickerLegacy.types';
5
3
  export { ItemPickerList } from './components/ItemPickerList/ItemPickerList';
4
+ export type { ItemPickerListAPI, ItemSelectHandler, } from './components/ItemPickerList/ItemPickerList.types';
5
+ export { findSectionById } from './components/ItemPickerList/utils/findSectionById';
6
6
  export { ItemPickerNew } from './components/ItemPickerNew/ItemPickerNew';
7
- export type { ItemSelectHandler, ItemPickerListAPI, } from './components/ItemPickerList/ItemPickerList.types';
8
- export type { ItemPickerProps as ItemPickerPropsNew, ItemLoaderConfig, ItemLoaderResponse, LoaderProps, OnLoadedData, ItemPickerListProps, } from './components/ItemPickerNew/ItemPickerNew.types';
9
- export type { BaseSectionTypeWithFolders, BaseSectionType, BaseItemType, } from './components/ItemPickerNew/types/baseItemSectionType.types';
10
- export type { ItemPickerListTexts } from './components/ItemPickerNew/types/itemPickerListTexts.types';
7
+ export type { ItemLoaderConfig, ItemLoaderResponse, ItemPickerListProps, ItemPickerProps as ItemPickerPropsNew, LoaderProps, OnLoadedData, } from './components/ItemPickerNew/ItemPickerNew.types';
11
8
  export type { Action } from './components/ItemPickerNew/types/actions.types';
12
- export { findSectionById } from './components/ItemPickerList/utils/findSectionById';
9
+ export type { BaseItemType, BaseSectionType, BaseSectionTypeWithFolders, } from './components/ItemPickerNew/types/baseItemSectionType.types';
10
+ export type { ItemPickerListTexts } from './components/ItemPickerNew/types/itemPickerListTexts.types';
11
+ export { default as ItemPickerTrigger } from './components/ItemPickerTrigger/Trigger';
12
+ export { default } from './ItemPicker';
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
- import { default as default2 } from "./ItemPicker.js";
2
- import { default as default3 } from "./components/ItemPickerLegacy/ItemPickerLegacy.js";
3
- import { default as default4 } from "./components/ItemPickerTrigger/Trigger.js";
1
+ import { default as default2 } from "./components/ItemPickerLegacy/ItemPickerLegacy.js";
4
2
  import { ItemPickerList } from "./components/ItemPickerList/ItemPickerList.js";
5
- import { ItemPickerNew } from "./components/ItemPickerNew/ItemPickerNew.js";
6
3
  import { findSectionById } from "./components/ItemPickerList/utils/findSectionById.js";
4
+ import { ItemPickerNew } from "./components/ItemPickerNew/ItemPickerNew.js";
5
+ import { default as default3 } from "./components/ItemPickerTrigger/Trigger.js";
6
+ import { default as default4 } from "./ItemPicker.js";
7
7
  export {
8
- default3 as ItemPickerLegacy,
8
+ default2 as ItemPickerLegacy,
9
9
  ItemPickerList,
10
10
  ItemPickerNew,
11
- default4 as ItemPickerTrigger,
12
- default2 as default,
11
+ default3 as ItemPickerTrigger,
12
+ default4 as default,
13
13
  findSectionById
14
14
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synerise/ds-item-picker",
3
- "version": "2.0.5",
3
+ "version": "2.1.1",
4
4
  "description": "ItemPicker UI Component for the Synerise Design System",
5
5
  "license": "ISC",
6
6
  "repository": "Synerise/synerise-design",
@@ -42,27 +42,27 @@
42
42
  ],
43
43
  "types": "dist/index.d.ts",
44
44
  "dependencies": {
45
- "@synerise/ds-avatar": "^2.0.2",
46
- "@synerise/ds-button": "^2.0.2",
47
- "@synerise/ds-dropdown": "^2.0.3",
48
- "@synerise/ds-empty-states": "^2.0.1",
49
- "@synerise/ds-flag": "^2.0.0",
50
- "@synerise/ds-form-field": "^2.0.2",
51
- "@synerise/ds-icon": "^2.1.0",
52
- "@synerise/ds-information-card": "^2.0.5",
53
- "@synerise/ds-inline-alert": "^2.0.1",
54
- "@synerise/ds-list-item": "^2.0.2",
55
- "@synerise/ds-loader": "^2.0.0",
56
- "@synerise/ds-popconfirm": "^2.0.2",
57
- "@synerise/ds-result": "^2.0.2",
58
- "@synerise/ds-scrollbar": "^2.0.1",
59
- "@synerise/ds-search": "^2.0.2",
60
- "@synerise/ds-search-bar": "^2.0.3",
61
- "@synerise/ds-short-cuts": "^2.0.2",
62
- "@synerise/ds-skeleton": "^2.0.2",
63
- "@synerise/ds-tooltip": "^2.0.2",
64
- "@synerise/ds-typography": "^2.0.2",
65
- "@synerise/ds-utils": "^2.0.0",
45
+ "@synerise/ds-avatar": "^2.0.4",
46
+ "@synerise/ds-button": "^2.0.4",
47
+ "@synerise/ds-dropdown": "^2.1.1",
48
+ "@synerise/ds-empty-states": "^2.0.3",
49
+ "@synerise/ds-flag": "^2.0.1",
50
+ "@synerise/ds-form-field": "^2.0.4",
51
+ "@synerise/ds-icon": "^2.1.2",
52
+ "@synerise/ds-information-card": "^2.0.7",
53
+ "@synerise/ds-inline-alert": "^2.0.3",
54
+ "@synerise/ds-list-item": "^2.1.1",
55
+ "@synerise/ds-loader": "^2.0.1",
56
+ "@synerise/ds-popconfirm": "^2.0.4",
57
+ "@synerise/ds-result": "^2.0.4",
58
+ "@synerise/ds-scrollbar": "^2.0.3",
59
+ "@synerise/ds-search": "^2.0.4",
60
+ "@synerise/ds-search-bar": "^2.0.5",
61
+ "@synerise/ds-short-cuts": "^2.0.4",
62
+ "@synerise/ds-skeleton": "^2.0.4",
63
+ "@synerise/ds-tooltip": "^2.0.4",
64
+ "@synerise/ds-typography": "^2.0.4",
65
+ "@synerise/ds-utils": "^2.1.1",
66
66
  "lodash.debounce": "^4.0.8",
67
67
  "react-window": "^1.8.11",
68
68
  "uuid": "^8.3.2"
@@ -77,5 +77,5 @@
77
77
  "styled-components": "^5.3.3",
78
78
  "vitest": "4"
79
79
  },
80
- "gitHead": "a49acd96b6f71f5617548ae5ce6126cb9b0985dc"
80
+ "gitHead": "b1d905617dfb186b5d80966d63ce55bf29df743d"
81
81
  }