Skip to content

Commit 018337f

Browse files
authored
feat: add slot props and deprecated render methods (#436)
1 parent 93a2efb commit 018337f

29 files changed

+224
-252
lines changed

docs/Guidelines.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ Global Styles compliant to the Fiori 2.0 Design Guidelines are located in [ui5-w
2222
- All Event handlers **must** start with `on`.<br />
2323
e.g. `onClick`, `onSelect`, `onSelectionChange`, .etc<br />
2424
All Events must pass a instance of the `Event`-Class as single parameter.
25-
- When passing additional elements into a component, a render function should be used. This prop must start with `render`<br />
26-
e.g. `renderExtension`, `renderHeaderContent`, .etc
25+
- When passing additional elements into a component, a slot should be used. This prop should contain a `ReactNode` or an array of ReactNodes (`ReactNode[]` or `ReactNodeArray`)
2726
- If you have a stateful component and use `getDerivedStateFromProps`, please store the previous props in a `prevProps` object in the state.<br />
2827
e.g. `state = { selectedKey: 1, prevProps: { selectedKey: 2 } }`
2928

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { useEffect, useMemo } from 'react';
2+
import { deprecationNotice } from '../utils';
3+
4+
export const useDeprecateRenderMethods = (props, renderMethodName, slotName) => {
5+
useEffect(() => {
6+
if (props[renderMethodName]) {
7+
deprecationNotice(
8+
`${renderMethodName}`,
9+
`The prop '${renderMethodName}' is deprecated and will be removed in the next major release.\nPlease use '${slotName}' instead.`
10+
);
11+
}
12+
}, []);
13+
14+
return useMemo(() => {
15+
return props[slotName] ?? (typeof props[renderMethodName] === 'function' ? props[renderMethodName]() : null);
16+
}, [props[renderMethodName], props[slotName]]);
17+
};

packages/base/src/hooks/useIsMounted.ts

Whitespace-only changes.

packages/base/src/lib/hooks.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { useConsolidatedRef } from '../hooks/useConsolidatedRef';
2+
import { useDeprecateRenderMethods } from '../hooks/useDeprecateRenderMethods';
3+
import { usePassThroughHtmlProps } from '../hooks/usePassThroughHtmlProps';
4+
import { useViewportRange } from '../hooks/useViewportRange';
5+
6+
export { useConsolidatedRef, useDeprecateRenderMethods, usePassThroughHtmlProps, useViewportRange };

packages/base/src/styling/HSLColor.ts

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -84,33 +84,23 @@ export class HSLColor {
8484
}
8585

8686
static lighten(color: HSLColor | string, amount: number) {
87-
return HSLColor.of(color)
88-
.clone()
89-
.lighten(amount);
87+
return HSLColor.of(color).clone().lighten(amount);
9088
}
9189

9290
static darken(color: HSLColor | string, amount: number) {
93-
return HSLColor.of(color)
94-
.clone()
95-
.darken(amount);
91+
return HSLColor.of(color).clone().darken(amount);
9692
}
9793

9894
static saturate(color: HSLColor | string, amount: number) {
99-
return HSLColor.of(color)
100-
.clone()
101-
.saturate(amount);
95+
return HSLColor.of(color).clone().saturate(amount);
10296
}
10397

10498
static desaturate(color: HSLColor | string, amount: number) {
105-
return HSLColor.of(color)
106-
.clone()
107-
.desaturate(amount);
99+
return HSLColor.of(color).clone().desaturate(amount);
108100
}
109101

110102
static hsla(color: HSLColor | string, amount: number) {
111-
return HSLColor.of(color)
112-
.clone()
113-
.setAlpha(amount);
103+
return HSLColor.of(color).clone().setAlpha(amount);
114104
}
115105

116106
getHue() {

packages/charts/src/components/RadialChart/RadialChart.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ interface RadialChartProps extends CommonProps {
1313
maxValue?: number;
1414
displayValue?: number | string;
1515
color?: CSSProperties['color'];
16-
onDataPointClick?: (event: CustomEvent<{value: unknown; payload: unknown; xIndex: number}>) => void;
16+
onDataPointClick?: (event: CustomEvent<{ value: unknown; payload: unknown; xIndex: number }>) => void;
1717
height?: number | string;
1818
width?: number | string;
1919
}

packages/charts/src/internal/withChartContainer.tsx

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,18 +63,15 @@ export const withChartContainer = (Component: ComponentType<any>) => {
6363

6464
const chartHeight = useMemo(() => (noLegend ? height : height - 60), [noLegend, height]);
6565

66-
const chartWrapperStyles: CSSProperties = useMemo(
67-
() => {
68-
let innerChartWrapperStyles : CSSProperties = {
69-
position: 'relative',
70-
height: chartHeight >= 0 ? `${chartHeight}px` : 'auto',
71-
width: width ? `${width}px` : 'auto'
72-
};
66+
const chartWrapperStyles: CSSProperties = useMemo(() => {
67+
let innerChartWrapperStyles: CSSProperties = {
68+
position: 'relative',
69+
height: chartHeight >= 0 ? `${chartHeight}px` : 'auto',
70+
width: width ? `${width}px` : 'auto'
71+
};
7372

74-
return innerChartWrapperStyles
75-
},
76-
[chartHeight, width]
77-
);
73+
return innerChartWrapperStyles;
74+
}, [chartHeight, width]);
7875

7976
return (
8077
<div ref={outerContainer} className={classNames} style={inlineStyle} title={tooltip} slot={slot}>

packages/charts/src/util/Utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export const useMergedConfig = (x, y) => {
1111

1212
// this needs to be a function as we need the `this` of the chart;
1313
export const formatAxisCallback = (formatter) =>
14-
function(value) {
14+
function (value) {
1515
// @ts-ignore
1616
const currentDataset = this.chart.data.datasets[0];
1717
return formatter(value, currentDataset);

packages/main/src/components/AnalyticalTable/AnalyticalTable.test.tsx

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -148,20 +148,14 @@ describe('AnalyticalTable', () => {
148148
expect(wrapper.render()).toMatchSnapshot();
149149

150150
// test asc function inside the popover element
151-
let component = wrapper
152-
.find('ui5-li')
153-
.at(1)
154-
.instance();
151+
let component = wrapper.find('ui5-li').at(1).instance();
155152
// @ts-ignore
156153
component.click();
157154

158155
expect(wrapper.render()).toMatchSnapshot();
159156

160157
// test desc function inside the popover element
161-
component = wrapper
162-
.find('ui5-li')
163-
.at(0)
164-
.instance();
158+
component = wrapper.find('ui5-li').at(0).instance();
165159
// @ts-ignore
166160
component.click();
167161

@@ -186,10 +180,7 @@ describe('AnalyticalTable', () => {
186180
/>
187181
);
188182

189-
const colInst = wrapper
190-
.find('div[role="columnheader"]')
191-
.at(0)
192-
.instance();
183+
const colInst = wrapper.find('div[role="columnheader"]').at(0).instance();
193184

194185
// @ts-ignore
195186
expect(colInst.draggable).toBeDefined();

packages/main/src/components/AnalyticalTable/demo/demo.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ export const tableWithExtension = () => {
171171
filterable={boolean('filterable', true)}
172172
visibleRows={number('visibleRows', 15)}
173173
groupable={boolean('groupable', true)}
174-
renderExtension={() => <Button>Hello from the Table Extension!</Button>}
174+
extension={<Button>Hello from the Table Extension!</Button>}
175175
/>
176176
);
177177
};

packages/main/src/components/AnalyticalTable/demo/generateData.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ValueState } from "@ui5/webcomponents-react/lib/ValueState";
1+
import { ValueState } from '@ui5/webcomponents-react/lib/ValueState';
22

33
const getRandomArrayEntry = (array) => array[Math.floor(Math.random() * array.length)];
44

@@ -38,7 +38,9 @@ const newEntry = () => {
3838
name: getRandomName(),
3939
age: getRandomNumber(18, 65)
4040
},
41-
status: [ValueState.None, ValueState.Information, ValueState.Success, ValueState.Warning, ValueState.Error][Math.floor(Math.random() * 4)]
41+
status: [ValueState.None, ValueState.Information, ValueState.Success, ValueState.Warning, ValueState.Error][
42+
Math.floor(Math.random() * 4)
43+
]
4244
};
4345
};
4446

@@ -63,7 +65,9 @@ const makeEntry = () => ({
6365
name: getRandomName(),
6466
age: getRandomNumber(18, 65)
6567
},
66-
status: [ValueState.None, ValueState.Information, ValueState.Success, ValueState.Warning, ValueState.Error][Math.floor(Math.random() * 4)]
68+
status: [ValueState.None, ValueState.Information, ValueState.Success, ValueState.Warning, ValueState.Error][
69+
Math.floor(Math.random() * 4)
70+
]
6771
});
6872

6973
const generateData = (numEntries, isTree = false) => {

packages/main/src/components/AnalyticalTable/hooks/useDynamicColumnWidths.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ const columnsDeps = (deps, { instance: { state, webComponentsReactProperties } }
1818
];
1919

2020
const columns = (columns, { instance }) => {
21-
2221
if (!instance.state || !instance.rows) {
2322
return columns;
2423
}

packages/main/src/components/AnalyticalTable/index.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { createComponentStyles } from '@ui5/webcomponents-react-base/lib/createC
22
import { StyleClassHelper } from '@ui5/webcomponents-react-base/lib/StyleClassHelper';
33
import { usePassThroughHtmlProps } from '@ui5/webcomponents-react-base/lib/usePassThroughHtmlProps';
44
import { enrichEventWithDetails } from '@ui5/webcomponents-react-base/lib/Utils';
5+
import { useDeprecateRenderMethods } from '@ui5/webcomponents-react-base/lib/hooks';
56
import { TableScaleWidthMode } from '@ui5/webcomponents-react/lib/TableScaleWidthMode';
67
import { TableSelectionBehavior } from '@ui5/webcomponents-react/lib/TableSelectionBehavior';
78
import { TableSelectionMode } from '@ui5/webcomponents-react/lib/TableSelectionMode';
@@ -71,6 +72,7 @@ export interface TableProps extends CommonProps {
7172
* Extension section of the Table. If not set, no extension area will be rendered
7273
*/
7374
renderExtension?: () => ReactNode;
75+
extension?: ReactNode;
7476

7577
// appearance
7678

@@ -137,7 +139,6 @@ const AnalyticalTable: FC<TableProps> = forwardRef((props: TableProps, ref: Ref<
137139
style,
138140
tooltip,
139141
title,
140-
renderExtension,
141142
loading,
142143
groupBy,
143144
selectionMode,
@@ -176,6 +177,7 @@ const AnalyticalTable: FC<TableProps> = forwardRef((props: TableProps, ref: Ref<
176177
const [analyticalTableRef, reactWindowRef] = useTableScrollHandles(ref);
177178
const tableRef: RefObject<HTMLDivElement> = useRef();
178179
const resizeObserverInitialized = useRef(false);
180+
const extension = useDeprecateRenderMethods(props, 'renderExtension', 'extension');
179181

180182
const getSubRows = useCallback((row) => row[subRowsKey] || [], [subRowsKey]);
181183

@@ -257,7 +259,7 @@ const AnalyticalTable: FC<TableProps> = forwardRef((props: TableProps, ref: Ref<
257259
useEffect(() => {
258260
// @ts-ignore
259261
const tableWidthObserver = new ResizeObserver(() => {
260-
if(resizeObserverInitialized.current) {
262+
if (resizeObserverInitialized.current) {
261263
updateTableClientWidth();
262264
}
263265
resizeObserverInitialized.current = true;
@@ -359,7 +361,7 @@ const AnalyticalTable: FC<TableProps> = forwardRef((props: TableProps, ref: Ref<
359361
return (
360362
<div className={className} style={inlineStyle} title={tooltip} ref={analyticalTableRef} {...passThroughProps}>
361363
{title && <TitleBar>{title}</TitleBar>}
362-
{typeof renderExtension === 'function' && <div>{renderExtension()}</div>}
364+
{extension && <div>{extension}</div>}
363365
<div className={tableContainerClasses.valueOf()} ref={tableRef}>
364366
{
365367
<div

packages/main/src/components/Bar/Bar.test.tsx

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ describe('Bar', () => {
1515
test('Render all content', () => {
1616
const wrapper = mount(
1717
<Bar
18-
renderContentLeft={() => <div>Content Left</div>}
19-
renderContentMiddle={() => <div>Content Middle</div>}
20-
renderContentRight={() => <div>Content Right</div>}
18+
contentLeft={<div>Content Left</div>}
19+
contentMiddle={<div>Content Middle</div>}
20+
contentRight={<div>Content Right</div>}
2121
/>
2222
);
2323
expect(wrapper.render()).toMatchSnapshot();
@@ -29,11 +29,7 @@ describe('Bar', () => {
2929
const text3 = 'Content Right';
3030

3131
const wrapper = mount(
32-
<Bar
33-
renderContentLeft={() => <div>{text1}</div>}
34-
renderContentMiddle={() => <div>{text2}</div>}
35-
renderContentRight={() => <div>{text3}</div>}
36-
/>
32+
<Bar contentLeft={<div>{text1}</div>} contentMiddle={<div>{text2}</div>} contentRight={<div>{text3}</div>} />
3733
);
3834
expect(wrapper.text()).toContain(text1);
3935
expect(wrapper.text()).toContain(text2);

packages/main/src/components/Bar/demo.stories.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ export const defaultStory = () => {
88
return (
99
<Bar
1010
design={select('design', BarDesign, BarDesign.Auto)}
11-
renderContentLeft={() => <Label>Content Left</Label>}
12-
renderContentMiddle={() => <Label>Content Middle</Label>}
13-
renderContentRight={() => <Label>Content Right</Label>}
11+
contentLeft={<Label>Content Left</Label>}
12+
contentMiddle={<Label>Content Middle</Label>}
13+
contentRight={<Label>Content Right</Label>}
1414
/>
1515
);
1616
};

packages/main/src/components/Bar/index.tsx

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { StyleClassHelper } from '@ui5/webcomponents-react-base/lib/StyleClassHelper';
22
import { usePassThroughHtmlProps } from '@ui5/webcomponents-react-base/lib/usePassThroughHtmlProps';
3-
import React, { FC, forwardRef, Ref } from 'react';
3+
import { useDeprecateRenderMethods } from '@ui5/webcomponents-react-base/lib/hooks';
4+
import React, { FC, forwardRef, ReactNode, Ref } from 'react';
45
import { createComponentStyles } from '@ui5/webcomponents-react-base/lib/createComponentStyles';
56
import { CommonProps } from '../../interfaces/CommonProps';
67
import { BarDesign } from '../../lib/BarDesign';
@@ -10,6 +11,9 @@ export interface BarPropTypes extends CommonProps {
1011
renderContentLeft?: () => JSX.Element;
1112
renderContentMiddle?: () => JSX.Element;
1213
renderContentRight?: () => JSX.Element;
14+
contentLeft: ReactNode | ReactNode[];
15+
contentMiddle: ReactNode | ReactNode[];
16+
contentRight: ReactNode | ReactNode[];
1317
design?: BarDesign;
1418
}
1519

@@ -19,7 +23,10 @@ const useStyles = createComponentStyles(styles, { name: 'Bar' });
1923
* <code>import { Bar } from '@ui5/webcomponents-react/lib/Bar';</code>
2024
*/
2125
const Bar: FC<BarPropTypes> = forwardRef((props: BarPropTypes, ref: Ref<HTMLDivElement>) => {
22-
const { renderContentLeft, renderContentMiddle, renderContentRight, className, style, tooltip, slot, design } = props;
26+
const { className, style, tooltip, slot, design } = props;
27+
const contentLeft = useDeprecateRenderMethods(props, 'renderContentLeft', 'contentLeft');
28+
const contentMiddle = useDeprecateRenderMethods(props, 'renderContentMiddle', 'contentMiddle');
29+
const contentRight = useDeprecateRenderMethods(props, 'renderContentRight', 'contentRight');
2330

2431
const classes = useStyles();
2532

@@ -56,24 +63,21 @@ const Bar: FC<BarPropTypes> = forwardRef((props: BarPropTypes, ref: Ref<HTMLDivE
5663
{...passThroughProps}
5764
>
5865
<div data-bar-part="Left" className={classes.left}>
59-
{renderContentLeft()}
66+
{contentLeft}
6067
</div>
6168
<div data-bar-part="Center" className={classes.center}>
62-
<div className={classes.inner}>{renderContentMiddle()}</div>
69+
<div className={classes.inner}>{contentMiddle}</div>
6370
</div>
6471
<div data-bar-part="Right" className={classes.right}>
65-
{renderContentRight()}
72+
{contentRight}
6673
</div>
6774
</div>
6875
);
6976
});
7077

7178
Bar.displayName = 'Bar';
7279
Bar.defaultProps = {
73-
design: BarDesign.Auto,
74-
renderContentLeft: () => null,
75-
renderContentMiddle: () => null,
76-
renderContentRight: () => null
80+
design: BarDesign.Auto
7781
};
7882

7983
export { Bar };

0 commit comments

Comments
 (0)