diff --git a/apis/nucleus/src/components/listbox/ListBoxInline.jsx b/apis/nucleus/src/components/listbox/ListBoxInline.jsx
index 469d98516..b02ab083a 100644
--- a/apis/nucleus/src/components/listbox/ListBoxInline.jsx
+++ b/apis/nucleus/src/components/listbox/ListBoxInline.jsx
@@ -22,6 +22,7 @@ import createSelectionState from './hooks/selections/selectionState';
import { CELL_PADDING_LEFT, ICON_WIDTH, ICON_PADDING, BUTTON_ICON_WIDTH } from './constants';
import useTempKeyboard from './components/useTempKeyboard';
import ListBoxError from './components/ListBoxError';
+import useRect from '../../hooks/useRect';
const PREFIX = 'ListBoxInline';
const classes = {
@@ -110,6 +111,7 @@ function ListBoxInline({ options, layout }) {
theme.listBox = addListboxTheme(themeApi);
const containerRef = useRef();
+ const [containerRectRef, containerRect] = useRect();
const [searchContainer, searchContainerRef] = useRefWithCallback();
const [showToolbar, setShowToolbar] = useState(false);
@@ -125,6 +127,7 @@ function ListBoxInline({ options, layout }) {
const isModalMode = useCallback(() => isModal({ app, appSelections }), [app, appSelections]);
const isInvalid = layout?.qListObject.qDimensionInfo.qError;
const errorText = isInvalid && constraints.active ? 'Visualization.Invalid.Dimension' : 'Visualization.Incomplete';
+ const [isToolbarDetached, setIsToolbarDetached] = useState(false);
const { handleKeyDown, handleOnMouseEnter, handleOnMouseLeave, globalKeyDown } = useMemo(
() =>
@@ -207,13 +210,28 @@ function ListBoxInline({ options, layout }) {
}
}, [searchContainer && searchContainer.current, showSearch, search, focusSearch]);
+ const { wildCardSearch, searchEnabled, layoutOptions = {} } = layout ?? {};
+ const showSearchIcon = searchEnabled !== false && search === 'toggle';
+ const isLocked = layout?.qListObject?.qDimensionInfo?.qLocked === true;
+ const showSearchOrLockIcon = isLocked || showSearchIcon;
+ const isDrillDown = layout?.qListObject?.qDimensionInfo?.qGrouping === 'H';
+ const showIcons = showSearchOrLockIcon || isDrillDown;
+ const iconsWidth = (showSearchOrLockIcon ? BUTTON_ICON_WIDTH : 0) + (isDrillDown ? ICON_WIDTH + ICON_PADDING : 0); // Drill-down icon needs padding right so there is space between the icon and the title
+
+ useEffect(() => {
+ if (!titleRef.current || !containerRect) {
+ return;
+ }
+
+ const isDetached = showToolbarDetached({ containerRect, titleRef, iconsWidth });
+ setIsToolbarDetached(isDetached);
+ }, [titleRef.current, containerRect]);
+
if (!model || !layout || !translator) {
return null;
}
- const isLocked = layout.qListObject.qDimensionInfo.qLocked === true;
const isRtl = direction === 'rtl';
- const isDrillDown = layout.qListObject.qDimensionInfo.qGrouping === 'H';
const listboxSelectionToolbarItems = createListboxSelectionToolbar({
layout,
model,
@@ -221,7 +239,6 @@ function ListBoxInline({ options, layout }) {
selectionState,
});
- const { wildCardSearch, searchEnabled, layoutOptions = {} } = layout;
const showTitle = true;
const showSearchToggle = search === 'toggle' && showSearch;
const searchVisible = (search === true || showSearchToggle) && !selectDisabled() && searchEnabled !== false;
@@ -258,13 +275,8 @@ function ListBoxInline({ options, layout }) {
});
const shouldAutoFocus = searchVisible && search === 'toggle';
- const showSearchIcon = searchEnabled !== false && search === 'toggle';
- const showSearchOrLockIcon = isLocked || showSearchIcon;
- const showIcons = showSearchOrLockIcon || isDrillDown;
- const iconsWidth = (showSearchOrLockIcon ? BUTTON_ICON_WIDTH : 0) + (isDrillDown ? ICON_WIDTH + ICON_PADDING : 0); // Drill-down icon needs padding right so there is space between the icon and the title
const headerPaddingLeft = CELL_PADDING_LEFT - (showSearchOrLockIcon ? ICON_PADDING : 0);
const headerPaddingRight = isRtl ? CELL_PADDING_LEFT - (showIcons ? ICON_PADDING : 0) : 0;
- const isDetached = showToolbarDetached({ containerRef, titleRef, iconsWidth });
// Add a container padding for grid mode to harmonize with the grid item margins (should sum to 8px).
const isGridMode = layoutOptions?.dataLayout === 'grid';
@@ -310,7 +322,10 @@ function ListBoxInline({ options, layout }) {
onKeyDown={handleKeyDown}
onMouseEnter={handleOnMouseEnter}
onMouseLeave={handleOnMouseLeave}
- ref={containerRef}
+ ref={(el) => {
+ containerRef.current = el;
+ containerRectRef(el);
+ }}
>
{showToolbarWithTitle && (
-
+
)}
diff --git a/apis/nucleus/src/components/listbox/__tests__/list-box-inline.test.jsx b/apis/nucleus/src/components/listbox/__tests__/list-box-inline.test.jsx
index 69e00070f..1cf4560e6 100644
--- a/apis/nucleus/src/components/listbox/__tests__/list-box-inline.test.jsx
+++ b/apis/nucleus/src/components/listbox/__tests__/list-box-inline.test.jsx
@@ -137,11 +137,11 @@ describe('', () => {
useCallback
.mockImplementationOnce((effectFunc, watchArr) => {
- expect(watchArr[1].key).toBe('model');
+ expect(watchArr).toHaveLength(0);
return effectFunc;
})
.mockImplementationOnce((effectFunc, watchArr) => {
- expect(watchArr[1].key).toBe('model');
+ expect(watchArr).toHaveLength(0);
return effectFunc;
});
});
diff --git a/apis/nucleus/src/components/listbox/interactions/__tests__/listbox-show-toolbar-detached.test.js b/apis/nucleus/src/components/listbox/interactions/__tests__/listbox-show-toolbar-detached.test.js
index 07544256a..392e68bec 100644
--- a/apis/nucleus/src/components/listbox/interactions/__tests__/listbox-show-toolbar-detached.test.js
+++ b/apis/nucleus/src/components/listbox/interactions/__tests__/listbox-show-toolbar-detached.test.js
@@ -4,20 +4,20 @@ const iconsWidth = 28;
describe('show listbox toolbar detached', () => {
it('should return true if there is not enough space for toolbar', () => {
- const containerRef = { current: { clientWidth: 100 } };
+ const containerRect = { width: 100 };
const titleRef = { current: { clientWidth: 60, scrollWidth: 80, offsetWidth: 81 } };
- expect(showToolbarDetached({ containerRef, titleRef, iconsWidth })).toStrictEqual(true);
+ expect(showToolbarDetached({ containerRect, titleRef, iconsWidth })).toStrictEqual(true);
});
it('should return true if title is truncated', () => {
- const containerRef = { current: { clientWidth: 300 } };
+ const containerRect = { width: 300 };
const titleRef = { current: { clientWidth: 60, scrollWidth: 200, offsetWidth: 199 } };
- expect(showToolbarDetached({ containerRef, titleRef, iconsWidth })).toStrictEqual(true);
+ expect(showToolbarDetached({ containerRect, titleRef, iconsWidth })).toStrictEqual(true);
});
it('should return false if there is enough space for title and toolbar', () => {
- const containerRef = { current: { clientWidth: 300 } };
+ const containerRect = { width: 300 };
const titleRef = { current: { clientWidth: 60, scrollWidth: 200, offsetWidth: 201 } };
- expect(showToolbarDetached({ containerRef, titleRef, iconsWidth })).toStrictEqual(false);
+ expect(showToolbarDetached({ containerRect, titleRef, iconsWidth })).toStrictEqual(false);
});
});
diff --git a/apis/nucleus/src/components/listbox/interactions/listbox-show-toolbar-detached.js b/apis/nucleus/src/components/listbox/interactions/listbox-show-toolbar-detached.js
index 77a72ca56..1610e9c5b 100644
--- a/apis/nucleus/src/components/listbox/interactions/listbox-show-toolbar-detached.js
+++ b/apis/nucleus/src/components/listbox/interactions/listbox-show-toolbar-detached.js
@@ -1,11 +1,11 @@
-export default function showToolbarDetached({ containerRef, titleRef, iconsWidth }) {
- const containerWidth = containerRef?.current?.clientWidth ?? 0;
+export default function showToolbarDetached({ containerRect, titleRef, iconsWidth }) {
+ const containerWidth = containerRect.width;
const padding = 16;
const contentWidth = (titleRef?.current?.clientWidth ?? 0) + iconsWidth + padding;
const actionToolbarWidth = 128;
const notSufficientSpace = containerWidth < contentWidth + actionToolbarWidth;
const isTruncated = titleRef?.current?.scrollWidth > titleRef?.current?.offsetWidth;
- const isDetached = !!(notSufficientSpace | isTruncated);
+ const isDetached = !!(notSufficientSpace || isTruncated);
return isDetached;
}