refactor: minor adjustments to actionstoolbar (#1281)
@@ -18,21 +18,11 @@ const PREFIX = 'ActionsToolbar';
|
||||
const classes = {
|
||||
item: `${PREFIX}-item`,
|
||||
itemSpacing: `${PREFIX}-itemSpacing`,
|
||||
firstItemSpacing: `${PREFIX}-firstItemSpacing`,
|
||||
lastItemSpacing: `${PREFIX}-lastItemSpacing`,
|
||||
};
|
||||
|
||||
const StyledPopover = styled(Popover)(({ theme }) => ({
|
||||
[`& .${classes.itemSpacing}`]: {
|
||||
padding: theme.spacing(0, 0.5),
|
||||
},
|
||||
|
||||
[`& .${classes.firstItemSpacing}`]: {
|
||||
padding: theme.spacing(0, 0.5, 0, 0),
|
||||
},
|
||||
|
||||
[`& .${classes.lastItemSpacing}`]: {
|
||||
padding: theme.spacing(0, 0, 0, 0.5),
|
||||
padding: theme.spacing(0, 0.25),
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -47,37 +37,14 @@ const ActionToolbarElement = {
|
||||
};
|
||||
|
||||
const ActionsGroup = React.forwardRef(
|
||||
(
|
||||
{ className, ariaExpanded = false, actions = [], first = false, last = false, addAnchor = false, isRtl = false },
|
||||
ref
|
||||
) =>
|
||||
({ className, ariaExpanded = false, actions = [], addAnchor = false, isRtl = false }, ref) =>
|
||||
actions.length > 0 ? (
|
||||
<Grid item container gap={0} flexDirection={isRtl ? 'row-reverse' : 'row'} wrap="nowrap" className={className}>
|
||||
{actions.map((e, ix) => {
|
||||
let cls = [];
|
||||
const isFirstItem = first && ix === 0;
|
||||
const isLastItem = last && actions.length - 1 === ix;
|
||||
if (isFirstItem && !isLastItem) {
|
||||
cls = [classes.firstItemSpacing, classes.item];
|
||||
}
|
||||
if (isLastItem && !isFirstItem) {
|
||||
cls = [...cls, classes.lastItemSpacing, classes.item];
|
||||
}
|
||||
if (!isFirstItem && !isLastItem && cls.length === 0) {
|
||||
cls = [classes.itemSpacing, classes.item];
|
||||
}
|
||||
return (
|
||||
<Grid item key={e.key} className={cls.join(' ').trim()}>
|
||||
<Item
|
||||
ariaExpanded={ariaExpanded}
|
||||
key={e.key}
|
||||
item={e}
|
||||
ref={ix === 0 ? ref : null}
|
||||
addAnchor={addAnchor}
|
||||
/>
|
||||
</Grid>
|
||||
);
|
||||
})}
|
||||
{actions.map((e, ix) => (
|
||||
<Grid item key={e.key} className={`${classes.itemSpacing} ${classes.item}`}>
|
||||
<Item ariaExpanded={ariaExpanded} key={e.key} item={e} ref={ix === 0 ? ref : null} addAnchor={addAnchor} />
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
) : null
|
||||
);
|
||||
@@ -119,7 +86,7 @@ function ActionsToolbar({
|
||||
const [showMoreItems, setShowMoreItems] = useState(false);
|
||||
|
||||
const popoverAnchorOrigin = {
|
||||
vertical: 7,
|
||||
vertical: 12,
|
||||
horizontal: (popover.anchorEl?.clientWidth ?? 0) - 7,
|
||||
};
|
||||
|
||||
@@ -204,7 +171,7 @@ function ActionsToolbar({
|
||||
data-testid="actions-toolbar"
|
||||
sx={{ flexDirection: isRtl ? 'row-reverse' : 'row' }}
|
||||
>
|
||||
{showActions && <ActionsGroup actions={newActions} first last={!showMore && !selections.show} />}
|
||||
{showActions && <ActionsGroup actions={newActions} />}
|
||||
{showMore && (
|
||||
<ActionsGroup
|
||||
id="actions-toolbar-show-more"
|
||||
@@ -212,8 +179,6 @@ function ActionsToolbar({
|
||||
ref={moreRef}
|
||||
ariaExpanded={showMoreItems}
|
||||
actions={[moreItem]}
|
||||
first={!showActions}
|
||||
last={!selections.show}
|
||||
addAnchor
|
||||
/>
|
||||
)}
|
||||
@@ -223,13 +188,7 @@ function ActionsToolbar({
|
||||
</Grid>
|
||||
)}
|
||||
{selections.show && (
|
||||
<ActionsGroup
|
||||
className="actions-toolbar-default-actions"
|
||||
actions={defaultSelectionActions}
|
||||
first={!showActions && !showMore}
|
||||
last
|
||||
isRtl={isRtl}
|
||||
/>
|
||||
<ActionsGroup className="actions-toolbar-default-actions" actions={defaultSelectionActions} isRtl={isRtl} />
|
||||
)}
|
||||
{showMoreItems && (
|
||||
<More
|
||||
@@ -261,7 +220,7 @@ function ActionsToolbar({
|
||||
className: ActionToolbarElement.className,
|
||||
style: {
|
||||
pointerEvents: 'auto',
|
||||
padding: theme.spacing(0.8),
|
||||
padding: theme.spacing(0.5, 0.25),
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -19,7 +19,7 @@ import useAppSelections from '../../hooks/useAppSelections';
|
||||
import showToolbarDetached from './interactions/listbox-show-toolbar-detached';
|
||||
import getListboxActionProps from './interactions/listbox-get-action-props';
|
||||
import createSelectionState from './hooks/selections/selectionState';
|
||||
import { CELL_PADDING_LEFT, ICON_WIDTH, ICON_PADDING, BUTTON_ICON_WIDTH } from './constants';
|
||||
import { CELL_PADDING_LEFT, ICON_WIDTH, ICON_PADDING, BUTTON_ICON_WIDTH, HEADER_PADDING_RIGHT } from './constants';
|
||||
import useTempKeyboard from './components/useTempKeyboard';
|
||||
import ListBoxError from './components/ListBoxError';
|
||||
import useRect from '../../hooks/useRect';
|
||||
@@ -223,13 +223,22 @@ function ListBoxInline({ options, layout }) {
|
||||
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
|
||||
const isRtl = direction === 'rtl';
|
||||
const headerPaddingLeft = CELL_PADDING_LEFT - (showSearchOrLockIcon ? ICON_PADDING : 0);
|
||||
const headerPaddingRight = isRtl ? CELL_PADDING_LEFT - (showIcons ? ICON_PADDING : 0) : HEADER_PADDING_RIGHT;
|
||||
|
||||
useEffect(() => {
|
||||
if (!titleRef.current || !containerRect) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isDetached = showToolbarDetached({ containerRect, titleRef, iconsWidth });
|
||||
const isDetached = showToolbarDetached({
|
||||
containerRect,
|
||||
titleRef,
|
||||
iconsWidth,
|
||||
headerPaddingLeft,
|
||||
headerPaddingRight,
|
||||
});
|
||||
setIsToolbarDetached(isDetached);
|
||||
}, [titleRef.current, containerRect]);
|
||||
|
||||
@@ -237,7 +246,6 @@ function ListBoxInline({ options, layout }) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isRtl = direction === 'rtl';
|
||||
const listboxSelectionToolbarItems = createListboxSelectionToolbar({
|
||||
layout,
|
||||
model,
|
||||
@@ -282,8 +290,6 @@ function ListBoxInline({ options, layout }) {
|
||||
});
|
||||
|
||||
const shouldAutoFocus = searchVisible && search === 'toggle';
|
||||
const headerPaddingLeft = CELL_PADDING_LEFT - (showSearchOrLockIcon ? ICON_PADDING : 0);
|
||||
const headerPaddingRight = isRtl ? CELL_PADDING_LEFT - (showIcons ? ICON_PADDING : 0) : 0;
|
||||
|
||||
// Add a container padding for grid mode to harmonize with the grid item margins (should sum to 8px).
|
||||
const isGridMode = layoutOptions?.dataLayout === 'grid';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export const CELL_PADDING_LEFT = 9;
|
||||
export const HEADER_PADDING_RIGHT = 4;
|
||||
export const ICON_WIDTH = 12;
|
||||
export const ICON_PADDING = 7;
|
||||
export const BUTTON_ICON_WIDTH = ICON_WIDTH + (ICON_PADDING + 1) * 2; // 1 is border width
|
||||
|
||||
@@ -1,23 +1,31 @@
|
||||
import showToolbarDetached from '../listbox-show-toolbar-detached';
|
||||
|
||||
const iconsWidth = 28;
|
||||
const headerPaddingLeft = 9;
|
||||
const headerPaddingRight = 4;
|
||||
|
||||
describe('show listbox toolbar detached', () => {
|
||||
it('should return true if there is not enough space for toolbar', () => {
|
||||
const containerRect = { width: 100 };
|
||||
const titleRef = { current: { clientWidth: 60, scrollWidth: 80, offsetWidth: 81 } };
|
||||
expect(showToolbarDetached({ containerRect, titleRef, iconsWidth })).toStrictEqual(true);
|
||||
const titleRef = { current: { clientWidth: 50, scrollWidth: 80, offsetWidth: 81 } };
|
||||
expect(
|
||||
showToolbarDetached({ containerRect, titleRef, iconsWidth, headerPaddingLeft, headerPaddingRight })
|
||||
).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it('should return true if title is truncated', () => {
|
||||
const containerRect = { width: 300 };
|
||||
const titleRef = { current: { clientWidth: 60, scrollWidth: 200, offsetWidth: 199 } };
|
||||
const titleRef = {
|
||||
current: { clientWidth: 60, scrollWidth: 200, offsetWidth: 199, headerPaddingLeft, headerPaddingRight },
|
||||
};
|
||||
expect(showToolbarDetached({ containerRect, titleRef, iconsWidth })).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it('should return false if there is enough space for title and toolbar', () => {
|
||||
const containerRect = { width: 300 };
|
||||
const titleRef = { current: { clientWidth: 60, scrollWidth: 200, offsetWidth: 201 } };
|
||||
const titleRef = {
|
||||
current: { clientWidth: 60, scrollWidth: 200, offsetWidth: 201, headerPaddingLeft, headerPaddingRight },
|
||||
};
|
||||
expect(showToolbarDetached({ containerRect, titleRef, iconsWidth })).toStrictEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
export default function showToolbarDetached({ containerRect, titleRef, iconsWidth }) {
|
||||
export default function showToolbarDetached({
|
||||
containerRect,
|
||||
titleRef,
|
||||
iconsWidth,
|
||||
headerPaddingLeft,
|
||||
headerPaddingRight,
|
||||
}) {
|
||||
const containerWidth = containerRect.width;
|
||||
const padding = 16;
|
||||
const contentWidth = (titleRef?.current?.clientWidth ?? 0) + iconsWidth + padding;
|
||||
const preventTruncation = 2;
|
||||
const padding = headerPaddingLeft + headerPaddingRight;
|
||||
const contentWidth = (titleRef?.current?.clientWidth ?? 0) + iconsWidth + padding + preventTruncation;
|
||||
const actionToolbarWidth = 128;
|
||||
const notSufficientSpace = containerWidth < contentWidth + actionToolbarWidth;
|
||||
const isTruncated = titleRef?.current?.scrollWidth > titleRef?.current?.offsetWidth;
|
||||
|
||||
@@ -19,7 +19,7 @@ function init() {
|
||||
});
|
||||
|
||||
nebbie.selections().then((s) => s.mount(document.querySelector('.toolbar')));
|
||||
nebbie.field('Alpha').then((s) => s.mount(document.querySelector('.listbox')));
|
||||
nebbie.field('Alpha').then((s) => s.mount(document.querySelector('.listbox'), { search: 'toggle' }));
|
||||
|
||||
document.querySelectorAll('.object').forEach((el) => {
|
||||
const type = el.getAttribute('data-type');
|
||||
|
||||
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |