Skip to content

Commit a67be72

Browse files
authored
feat(content-explorer): enable independent theming (#4062)
1 parent b09cbf3 commit a67be72

File tree

9 files changed

+59
-28
lines changed

9 files changed

+59
-28
lines changed
Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as React from 'react';
2+
import { useIntl } from 'react-intl';
23
import { DropdownMenu, IconButton } from '@box/blueprint-web';
34
import { Ellipsis } from '@box/blueprint-web-assets/icons/Fill';
45
import type { Crumb } from '../../../common/types/core';
@@ -8,21 +9,26 @@ import messages from '../messages';
89
export interface BreadcrumbDropdownProps {
910
crumbs: Crumb[];
1011
onCrumbClick: (item: string) => void;
12+
portalElement?: HTMLElement;
1113
}
1214

13-
const BreadcrumbDropdown = ({ crumbs, onCrumbClick }: BreadcrumbDropdownProps) => (
14-
<DropdownMenu.Root>
15-
<DropdownMenu.Trigger>
16-
<IconButton aria-label={messages.breadcrumbLabel.defaultMessage} icon={Ellipsis} />
17-
</DropdownMenu.Trigger>
18-
<DropdownMenu.Content>
19-
{crumbs.map(({ id, name }: Crumb) => (
20-
<DropdownMenu.Item key={id} onClick={() => onCrumbClick(id)}>
21-
{name}
22-
</DropdownMenu.Item>
23-
))}
24-
</DropdownMenu.Content>
25-
</DropdownMenu.Root>
26-
);
15+
const BreadcrumbDropdown = ({ crumbs, onCrumbClick, portalElement }: BreadcrumbDropdownProps) => {
16+
const { formatMessage } = useIntl();
17+
18+
return (
19+
<DropdownMenu.Root>
20+
<DropdownMenu.Trigger>
21+
<IconButton aria-label={formatMessage(messages.breadcrumbLabel)} icon={Ellipsis} />
22+
</DropdownMenu.Trigger>
23+
<DropdownMenu.Content container={portalElement}>
24+
{crumbs.map(({ id, name }: Crumb) => (
25+
<DropdownMenu.Item key={id} onClick={() => onCrumbClick(id)}>
26+
{name}
27+
</DropdownMenu.Item>
28+
))}
29+
</DropdownMenu.Content>
30+
</DropdownMenu.Root>
31+
);
32+
};
2733

2834
export default BreadcrumbDropdown;

src/elements/common/breadcrumbs/Breadcrumbs.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export interface BreadcrumbsProps {
1616
delimiter: Delimiter;
1717
isSmall?: boolean;
1818
onCrumbClick: (item: string) => void;
19+
portalElement?: HTMLElement;
1920
rootId: string;
2021
}
2122

@@ -46,12 +47,13 @@ function getBreadcrumb(
4647
isLast: boolean,
4748
onCrumbClick: (item: string) => void,
4849
delimiter: Delimiter,
50+
portalElement?: HTMLElement,
4951
) {
5052
if (Array.isArray(crumbs)) {
5153
const condensed = delimiter !== DELIMITER_CARET;
5254
return (
5355
<span className="be-breadcrumb-more">
54-
<BreadcrumbDropdown crumbs={crumbs} onCrumbClick={onCrumbClick} />
56+
<BreadcrumbDropdown crumbs={crumbs} onCrumbClick={onCrumbClick} portalElement={portalElement} />
5557
<BreadcrumbDelimiter delimiter={condensed ? DELIMITER_SLASH : DELIMITER_CARET} />
5658
</span>
5759
);
@@ -61,7 +63,7 @@ function getBreadcrumb(
6163
return <Breadcrumb delimiter={delimiter} isLast={isLast} name={name} onClick={() => onCrumbClick(id)} />;
6264
}
6365

64-
const Breadcrumbs = ({ rootId, crumbs, onCrumbClick, delimiter, isSmall = false }: BreadcrumbsProps) => {
66+
const Breadcrumbs = ({ crumbs, delimiter, isSmall = false, onCrumbClick, portalElement, rootId }: BreadcrumbsProps) => {
6567
const { formatMessage } = useIntl();
6668

6769
if (!rootId || crumbs.length === 0) {
@@ -86,14 +88,17 @@ const Breadcrumbs = ({ rootId, crumbs, onCrumbClick, delimiter, isSmall = false
8688

8789
// Always show the second last/parent breadcrumb when there are at least 2 crumbs.
8890
const secondLastBreadcrumb =
89-
length > 1 ? getBreadcrumb(filteredCrumbs[length - 2], false, onCrumbClick, delimiter) : null;
91+
length > 1 ? getBreadcrumb(filteredCrumbs[length - 2], false, onCrumbClick, delimiter, portalElement) : null;
9092

9193
// Only show the more dropdown when there were at least 4 crumbs.
9294
const moreBreadcrumbs =
93-
length > 3 ? getBreadcrumb(filteredCrumbs.slice(1, length - 2), false, onCrumbClick, delimiter) : null;
95+
length > 3
96+
? getBreadcrumb(filteredCrumbs.slice(1, length - 2), false, onCrumbClick, delimiter, portalElement)
97+
: null;
9498

9599
// Only show the root breadcrumb when there are at least 3 crumbs.
96-
const firstBreadcrumb = length > 2 ? getBreadcrumb(filteredCrumbs[0], false, onCrumbClick, delimiter) : null;
100+
const firstBreadcrumb =
101+
length > 2 ? getBreadcrumb(filteredCrumbs[0], false, onCrumbClick, delimiter, portalElement) : null;
97102

98103
return (
99104
<div className="be-breadcrumbs">

src/elements/common/sub-header/Add.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@ export interface AddProps {
99
isDisabled: boolean;
1010
onCreate: () => void;
1111
onUpload: () => void;
12+
portalElement?: HTMLElement;
1213
showCreate: boolean;
1314
showUpload: boolean;
1415
}
1516

16-
const Add = ({ isDisabled, onUpload, onCreate, showUpload = true, showCreate = true }: AddProps) => {
17+
const Add = ({ isDisabled, onUpload, onCreate, portalElement, showCreate = true, showUpload = true }: AddProps) => {
1718
const { formatMessage } = useIntl();
1819

1920
return (
@@ -26,7 +27,7 @@ const Add = ({ isDisabled, onUpload, onCreate, showUpload = true, showCreate = t
2627
icon={Plus}
2728
/>
2829
</DropdownMenu.Trigger>
29-
<DropdownMenu.Content>
30+
<DropdownMenu.Content container={portalElement}>
3031
{showUpload && (
3132
<DropdownMenu.Item onClick={onUpload}>{formatMessage(messages.upload)}</DropdownMenu.Item>
3233
)}

src/elements/common/sub-header/Sort.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import messages from '../messages';
99

1010
export interface SortProps {
1111
onSortChange: (sortBy: SortBy, sortDirection: SortDirection) => void;
12+
portalElement?: HTMLElement;
1213
}
1314

1415
type SortItem = [SortBy, SortDirection];
@@ -22,15 +23,15 @@ const SORT_ITEMS: Array<SortItem> = [
2223
[FIELD_SIZE, SORT_DESC],
2324
];
2425

25-
const Sort = ({ onSortChange }: SortProps) => {
26+
const Sort = ({ onSortChange, portalElement }: SortProps) => {
2627
const { formatMessage } = useIntl();
2728

2829
return (
2930
<DropdownMenu.Root>
3031
<DropdownMenu.Trigger>
3132
<IconButton aria-label={formatMessage(messages.sort)} className="be-btn-sort" icon={IconSort} />
3233
</DropdownMenu.Trigger>
33-
<DropdownMenu.Content>
34+
<DropdownMenu.Content container={portalElement}>
3435
{SORT_ITEMS.map(([sortByValue, sortDirectionValue]) => {
3536
const sortItemKey = `${sortByValue}${sortDirectionValue}`;
3637

src/elements/common/sub-header/SubHeader.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export interface SubHeaderProps {
2424
onSortChange: (sortBy: string, sortDirection: string) => void;
2525
onUpload: () => void;
2626
onViewModeChange?: (viewMode: ViewMode) => void;
27+
portalElement?: HTMLElement;
2728
rootId: string;
2829
rootName?: string;
2930
view: View;
@@ -45,6 +46,7 @@ const SubHeader = ({
4546
onSortChange,
4647
onUpload,
4748
onViewModeChange,
49+
portalElement,
4850
rootId,
4951
rootName,
5052
view,
@@ -56,6 +58,7 @@ const SubHeader = ({
5658
currentCollection={currentCollection}
5759
isSmall={isSmall}
5860
onItemClick={onItemClick}
61+
portalElement={portalElement}
5962
rootId={rootId}
6063
rootName={rootName}
6164
view={view}
@@ -75,6 +78,7 @@ const SubHeader = ({
7578
onSortChange={onSortChange}
7679
onUpload={onUpload}
7780
onViewModeChange={onViewModeChange}
81+
portalElement={portalElement}
7882
view={view}
7983
viewMode={viewMode}
8084
/>

src/elements/common/sub-header/SubHeaderLeft.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,21 @@ export interface SubHeaderLeftProps {
1010
currentCollection: Collection;
1111
isSmall: boolean;
1212
onItemClick: (id: string | null, triggerNavigationEvent: boolean | null) => void;
13+
portalElement?: HTMLElement;
1314
rootId: string;
1415
rootName?: string;
1516
view: View;
1617
}
1718

18-
const SubHeaderLeft = ({ view, isSmall, rootId, rootName, currentCollection, onItemClick }: SubHeaderLeftProps) => {
19+
const SubHeaderLeft = ({
20+
currentCollection,
21+
isSmall,
22+
onItemClick,
23+
portalElement,
24+
rootId,
25+
rootName,
26+
view,
27+
}: SubHeaderLeftProps) => {
1928
let crumbs;
2029
const { formatMessage } = useIntl();
2130

@@ -53,6 +62,7 @@ const SubHeaderLeft = ({ view, isSmall, rootId, rootName, currentCollection, onI
5362
delimiter={DELIMITER_CARET}
5463
isSmall={isSmall}
5564
onCrumbClick={onItemClick}
65+
portalElement={portalElement}
5666
rootId={rootId}
5767
/>
5868
);

src/elements/common/sub-header/SubHeaderRight.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export interface SubHeaderRightProps {
2121
onSortChange: (sortBy: SortBy, sortDirection: SortDirection) => void;
2222
onUpload: () => void;
2323
onViewModeChange?: (viewMode: ViewMode) => void;
24+
portalElement?: HTMLElement;
2425
view: View;
2526
viewMode: ViewMode;
2627
}
@@ -38,6 +39,7 @@ const SubHeaderRight = ({
3839
onSortChange,
3940
onUpload,
4041
onViewModeChange,
42+
portalElement,
4143
view,
4244
viewMode,
4345
}: SubHeaderRightProps) => {
@@ -61,12 +63,13 @@ const SubHeaderRight = ({
6163
{hasItems && hasGridView && (
6264
<ViewModeChangeButton viewMode={viewMode} onViewModeChange={onViewModeChange} />
6365
)}
64-
{showSort && <Sort onSortChange={onSortChange} />}
66+
{showSort && <Sort onSortChange={onSortChange} portalElement={portalElement} />}
6567
{showAdd && (
6668
<Add
6769
isDisabled={!isFolder}
6870
onCreate={onCreate}
6971
onUpload={onUpload}
72+
portalElement={portalElement}
7073
showCreate={canCreateNewFolder}
7174
showUpload={canUpload}
7275
/>

src/elements/content-explorer/ContentExplorer.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1646,7 +1646,7 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
16461646
<Internationalize language={language} messages={messages}>
16471647
<TooltipProvider container={this.rootElement}>
16481648
<div id={this.id} className={styleClassName} ref={measureRef} data-testid="content-explorer">
1649-
<ThemingStyles theme={theme} />
1649+
<ThemingStyles selector={`#${this.id}`} theme={theme} />
16501650
<div className="be-app-element" onKeyDown={this.onKeyDown} tabIndex={0}>
16511651
{!isDefaultViewMetadata && (
16521652
<>
@@ -1670,6 +1670,7 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
16701670
onItemClick={this.fetchFolder}
16711671
onSortChange={this.sort}
16721672
onViewModeChange={this.changeViewMode}
1673+
portalElement={this.rootElement}
16731674
/>
16741675
</>
16751676
)}

src/elements/content-uploader/ContentUploader.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1273,7 +1273,7 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
12731273
<TooltipProvider>
12741274
{useUploadsManager ? (
12751275
<div ref={measureRef} className={styleClassName} id={this.id}>
1276-
<ThemingStyles theme={theme} />
1276+
<ThemingStyles selector={`#${this.id}`} theme={theme} />
12771277
<UploadsManager
12781278
isDragging={isDraggingItemsToUploadsManager}
12791279
isExpanded={isUploadsManagerExpanded}
@@ -1290,7 +1290,7 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
12901290
</div>
12911291
) : (
12921292
<div ref={measureRef} className={styleClassName} id={this.id}>
1293-
<ThemingStyles theme={theme} />
1293+
<ThemingStyles selector={`#${this.id}`} theme={theme} />
12941294
<DroppableContent
12951295
addDataTransferItemsToUploadQueue={this.addDroppedItemsToUploadQueue}
12961296
addFiles={this.addFilesToUploadQueue}

0 commit comments

Comments
 (0)