diff --git a/packages/main/src/components/SegmentedButton/SegmentedButton.test.tsx b/packages/main/src/components/SegmentedButton/SegmentedButton.test.tsx
index 1115629e8c8..2bff98dd473 100644
--- a/packages/main/src/components/SegmentedButton/SegmentedButton.test.tsx
+++ b/packages/main/src/components/SegmentedButton/SegmentedButton.test.tsx
@@ -1,9 +1,8 @@
import { getEventFromCallback, mountThemedComponent } from '@shared/tests/utils';
-import { mount } from 'enzyme';
-import React from 'react';
-import sinon from 'sinon';
import { SegmentedButton } from '@ui5/webcomponents-react/lib/SegmentedButton';
import { SegmentedButtonItem } from '@ui5/webcomponents-react/lib/SegmentedButtonItem';
+import React, { cloneElement } from 'react';
+import sinon from 'sinon';
describe('SegmentedButton', () => {
test('Selection', () => {
@@ -25,21 +24,19 @@ describe('SegmentedButton', () => {
test('Update Selection via API', () => {
const callback = sinon.spy();
- const SegmentedBtn = (SegmentedButton as any).InnerComponent;
- const SegmentedBtnItem = (SegmentedButtonItem as any).InnerComponent;
- const wrapper = mount(
-
-
- Test
-
-
- Test
-
-
+
+ const wrapper = mountThemedComponent(
+
+ Test
+ Test
+
);
- wrapper.setProps({ selectedKey: 'btn-2' });
+ expect(wrapper.render()).toMatchSnapshot();
+ wrapper.setProps({
+ children: cloneElement(wrapper.prop('children'), { selectedKey: 'btn-2' })
+ });
wrapper.update();
- expect(wrapper.state('selectedKey')).toEqual('btn-2');
+ expect(wrapper.render()).toMatchSnapshot();
expect(callback.called).toBe(false);
});
});
diff --git a/packages/main/src/components/SegmentedButton/__snapshots__/SegmentedButton.test.tsx.snap b/packages/main/src/components/SegmentedButton/__snapshots__/SegmentedButton.test.tsx.snap
new file mode 100644
index 00000000000..55d744c189d
--- /dev/null
+++ b/packages/main/src/components/SegmentedButton/__snapshots__/SegmentedButton.test.tsx.snap
@@ -0,0 +1,43 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`SegmentedButton Update Selection via API 1`] = `
+
+`;
+
+exports[`SegmentedButton Update Selection via API 2`] = `
+
+`;
diff --git a/packages/main/src/components/SegmentedButton/demo.stories.tsx b/packages/main/src/components/SegmentedButton/demo.stories.tsx
index 59d5adb560a..d5155056561 100644
--- a/packages/main/src/components/SegmentedButton/demo.stories.tsx
+++ b/packages/main/src/components/SegmentedButton/demo.stories.tsx
@@ -8,7 +8,7 @@ import { SegmentedButtonItem } from '@ui5/webcomponents-react/lib/SegmentedButto
export const renderStory = () => {
return (
@@ -16,7 +16,9 @@ export const renderStory = () => {
}>
Button 2
- Button 3
+
+ Button 3
+
);
};
diff --git a/packages/main/src/components/SegmentedButton/index.tsx b/packages/main/src/components/SegmentedButton/index.tsx
index 339b6771bd7..5ac16decada 100644
--- a/packages/main/src/components/SegmentedButton/index.tsx
+++ b/packages/main/src/components/SegmentedButton/index.tsx
@@ -1,34 +1,36 @@
-import { Event, StyleClassHelper, withStyles } from '@ui5/webcomponents-react-base';
-import React, { Children, cloneElement, Component, CSSProperties, ReactElement, RefObject } from 'react';
-import { ClassProps } from '../../interfaces/ClassProps';
-import { CommonProps } from '../../interfaces/CommonProps';
+import { Event, StyleClassHelper, useConsolidatedRef } from '@ui5/webcomponents-react-base';
import { ContentDensity } from '@ui5/webcomponents-react/lib/ContentDensity';
-import { SegmentedButtonItemPropTypes } from '../SegmentedButtonItem';
+import React, {
+ Children,
+ cloneElement,
+ FC,
+ forwardRef,
+ ReactNode,
+ Ref,
+ RefObject,
+ useCallback,
+ useEffect,
+ useState
+} from 'react';
+import { createUseStyles } from 'react-jss';
+import { CommonProps } from '../../interfaces/CommonProps';
+import { JSSTheme } from '../../interfaces/JSSTheme';
export type SelectedKey = string | number;
export interface SegmentedButtonPropTypes extends CommonProps {
- enabled?: boolean;
+ disabled?: boolean;
selectedKey?: SelectedKey;
- children: ReactElement | Array>;
+ children: ReactNode | ReactNode[];
onItemSelected?: (event: Event) => void;
}
-interface SegmentedButtonInternalProps extends SegmentedButtonPropTypes, ClassProps {}
-
-interface SegmentedButtonState {
- selectedKey: SelectedKey;
- prevPropSelectedKey: SelectedKey;
- itemWidth: CSSProperties['width'];
-}
-
const styles = ({ contentDensity }) => ({
segmentedButton: {
verticalAlign: 'top',
position: 'relative',
margin: '0',
padding: contentDensity === ContentDensity.Compact ? '0.1875rem 0' : '0.250rem 0',
- WebkitTapHighlightColor: 'rgba(255, 255, 255, 0)',
border: 'none',
whiteSpace: 'nowrap',
display: 'inline-block',
@@ -41,105 +43,100 @@ const styles = ({ contentDensity }) => ({
}
});
-@withStyles(styles)
-export class SegmentedButton extends Component {
- static defaultProps = {
- enabled: true,
- selectedKey: '',
- onItemSelected: null,
- width: null
- };
-
- state = {
- selectedKey: null,
- prevPropSelectedKey: null,
- itemWidth: 'auto'
- };
-
- items: RefObject = (this.props as SegmentedButtonInternalProps).innerRef;
-
- static getDerivedStateFromProps(nextProps, prevState) {
- if (prevState.prevPropSelectedKey !== nextProps.selectedKey) {
- const newKey = nextProps.selectedKey ? nextProps.selectedKey : nextProps.children[0].props.id;
- return {
- selectedKey: newKey,
- prevPropSelectedKey: newKey
- };
- }
- return null;
- }
+const useStyles = createUseStyles>(styles, { name: 'SegmentedButton' });
- private handleSegmentedButtonItemSelected = (e) => {
- const selectedKey = e.getParameter('selectedKey');
- if (selectedKey !== this.state.selectedKey) {
- this.setState({
- selectedKey
- });
- if (this.props.onItemSelected) {
- this.props.onItemSelected(Event.of(this, e.getOriginalEvent(), e.getParameters()));
- }
- }
- };
-
- private updateChildElementSize() {
- let maxWidth = 0;
- requestAnimationFrame(() => {
- for (let i = 0; i < this.items.current.childElementCount; i++) {
- const item = this.items.current.children.item(i) as HTMLUListElement;
- if (item.offsetWidth && item.offsetWidth > maxWidth) {
- maxWidth = item.offsetWidth;
- }
- }
+const SegmentedButton: FC = forwardRef(
+ (props: SegmentedButtonPropTypes, ref: Ref) => {
+ const { children, disabled, className, style, tooltip, slot, onItemSelected, selectedKey } = props;
- if (maxWidth > this.items.current.offsetWidth) {
- this.setState({
- itemWidth: 'auto'
- });
- } else if (this.state.itemWidth !== `${maxWidth}px`) {
- this.setState({
- itemWidth: `${maxWidth}px`
- });
+ const listRef: RefObject = useConsolidatedRef(ref);
+
+ const [internalSelectedKey, setSelectedKey] = useState(() => {
+ if (selectedKey) return selectedKey;
+ const firstChild: any = Children.toArray(children)[0];
+ if (firstChild && firstChild.props) {
+ return firstChild.props.id;
}
+ return null;
});
- }
- componentDidMount() {
- this.updateChildElementSize();
- }
-
- componentDidUpdate() {
- this.updateChildElementSize();
- }
+ useEffect(() => {
+ if (selectedKey) {
+ setSelectedKey(selectedKey);
+ }
+ }, [selectedKey, setSelectedKey]);
- render() {
- const { children, enabled, classes, className, style, tooltip, slot } = this.props as SegmentedButtonInternalProps;
- const { selectedKey } = this.state;
+ const classes = useStyles();
const segmentedBtnClasses = StyleClassHelper.of(classes.segmentedButton);
if (className) {
segmentedBtnClasses.put(className);
}
+ const handleSegmentedButtonItemSelected = useCallback(
+ (e) => {
+ const newSelectedKey = e.getParameter('selectedKey');
+ if (newSelectedKey !== internalSelectedKey) {
+ setSelectedKey(newSelectedKey);
+ if (typeof onItemSelected === 'function') {
+ onItemSelected(Event.of(null, e.getOriginalEvent(), e.getParameters()));
+ }
+ }
+ },
+ [internalSelectedKey, setSelectedKey, onItemSelected]
+ );
+
+ useEffect(() => {
+ requestAnimationFrame(() => {
+ let maxWidth = 0;
+ for (let i = 0; i < listRef.current.childElementCount; i++) {
+ const item = listRef.current.children.item(i) as HTMLLIElement;
+ if (item.offsetWidth && item.offsetWidth > maxWidth) {
+ maxWidth = item.offsetWidth;
+ }
+ }
+ if (maxWidth < listRef.current.offsetWidth) {
+ for (let i = 0; i < listRef.current.childElementCount; i++) {
+ const item = listRef.current.children.item(i) as HTMLLIElement;
+ if (item.getAttribute('data-has-own-width') === 'false') {
+ item.style.width = `${maxWidth}px`;
+ }
+ }
+ }
+ });
+ }, [children, listRef]);
+
return (
- {Children.map(children, (item: any) =>
- cloneElement(item, {
- key: item.props.id,
- selected: selectedKey === item.props.id,
- enabled: enabled === false ? enabled : item.props.enabled,
- width: item.props.width ? item.props.width : this.state.itemWidth,
- onClick: this.handleSegmentedButtonItemSelected
- })
- )}
+ {Children.toArray(children)
+ .filter(Boolean)
+ .map((item: any) =>
+ cloneElement(item, {
+ key: item.props.id,
+ selected: internalSelectedKey === item.props.id,
+ disabled: disabled === true ? disabled : item.props.disabled,
+ onClick: handleSegmentedButtonItemSelected
+ })
+ )}
);
}
-}
+);
+
+SegmentedButton.displayName = 'SegmentedButton';
+
+SegmentedButton.defaultProps = {
+ disabled: false,
+ selectedKey: '',
+ onItemSelected: null
+};
+
+export { SegmentedButton };
diff --git a/packages/main/src/components/SegmentedButtonItem/SegmentedButtonItem.jss.ts b/packages/main/src/components/SegmentedButtonItem/SegmentedButtonItem.jss.ts
index 796456c02a7..5dd689576ba 100644
--- a/packages/main/src/components/SegmentedButtonItem/SegmentedButtonItem.jss.ts
+++ b/packages/main/src/components/SegmentedButtonItem/SegmentedButtonItem.jss.ts
@@ -2,7 +2,7 @@ import { fonts } from '@ui5/webcomponents-react-base';
import { JSSTheme } from '../../interfaces/JSSTheme';
import { ContentDensity } from '@ui5/webcomponents-react/lib/ContentDensity';
-const styles = ({ theme, contentDensity, parameters }: JSSTheme) => ({
+const styles = ({ contentDensity, parameters }: JSSTheme) => ({
segmentedButtonItem: {
fontFamily: fonts.sapUiFontFamily,
listStyle: 'none',
@@ -41,6 +41,7 @@ const styles = ({ theme, contentDensity, parameters }: JSSTheme) => ({
background: parameters.sapUiSegmentedButtonSelectedBackground,
color: parameters.sapUiSegmentedButtonSelectedTextColor,
borderColor: parameters.sapUiSegmentedButtonSelectedHoverBorderColor,
+ '--sapUiContentNonInteractiveIconColor': parameters.sapUiContentContrastIconColor,
'$:active': {
background: parameters.sapUiButtonActiveBackground,
color: parameters.sapUiButtonActiveTextColor
diff --git a/packages/main/src/components/SegmentedButtonItem/SegmentedButtonItem.test.tsx b/packages/main/src/components/SegmentedButtonItem/SegmentedButtonItem.test.tsx
index bcd1c6af3fa..faf97c6b0e9 100644
--- a/packages/main/src/components/SegmentedButtonItem/SegmentedButtonItem.test.tsx
+++ b/packages/main/src/components/SegmentedButtonItem/SegmentedButtonItem.test.tsx
@@ -32,7 +32,7 @@ describe('SegmentedButtonItem', () => {
test('SegmentedButtonItem Disabled', () => {
const callback = sinon.spy();
const wrapper = mountThemedComponent(
- } enabled={false} onClick={callback} />
+ } disabled onClick={callback} />
);
wrapper.simulate('click');
expect(wrapper.render()).toMatchSnapshot();
diff --git a/packages/main/src/components/SegmentedButtonItem/__snapshots__/SegmentedButtonItem.test.tsx.snap b/packages/main/src/components/SegmentedButtonItem/__snapshots__/SegmentedButtonItem.test.tsx.snap
index 35754ee8251..713cffd0762 100644
--- a/packages/main/src/components/SegmentedButtonItem/__snapshots__/SegmentedButtonItem.test.tsx.snap
+++ b/packages/main/src/components/SegmentedButtonItem/__snapshots__/SegmentedButtonItem.test.tsx.snap
@@ -2,10 +2,11 @@
exports[`SegmentedButtonItem Basic SegmentedButtonItem 1`] = `