Skip to content

Commit 3fff8ba

Browse files
committed
feat: add portalContainer prop for elements rendered via createPortal (#2275)
1 parent 80921d0 commit 3fff8ba

File tree

12 files changed

+111
-30
lines changed

12 files changed

+111
-30
lines changed

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

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ import { Button } from '@ui5/webcomponents-react/lib/Button';
2929

3030
export interface ActionSheetPropTypes extends Omit<ResponsivePopoverPropTypes, 'children'> {
3131
/**
32-
* Defines the actions of the <code>ActionSheet</code>. <br><b>Note:</b> Although this slot accepts all HTML Elements, it is strongly recommended that you only use `Buttons` in order to preserve the intended design.
32+
* Defines the actions of the `ActionSheet`.
33+
*
34+
* __Note:__ Although this slot accepts all HTML Elements, it is strongly recommended that you only use `Buttons` in order to preserve the intended design.
3335
*/
3436
children?: ReactElement<ButtonPropTypes> | ReactElement<ButtonPropTypes>[];
3537
/**
@@ -49,6 +51,12 @@ export interface ActionSheetPropTypes extends Omit<ResponsivePopoverPropTypes, '
4951
ariaLabel?: string;
5052
};
5153
};
54+
/**
55+
* Defines where modals are rendered into via `React.createPortal`.
56+
*
57+
* Defaults to: `document.body`
58+
*/
59+
portalContainer?: Element;
5260
}
5361

5462
const useStyles = createUseStyles(styles, { name: 'ActionSheet' });
@@ -116,7 +124,8 @@ const ActionSheet: FC<ActionSheetPropTypes> = forwardRef(
116124
onBeforeOpen,
117125
showCancelButton,
118126
alwaysShowHeader,
119-
a11yConfig
127+
a11yConfig,
128+
portalContainer
120129
} = props;
121130
const i18nBundle = useI18nBundle('@ui5/webcomponents-react');
122131
const classes = useStyles();
@@ -235,14 +244,15 @@ const ActionSheet: FC<ActionSheetPropTypes> = forwardRef(
235244
)}
236245
</div>
237246
</ResponsivePopover>,
238-
document.body
247+
portalContainer
239248
);
240249
}
241250
);
242251

243252
ActionSheet.defaultProps = {
244253
showCancelButton: true,
245-
alwaysShowHeader: true
254+
alwaysShowHeader: true,
255+
portalContainer: document.body
246256
};
247257

248258
ActionSheet.displayName = 'ActionSheet';

packages/main/src/components/AnalyticalTable/ColumnHeader/ColumnHeaderContainer.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ interface ColumnHeaderContainerProps {
3838
resizeInfo: Record<string, unknown>;
3939
reactWindowRef: MutableRefObject<any>;
4040
isRtl: boolean;
41+
portalContainer: Element;
4142
}
4243

4344
const useStyles = createUseStyles(styles, { name: 'Resizer' });
@@ -59,7 +60,8 @@ export const ColumnHeaderContainer = forwardRef((props: ColumnHeaderContainerPro
5960
overscanCountHorizontal,
6061
resizeInfo,
6162
reactWindowRef,
62-
isRtl
63+
isRtl,
64+
portalContainer
6365
} = props;
6466
const columnVirtualizer = useVirtual({
6567
size: visibleColumnsWidth.length,
@@ -132,6 +134,7 @@ export const ColumnHeaderContainer = forwardRef((props: ColumnHeaderContainerPro
132134
isDraggable={column.canReorder && !resizeInfo.isResizingColumn}
133135
virtualColumn={virtualColumn}
134136
isRtl={isRtl}
137+
portalContainer={portalContainer}
135138
>
136139
{column.render('Header')}
137140
</ColumnHeader>

packages/main/src/components/AnalyticalTable/ColumnHeader/ColumnHeaderModal.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export interface ColumnHeaderModalProperties {
3333
open: boolean;
3434
setPopoverOpen: (open: boolean) => void;
3535
targetRef: RefObject<any>;
36+
portalContainer: Element;
3637
}
3738

3839
const styles = {
@@ -49,7 +50,7 @@ const styles = {
4950
const useStyles = createUseStyles(styles, { name: 'ColumnHeaderModal' });
5051

5152
export const ColumnHeaderModal = (props: ColumnHeaderModalProperties) => {
52-
const { column, onSort, onGroupBy, open, setPopoverOpen, targetRef } = props;
53+
const { column, onSort, onGroupBy, open, setPopoverOpen, targetRef, portalContainer } = props;
5354
const classes = useStyles();
5455
const showFilter = column.canFilter;
5556
const showGroup = column.canGroupBy;
@@ -197,7 +198,7 @@ export const ColumnHeaderModal = (props: ColumnHeaderModalProperties) => {
197198
)}
198199
</List>
199200
</Popover>,
200-
document.body
201+
portalContainer
201202
);
202203
};
203204
ColumnHeaderModal.displayName = 'ColumnHeaderModal';

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ import React, {
1313
MouseEventHandler,
1414
KeyboardEventHandler,
1515
ReactNode,
16-
ReactNodeArray,
17-
useCallback,
18-
useMemo,
1916
useRef,
2017
useState
2118
} from 'react';
@@ -38,7 +35,8 @@ export interface ColumnHeaderProps {
3835
headerTooltip: string;
3936
virtualColumn: VirtualItem;
4037
isRtl: boolean;
41-
children: ReactNode | ReactNodeArray;
38+
children: ReactNode | ReactNode[];
39+
portalContainer: Element;
4240

4341
//getHeaderProps()
4442
id: string;
@@ -113,7 +111,8 @@ export const ColumnHeader: FC<ColumnHeaderProps> = (props: ColumnHeaderProps) =>
113111
columnIndex,
114112
visibleColumnIndex,
115113
onClick,
116-
onKeyDown
114+
onKeyDown,
115+
portalContainer
117116
} = props;
118117

119118
const isFiltered = column.filterValue && column.filterValue.length > 0;
@@ -238,6 +237,7 @@ export const ColumnHeader: FC<ColumnHeaderProps> = (props: ColumnHeaderProps) =>
238237
targetRef={targetRef}
239238
open={popoverOpen}
240239
setPopoverOpen={setPopoverOpen}
240+
portalContainer={portalContainer}
241241
/>
242242
)}
243243
</div>

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ interface VerticalResizerProps {
4444
internalRowHeight: number;
4545
hasPopInColumns: boolean;
4646
popInRowHeight: number;
47+
portalContainer: Element;
4748
}
4849

4950
const isTouchEvent = (e, touchEvent) => {
@@ -54,7 +55,15 @@ const isTouchEvent = (e, touchEvent) => {
5455
};
5556

5657
export const VerticalResizer = (props: VerticalResizerProps) => {
57-
const { analyticalTableRef, dispatch, extensionsHeight, internalRowHeight, hasPopInColumns, popInRowHeight } = props;
58+
const {
59+
analyticalTableRef,
60+
dispatch,
61+
extensionsHeight,
62+
internalRowHeight,
63+
hasPopInColumns,
64+
popInRowHeight,
65+
portalContainer
66+
} = props;
5867
const classes = useStyles();
5968
const startY = useRef(null);
6069
const verticalResizerRef = useRef(null);
@@ -162,7 +171,7 @@ export const VerticalResizer = (props: VerticalResizerProps) => {
162171
className={classes.resizer}
163172
style={{ top: resizerPosition.top, left: resizerPosition.left, width: resizerPosition.width }}
164173
/>,
165-
document.body
174+
portalContainer
166175
)}
167176
</div>
168177
);

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,12 @@ export interface TableProps extends Omit<CommonProps, 'title'> {
246246
* Defines whether a subcomponent should be rendered as expandable container or directly at the bottom of the row.
247247
*/
248248
alwaysShowSubComponent?: boolean;
249+
/**
250+
* Defines where modals and other elements which should be mounted outside of the DOM hierarchy are rendered into via `React.createPortal`.
251+
*
252+
* Defaults to: `document.body`
253+
*/
254+
portalContainer?: Element;
249255

250256
// events
251257
/**
@@ -366,7 +372,8 @@ const AnalyticalTable: FC<TableProps> = forwardRef((props: TableProps, ref: Ref<
366372
renderRowSubComponent,
367373
alwaysShowSubComponent,
368374
globalFilterValue,
369-
tableInstance
375+
tableInstance,
376+
portalContainer
370377
} = props;
371378

372379
const classes = useStyles();
@@ -749,6 +756,7 @@ const AnalyticalTable: FC<TableProps> = forwardRef((props: TableProps, ref: Ref<
749756
onDragEnd={handleOnDragEnd}
750757
dragOver={dragOver}
751758
isRtl={isRtl}
759+
portalContainer={portalContainer}
752760
/>
753761
)
754762
);
@@ -829,6 +837,7 @@ const AnalyticalTable: FC<TableProps> = forwardRef((props: TableProps, ref: Ref<
829837
dispatch={dispatch}
830838
extensionsHeight={extensionsHeight}
831839
internalRowHeight={internalRowHeight}
840+
portalContainer={portalContainer}
832841
/>
833842
)}
834843
</div>
@@ -867,7 +876,8 @@ AnalyticalTable.defaultProps = {
867876
alternateRowColor: false,
868877
overscanCountHorizontal: 5,
869878
visibleRowCountMode: TableVisibleRowCountMode.FIXED,
870-
alwaysShowSubComponent: false
879+
alwaysShowSubComponent: false,
880+
portalContainer: document.body
871881
};
872882

873883
export { AnalyticalTable };

packages/main/src/components/FilterBar/FilterDialog.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ export const FilterDialog = (props) => {
5555
onGo,
5656
handleSelectionChange,
5757
handleDialogSearch,
58-
handleDialogCancel
58+
handleDialogCancel,
59+
portalContainer
5960
} = props;
6061
const classes = useStyles();
6162
const [searchString, setSearchString] = useState('');
@@ -284,6 +285,6 @@ export const FilterDialog = (props) => {
284285
{renderGroups()}
285286
</div>
286287
</Dialog>,
287-
document.body
288+
portalContainer
288289
);
289290
};

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,12 @@ export interface FilterBarPropTypes extends CommonProps {
119119
* __Note:__ For TypeScript the types of `ref` are bound to the default tag name, if you change it you are responsible to set the respective types yourself.
120120
*/
121121
as?: keyof HTMLElementTagNameMap;
122+
/**
123+
* Defines where modals are rendered into via `React.createPortal`.
124+
*
125+
* Defaults to: `document.body`
126+
*/
127+
portalContainer?: Element;
122128
/**
123129
* The event is fired when the `FilterBar` is collapsed/expanded.
124130
*/
@@ -194,6 +200,7 @@ const FilterBar: FC<FilterBarPropTypes> = forwardRef((props: FilterBarPropTypes,
194200
search,
195201
variants,
196202
as,
203+
portalContainer,
197204

198205
onToggleFilters,
199206
onFiltersDialogOpen,
@@ -463,6 +470,7 @@ const FilterBar: FC<FilterBarPropTypes> = forwardRef((props: FilterBarPropTypes,
463470
showGoButton={showGo}
464471
handleDialogSearch={onFiltersDialogSearch}
465472
handleDialogCancel={onFiltersDialogCancel}
473+
portalContainer={portalContainer}
466474
>
467475
{safeChildren()}
468476
</FilterDialog>
@@ -545,7 +553,8 @@ FilterBar.defaultProps = {
545553
onFiltersDialogSelectionChange: null,
546554
onFiltersDialogSearch: null,
547555
onGo: null,
548-
onRestore: null
556+
onRestore: null,
557+
portalContainer: document.body
549558
};
550559

551560
FilterBar.displayName = 'FilterBar';

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ export interface ObjectPagePropTypes extends CommonProps {
9595
* Defines the ID of the currently `ObjectPageSubSection` section.
9696
*/
9797
selectedSubSectionId?: string;
98+
/**
99+
* Defines where modals are rendered into via `React.createPortal`.
100+
*
101+
* Defaults to: `document.body`
102+
*/
103+
portalContainer?: Element;
98104
/**
99105
* Fired when the selected section changes.
100106
*/
@@ -170,7 +176,8 @@ const ObjectPage: FC<ObjectPagePropTypes> = forwardRef((props: ObjectPagePropTyp
170176
showTitleInHeaderContent,
171177
headerContent,
172178
headerContentPinnable,
173-
a11yConfig
179+
a11yConfig,
180+
portalContainer
174181
} = props;
175182

176183
const classes = useStyles();
@@ -821,7 +828,7 @@ const ObjectPage: FC<ObjectPagePropTypes> = forwardRef((props: ObjectPagePropTyp
821828
))}
822829
</List>
823830
</Popover>,
824-
document.body
831+
portalContainer
825832
)}
826833
</div>
827834
<div data-component-name="ObjectPageContent" className={responsivePaddingClass}>
@@ -843,7 +850,8 @@ ObjectPage.defaultProps = {
843850
image: null,
844851
mode: ObjectPageMode.Default,
845852
imageShapeCircle: false,
846-
showHideHeaderButton: false
853+
showHideHeaderButton: false,
854+
portalContainer: document.body
847855
};
848856

849857
export { ObjectPage };

packages/main/src/components/Toolbar/OverflowPopover.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ interface OverflowPopoverProps {
1212
lastVisibleIndex: number;
1313
contentClass: string;
1414
children: ReactNode;
15+
portalContainer: Element;
1516
}
1617

1718
export const OverflowPopover: FC<OverflowPopoverProps> = (props: OverflowPopoverProps) => {
18-
const { lastVisibleIndex, contentClass, children } = props;
19+
const { lastVisibleIndex, contentClass, children, portalContainer } = props;
1920
const popoverRef = useRef<Ui5PopoverDomRef>();
2021
const [pressed, setPressed] = useState(false);
2122

@@ -82,7 +83,7 @@ export const OverflowPopover: FC<OverflowPopoverProps> = (props: OverflowPopover
8283
<Popover placementType={PlacementType.Bottom} ref={popoverRef} onAfterClose={handleClose}>
8384
<div className={contentClass}>{renderChildren()}</div>
8485
</Popover>,
85-
document.body
86+
portalContainer
8687
)}
8788
</>
8889
);

0 commit comments

Comments
 (0)