diff --git a/src/components/ResponsiveList/ResponsiveList.jsx b/src/components/ResponsiveList/ResponsiveList.jsx
index 7c868f9f41..2af074688d 100644
--- a/src/components/ResponsiveList/ResponsiveList.jsx
+++ b/src/components/ResponsiveList/ResponsiveList.jsx
@@ -14,6 +14,7 @@ const ResponsiveList = forwardRef(
{
id,
className,
+ rootClassName,
children,
menuButtonSize,
paddingSize,
@@ -21,13 +22,20 @@ const ResponsiveList = forwardRef(
dialogClassName,
menuButtonClassName,
resizeDebounceTime,
+ menuButtonAriaLabel,
menuButtonProps
},
ref
) => {
const componentRef = useRef(null);
const mergedRef = useMergeRefs({ refs: [ref, componentRef] });
- const index = useElementsOverflowingIndex({ ref: componentRef, children, paddingSize, resizeDebounceTime });
+ const index = useElementsOverflowingIndex({
+ ref: componentRef,
+ children,
+ paddingSize,
+ resizeDebounceTime,
+ ignoreLast: true
+ });
const directChildren = useMemo(() => {
if (index === -1) {
@@ -47,19 +55,37 @@ const ResponsiveList = forwardRef(
}, [children, index]);
return (
-
- {directChildren}
- {!!menuChildren.length && (
+
+ {index !== null && (
+
+ {directChildren}
+ {!!menuChildren.length && (
+
+ {menuChildren}
+
+ )}
+
+ )}
+
+ {children}
- {menuChildren}
+
- )}
+
);
}
@@ -75,6 +101,8 @@ ResponsiveList.propTypes = {
These attributes will be passed to the MenuButton
*/
menuButtonProps: PropTypes.object,
+ menuButtonAriaLabel: "More Actions",
+ rootClassName: PropTypes.string,
dialogClassName: PropTypes.string,
menuButtonSize: PropTypes.oneOf(Object.keys(ResponsiveList.menuButtonSizes)),
/**
@@ -92,6 +120,8 @@ ResponsiveList.defaultProps = {
className: "",
dialogClassName: "",
menuButtonClassName: "",
+ rootClassName: "",
+ menuButtonAriaLabel: "More Actions",
menuButtonProps: {},
menuButtonSize: ResponsiveList.menuButtonSizes.SMALL,
paddingSize: DEFAULT_MINIMAL_MARGIN,
diff --git a/src/components/ResponsiveList/ResponsiveList.scss b/src/components/ResponsiveList/ResponsiveList.scss
index a3701d27a2..f47c77ee5b 100644
--- a/src/components/ResponsiveList/ResponsiveList.scss
+++ b/src/components/ResponsiveList/ResponsiveList.scss
@@ -1,6 +1,9 @@
@import "../../styles/themes.scss";
@import "../../styles/typography.scss";
+.responsive-list--root {
+ position: relative;
+}
.responsive-list--wrapper {
display: flex;
justify-content: flex-end;
@@ -8,6 +11,11 @@
flex-shrink: 0;
}
}
+.responsive-list--dummy {
+ width: 100%;
+ position: absolute;
+ visibility: hidden;
+}
.responsive-list--menu-button-dialog {
display: flex;
}
diff --git a/src/components/ResponsiveList/__stories__/responsiveList.stories.js b/src/components/ResponsiveList/__stories__/responsiveList.stories.js
index 34886d8f3a..2e2d20f26e 100644
--- a/src/components/ResponsiveList/__stories__/responsiveList.stories.js
+++ b/src/components/ResponsiveList/__stories__/responsiveList.stories.js
@@ -1,4 +1,4 @@
-import React from "react";
+import React, { useState } from "react";
import { withPerformance } from "storybook-addon-performance";
import ResponsiveList from "../ResponsiveList";
import "./responsiveListStory.scss";
@@ -16,11 +16,13 @@ import {
Alert,
Broom,
Search as SearchIcon,
- CloseSmall
+ CloseSmall,
+ MoreActions
} from "../../Icon/Icons";
import { MenuItem } from "../../index";
import Menu from "../../Menu/Menu/Menu";
import DescriptionLabel from "../../storybook-helpers/description-label/description-label";
+import { boolean, number } from "@storybook/addon-knobs";
function SecondaryContentComponent() {
return (
@@ -32,6 +34,7 @@ function SecondaryContentComponent() {
}
const DefaultExampleTemplate = (responseListProps) => {
+ const { lessItems } = responseListProps;
return
}>
Add Item
@@ -44,19 +47,19 @@ const DefaultExampleTemplate = (responseListProps) => {
secondaryIconName={() => }
/>
-
+ {!lessItems &&
Clean
-
-
+ }
+ {!lessItems &&
-
-
+ }
+ {!lessItems &&
-
-
+ }
+ {!lessItems &&
-
+ }
@@ -66,8 +69,10 @@ const DefaultExampleTemplate = (responseListProps) => {
}
-export const Sandbox = () => (
-
+export const Sandbox = () => {
+ const lessItems = boolean("Less iitems", false);
+
+ return
Use this component when you want to collapse elements into a menu button which appends to the end of the row. The
list wraps the element with display: flex;
property in order to
@@ -75,19 +80,40 @@ export const Sandbox = () => (
-
+
-);
+};
export const SandboxWithDifferentIcon = () => {
return
- You can also override the MenuButton props. Here's an example of how to use it with Bolt icon
+ You can also override the MenuButton props. Here's an example of how to use it with MoreActions icon
-
+
+
+
+}
+
+
+export const ChangeChildrenCheck = () => {
+ const width = number("width", 300)
+ const knobLessItems = boolean("less items", false);
+ const [lessItems, setLessItems] = useState(true);
+ setTimeout(() => {
+ setLessItems(false);
+ }, 100);
+ return
+
+ This is a story to reproduce a case where the items in the list are changed,
+ it should still be able to recalculate their size.
+ It adds some items at the beginning of the story, and it should be able to calculate the new items size although they weren't drawn yet.
+
+
+
+
}
diff --git a/src/hooks/useElementsOverflowingIndex.js b/src/hooks/useElementsOverflowingIndex.js
index 786e2fa0fb..500665bf7d 100644
--- a/src/hooks/useElementsOverflowingIndex.js
+++ b/src/hooks/useElementsOverflowingIndex.js
@@ -1,14 +1,15 @@
import { useCallback, useEffect, useState } from "react";
+import last from "lodash/last";
import useResizeObserver from "./useResizeObserver";
// Use this hook when you want to get the index of the child which should be hidden from
-function useElementsOverflowingIndex({ ref, children, paddingSize, resizeDebounceTime }) {
+function useElementsOverflowingIndex({ ref, children, paddingSize, resizeDebounceTime, ignoreLast }) {
const [size, setSize] = useState(null);
const onResize = useCallback(
- () => {
- setSize(ref.current.scrollWidth);
+ ({ borderBoxSize }) => {
+ setSize(borderBoxSize.inlineSize);
},
[setSize]
);
@@ -19,10 +20,21 @@ function useElementsOverflowingIndex({ ref, children, paddingSize, resizeDebounc
});
const [aggregatedChildLengths, setAggregatedChildLengths] = useState([]);
- const [indexToSplit, setIndexToSplit] = useState(-1);
+ const [indexToSplit, setIndexToSplit] = useState(null);
useEffect(() => {
- setIndexToSplit(aggregatedChildLengths.findIndex(({ totalLength }) => totalLength > size - paddingSize));
+ if(ignoreLast) {
+ const withoutLast = aggregatedChildLengths.slice(0, -1);
+ const allInWithoutLast = !withoutLast.find(({ totalLength }) => totalLength > size - paddingSize);
+ if(allInWithoutLast) {
+ setIndexToSplit(-1);
+ } else {
+ const lastSize = aggregatedChildLengths.length > 0 ? last(aggregatedChildLengths).childLength : 0;
+ setIndexToSplit(aggregatedChildLengths.findIndex(({ totalLength }) => totalLength > size - paddingSize - lastSize));
+ }
+ } else {
+ setIndexToSplit(aggregatedChildLengths.findIndex(({ totalLength }) => totalLength > size - paddingSize));
+ }
}, [aggregatedChildLengths, size, setIndexToSplit, paddingSize]);
useEffect(() => {