diff --git a/flow-typed/npm/@box/blueprint-web-assets_vx.x.x.js b/flow-typed/npm/@box/blueprint-web-assets_vx.x.x.js index 9edc77abd2..e2a1e28542 100644 --- a/flow-typed/npm/@box/blueprint-web-assets_vx.x.x.js +++ b/flow-typed/npm/@box/blueprint-web-assets_vx.x.x.js @@ -7,8 +7,14 @@ declare module '@box/blueprint-web-assets/icons/Medium' { declare export var AlertCircle: React$ComponentType; declare export var AlertTriangle: React$ComponentType; declare export var XMark: React$ComponentType; - declare export var BoxAiAdvancedLogo24: React$ComponentType; - declare export var BoxAiLogo24: React$ComponentType; + declare export var Comment: React$ComponentType; + declare export var Metadata: React$ComponentType; +} + +declare module '@box/blueprint-web-assets/icons/MediumFilled' { + declare export var Comment: React$ComponentType; + declare export var InformationCircle: React$ComponentType; + declare export var Metadata: React$ComponentType; } declare module '@box/blueprint-web-assets/icons/Content' { @@ -37,6 +43,7 @@ declare module '@box/blueprint-web-assets/icons/Fill' { declare module '@box/blueprint-web-assets/icons/Logo' { declare export var BoxLogo: React$ComponentType; declare export var BoxAiLogo: React$ComponentType; + declare export var BoxAiLogo24: React$ComponentType; } declare module '@box/blueprint-web-assets/illustrations/Medium' { @@ -56,4 +63,5 @@ declare module '@box/blueprint-web-assets/tokens/tokens' { declare export var Gray50: any; declare export var Size3: any; declare export var Size6: any; + declare export var IconIconBlue: any; } diff --git a/src/components/sidebar-toggle-button/SidebarToggleButton.js b/src/components/sidebar-toggle-button/SidebarToggleButton.js index 3564febd1f..2d66846097 100644 --- a/src/components/sidebar-toggle-button/SidebarToggleButton.js +++ b/src/components/sidebar-toggle-button/SidebarToggleButton.js @@ -3,12 +3,12 @@ import * as React from 'react'; import classNames from 'classnames'; import { injectIntl } from 'react-intl'; import type { IntlShape } from 'react-intl'; - +import { Tooltip as BPTooltip } from '@box/blueprint-web'; import IconHide from '../../icons/general/IconHide'; import IconShow from '../../icons/general/IconShow'; import PlainButton from '../plain-button'; import Tooltip from '../tooltip'; - +import { useFeatureConfig } from '../../elements/common/feature-checking'; import messages from '../../elements/common/messages'; import './SidebarToggleButton.scss'; @@ -32,14 +32,15 @@ const SidebarToggleButton = ({ onClick, ...rest }: Props) => { + const { enabled: isPreviewModernizationEnabled } = useFeatureConfig('previewModernization'); const isCollapsed = !isOpen ? 'collapsed' : ''; const intlMessage = isOpen ? messages.sidebarHide : messages.sidebarShow; const intlText = intl.formatMessage(intlMessage); const classes = classNames(className, 'bdl-SidebarToggleButton', { 'bdl-is-collapsed': isCollapsed, + 'bdl-SidebarToggleButton--modernized': isPreviewModernizationEnabled, }); const tooltipPosition = direction === DIRECTION_LEFT ? 'middle-right' : 'middle-left'; - const renderButton = () => { if (direction === DIRECTION_LEFT) { return isOpen ? : ; @@ -47,6 +48,20 @@ const SidebarToggleButton = ({ return isOpen ? : ; }; + if (isPreviewModernizationEnabled) { + const tooltipPositionModernized = direction === DIRECTION_LEFT ? DIRECTION_RIGHT : DIRECTION_LEFT; + + return ( + + {/* Workaround to attach BP tooltip to legacy button, remove span when buttons are migrated to BP */} + + + {renderButton()} + + + + ); + } return ( diff --git a/src/components/sidebar-toggle-button/SidebarToggleButton.scss b/src/components/sidebar-toggle-button/SidebarToggleButton.scss index 510da1944b..f62b6a3d1a 100644 --- a/src/components/sidebar-toggle-button/SidebarToggleButton.scss +++ b/src/components/sidebar-toggle-button/SidebarToggleButton.scss @@ -29,3 +29,17 @@ } } } + +.bcs-SidebarNav--modernized { + .bdl-SidebarToggleButton { + &:not(.bdl-is-disabled):hover svg, + &:not(.is-disabled):hover svg, + &:not(.bdl-is-disabled):focus svg, + &:not(.is-disabled):focus svg, + &.bdl-is-collapsed svg, + &.bdl-is-collapsed:hover svg { + transform: scale(1.09); + transition: transform 150ms; + } + } +} diff --git a/src/elements/content-sidebar/SidebarNav.js b/src/elements/content-sidebar/SidebarNav.js index d92cee1eba..208aec84ca 100644 --- a/src/elements/content-sidebar/SidebarNav.js +++ b/src/elements/content-sidebar/SidebarNav.js @@ -9,10 +9,18 @@ import { injectIntl } from 'react-intl'; import type { IntlShape } from 'react-intl'; import classNames from 'classnames'; import noop from 'lodash/noop'; -// $FlowFixMe -import { BoxAiLogo } from '@box/blueprint-web-assets/icons/Logo'; -// $FlowFixMe -import { Size6 } from '@box/blueprint-web-assets/tokens/tokens'; +import { BoxAiLogo, BoxAiLogo24 } from '@box/blueprint-web-assets/icons/Logo'; +import { + Comment as CommentIcon, + InformationCircle as InformationCircleIcon, + Metadata as MetadataIcon, +} from '@box/blueprint-web-assets/icons/Medium'; +import { + Comment as CommentIconFilled, + InformationCircle as InformationCircleIconFilled, + Metadata as MetadataIconFilled, +} from '@box/blueprint-web-assets/icons/MediumFilled'; +import { Size6, Size5, IconIconBlue } from '@box/blueprint-web-assets/tokens/tokens'; import { usePromptFocus } from '@box/box-ai-content-answers'; import AdditionalTabs from './additional-tabs'; import DocGenIcon from '../../icon/fill/DocGenIcon'; @@ -40,6 +48,50 @@ import type { InternalSidebarNavigation, InternalSidebarNavigationHandler } from import './SidebarNav.scss'; import type { SignSidebarProps } from './SidebarNavSign'; +const SIDEBAR_TAB_ICON_PROPS = { + height: Size5, + width: Size5, +}; + +type IconWrapperProps = { + isActive?: boolean, + isPreviewModernizationEnabled: boolean, +}; + +// Icon wrapper components that receive isActive prop from SidebarNavButton +const ActivityIconWrapper = ({ isActive, isPreviewModernizationEnabled }: IconWrapperProps) => { + if (!isPreviewModernizationEnabled) { + return ; + } + return isActive ? ( + + ) : ( + + ); +}; + +const DetailsIconWrapper = ({ isActive, isPreviewModernizationEnabled }: IconWrapperProps) => { + if (!isPreviewModernizationEnabled) { + return ; + } + return isActive ? ( + + ) : ( + + ); +}; + +const MetadataIconWrapper = ({ isActive, isPreviewModernizationEnabled }: IconWrapperProps) => { + if (!isPreviewModernizationEnabled) { + return ; + } + return isActive ? ( + + ) : ( + + ); +}; + type Props = { additionalTabs?: Array, elementId: string, @@ -98,7 +150,12 @@ const SidebarNav = ({ }; return ( -
+
{hasBoxAI && ( - + {isPreviewModernizationEnabled ? ( + + ) : ( + + )} )} {hasActivity && ( - + )} {hasDetails && ( - + )} {hasSkills && ( - + )} {hasDocGen && ( - +
)}
diff --git a/src/elements/content-sidebar/SidebarNavButton.js b/src/elements/content-sidebar/SidebarNavButton.js index 15fcae0de9..a94b6c5f34 100644 --- a/src/elements/content-sidebar/SidebarNavButton.js +++ b/src/elements/content-sidebar/SidebarNavButton.js @@ -8,21 +8,26 @@ import * as React from 'react'; import { Route } from 'react-router-dom'; import noop from 'lodash/noop'; import classNames from 'classnames'; -import { Button } from '@box/blueprint-web'; +import { Button, Tooltip as BPTooltip } from '@box/blueprint-web'; import Tooltip from '../../components/tooltip/Tooltip'; import { isLeftClick } from '../../utils/dom'; -import type { InternalSidebarNavigation, InternalSidebarNavigationHandler, ViewTypeValues } from '../common/types/SidebarNavigation'; +import type { + InternalSidebarNavigation, + InternalSidebarNavigationHandler, + ViewTypeValues, +} from '../common/types/SidebarNavigation'; import './SidebarNavButton.scss'; type Props = { 'data-resin-target'?: string, 'data-testid'?: string, - children: React.Node, + children: React.Element, elementId?: string, internalSidebarNavigation?: InternalSidebarNavigation, internalSidebarNavigationHandler?: InternalSidebarNavigationHandler, isDisabled?: boolean, isOpen?: boolean, + isPreviewModernizationEnabled?: boolean, onClick?: (sidebarView: ViewTypeValues) => void, routerDisabled?: boolean, sidebarView: ViewTypeValues, @@ -43,39 +48,52 @@ const SidebarNavButton = React.forwardRef>((props: Props, routerDisabled = false, sidebarView, tooltip, + isPreviewModernizationEnabled = false, } = props; const sidebarPath = `/${sidebarView}`; const id = `${elementId}${elementId === '' ? '' : '_'}${sidebarView}`; + const TooltipComponent = isPreviewModernizationEnabled ? BPTooltip : Tooltip; + // Blueprint Tooltip uses 'content' prop, legacy Tooltip uses 'text' prop + const tooltipProps = isPreviewModernizationEnabled + ? { content: tooltip, side: 'left' } + : { text: tooltip, position: 'middle-left', isTabbable: false }; + if (routerDisabled) { // Mimic router behavior using internalSidebarNavigation const isMatch = !!internalSidebarNavigation && internalSidebarNavigation.sidebar === sidebarView; const isActiveValue = isMatch && !!isOpen; - + // Mimic isExactMatch: true when no extra navigation parameters are present - const hasExtraParams = internalSidebarNavigation && ( - internalSidebarNavigation.versionId || - internalSidebarNavigation.activeFeedEntryType || - internalSidebarNavigation.activeFeedEntryId || - internalSidebarNavigation.fileVersionId - ); + const hasExtraParams = + internalSidebarNavigation && + (internalSidebarNavigation.versionId || + internalSidebarNavigation.activeFeedEntryType || + internalSidebarNavigation.activeFeedEntryId || + internalSidebarNavigation.fileVersionId); const isExactMatch = isMatch && !hasExtraParams; - + const handleNavButtonClick = event => { onClick(sidebarView); - + // Mimic router navigation behavior if (internalSidebarNavigationHandler && !event.defaultPrevented && isLeftClick(event)) { const replace = isExactMatch; - internalSidebarNavigationHandler({ - sidebar: sidebarView, - open: true, - }, replace); + internalSidebarNavigationHandler( + { + sidebar: sidebarView, + open: true, + }, + replace, + ); } }; + // Clone children and pass isActive prop + const childrenWithProps = React.cloneElement(children, { isActive: isActiveValue }); + return ( - + - + ); } @@ -121,8 +139,11 @@ const SidebarNavButton = React.forwardRef>((props: Props, } }; + // Clone children and pass isActive prop + const childrenWithProps = React.cloneElement(children, { isActive: isActiveValue }); + return ( - + - + ); }} diff --git a/src/elements/content-sidebar/SidebarNavButton.scss b/src/elements/content-sidebar/SidebarNavButton.scss index f9a98284e1..7ba6e9ebea 100644 --- a/src/elements/content-sidebar/SidebarNavButton.scss +++ b/src/elements/content-sidebar/SidebarNavButton.scss @@ -3,7 +3,7 @@ .bcs .bcs-NavButton { @include bdl-SidebarNavButton; - + border-radius: 0; &::before { @@ -24,7 +24,7 @@ } // Style disabled buttons with proper visual feedback - &[aria-disabled="true"] { + &[aria-disabled='true'] { cursor: default; } @@ -37,7 +37,7 @@ fill: $blue; } } - + // Blueprint button focus override &:not(:disabled)[data-focus-visible] { border-radius: var(--radius-1); @@ -45,6 +45,17 @@ } } +.bcs-SidebarNav--modernized { + .bcs-NavButton { + &:not([aria-disabled='true']):hover svg, + &:not([aria-disabled='true']):focus svg, + &.bcs-is-selected svg { + transform: scale(1.09); + transition: transform 150ms; + } + } +} + @include breakpoint($medium-screen) { .bcs .bcs-NavButton { width: $sidebarTabResponsiveSize; diff --git a/src/elements/content-sidebar/SidebarNavSign.tsx b/src/elements/content-sidebar/SidebarNavSign.tsx index 429a9517c8..5e532ffe75 100644 --- a/src/elements/content-sidebar/SidebarNavSign.tsx +++ b/src/elements/content-sidebar/SidebarNavSign.tsx @@ -34,10 +34,27 @@ export function SidebarNavSign(signSidebarProps: SignSidebarProps) { targetingApi: boxSignTargetingApi, } = signSidebarProps; + const [isDropdownOpen, setIsDropdownOpen] = React.useState(false); + + const handleOnDropdownOpen = () => { + setIsDropdownOpen(true); + }; + + const handleOnDropdownClose = () => { + setIsDropdownOpen(false); + }; + return ( - + diff --git a/src/elements/content-sidebar/SidebarNavSignButton.scss b/src/elements/content-sidebar/SidebarNavSignButton.scss index ee62a6c739..91a48e01b4 100644 --- a/src/elements/content-sidebar/SidebarNavSignButton.scss +++ b/src/elements/content-sidebar/SidebarNavSignButton.scss @@ -11,7 +11,15 @@ .bcs-SidebarNavSignButton-icon--grayscale { display: none; - margin-top: 2px; // for visual alignment + margin-top: 2px; // for visual alignment; +} + +.bcs-SidebarNav--modernized { + .bcs-SidebarNavSignButton:not(.bdl-is-disabled):hover svg, + .bcs-SidebarNavSignButton:not(.bdl-is-disabled):focus svg { + transform: scale(1.09); + transition: transform 150ms; + } } @include breakpoint($medium-screen) { diff --git a/src/elements/content-sidebar/SidebarNavSignButton.tsx b/src/elements/content-sidebar/SidebarNavSignButton.tsx index 33a43356b0..1090bd9813 100644 --- a/src/elements/content-sidebar/SidebarNavSignButton.tsx +++ b/src/elements/content-sidebar/SidebarNavSignButton.tsx @@ -1,18 +1,23 @@ import * as React from 'react'; import classnames from 'classnames'; import { injectIntl, IntlShape } from 'react-intl'; +import SignIcon from '@box/blueprint-web-assets/icons/Medium/Sign'; +import { IconIconBlue, Size5 } from '@box/blueprint-web-assets/tokens/tokens'; +import { Tooltip as BPTooltip } from '@box/blueprint-web'; import BoxSign28 from '../../icon/logo/BoxSign28'; import Sign16 from '../../icon/fill/Sign16'; import PlainButton, { PlainButtonProps } from '../../components/plain-button'; // @ts-ignore Module is written in Flow import TargetedClickThroughGuideTooltip from '../../features/targeting/TargetedClickThroughGuideTooltip'; import Tooltip, { TooltipPosition } from '../../components/tooltip'; +import { useFeatureConfig } from '../common/feature-checking'; // @ts-ignore Module is written in Flow import messages from './messages'; import './SidebarNavSignButton.scss'; export type Props = PlainButtonProps & { blockedReason?: string; + isDropdownOpen: boolean; intl: IntlShape; targetingApi?: { canShow: boolean; @@ -24,12 +29,13 @@ export type Props = PlainButtonProps & { export const PlaceholderTooltip = ({ children }: { children: React.ReactNode }) => children; -export function SidebarNavSignButton({ blockedReason, intl, targetingApi, ...rest }: Props) { +export function SidebarNavSignButton({ blockedReason, intl, isDropdownOpen, targetingApi, ...rest }: Props) { const isSignDisabled = !!blockedReason; const isTargeted = targetingApi?.canShow; const FtuxTooltip = !isSignDisabled && isTargeted ? TargetedClickThroughGuideTooltip : PlaceholderTooltip; const label = intl.formatMessage(messages.boxSignRequest); const buttonClassName = classnames('bcs-SidebarNavSignButton', { 'bdl-is-disabled': isSignDisabled }); + const { enabled: isPreviewModernizationEnabled } = useFeatureConfig('previewModernization'); let tooltipMessage = label; @@ -45,15 +51,36 @@ export function SidebarNavSignButton({ blockedReason, intl, targetingApi, ...res default: } - return ( - targetingApi} - > - + const renderButtonWithTooltip = () => { + // Use Blueprint tooltip when modernization is enabled + if (isPreviewModernizationEnabled) { + const modernizedButton = ( + + + + ); + + if (isTargeted) { + return modernizedButton; + } + + return ( + + {/* Workaround to attach BP tooltip to legacy button, remove span when buttons are migrated to BP */} + {modernizedButton} + + ); + } + + // Use legacy tooltip by default + return ( + + ); + }; + + return ( + targetingApi} + > + {renderButtonWithTooltip()} ); } diff --git a/src/elements/content-sidebar/__tests__/SidebarNavButton.test.js b/src/elements/content-sidebar/__tests__/SidebarNavButton.test.js index 2b25c3c02f..cbfbdfb940 100644 --- a/src/elements/content-sidebar/__tests__/SidebarNavButton.test.js +++ b/src/elements/content-sidebar/__tests__/SidebarNavButton.test.js @@ -1,6 +1,6 @@ import * as React from 'react'; import { MemoryRouter, Router } from 'react-router-dom'; -// Using fireEvent for all click interactions instead of userEvent because +// Using fireEvent for all click interactions instead of userEvent because // userEvent.pointer with right-click doesn't reliably trigger onClick handlers import { render, screen, fireEvent } from '../../../test-utils/testing-library'; import SidebarNavButton from '../SidebarNavButton'; @@ -23,7 +23,7 @@ describe('elements/content-sidebar/SidebarNavButton', () => { renderWrapper({ tooltip: 'foo', sidebarView: 'activity', - children: 'test button', + children: test button, }); const button = screen.getByRole('tab'); @@ -49,7 +49,7 @@ describe('elements/content-sidebar/SidebarNavButton', () => { isOpen, sidebarView: 'activity', tooltip: 'foo', - children: 'test button', + children: test button, }; renderWrapper(props, '/activity'); const button = screen.getByRole('tab'); @@ -78,7 +78,7 @@ describe('elements/content-sidebar/SidebarNavButton', () => { isOpen: true, sidebarView: 'activity', tooltip: 'foo', - children: 'test button', + children: test button, }, path, ); @@ -103,7 +103,7 @@ describe('elements/content-sidebar/SidebarNavButton', () => { onClick: mockOnClick, sidebarView: mockSidebarView, tooltip: 'test', - children: 'button', + children: button, }); const button = screen.getByText('button'); @@ -117,12 +117,11 @@ describe('elements/content-sidebar/SidebarNavButton', () => { ${false} | ${false} ${undefined} | ${false} `('should apply bdl-is-disabled class when isDisabled is $isDisabled', ({ isDisabled, expected }) => { - const content = 'Activity'; renderWrapper({ isDisabled, sidebarView: 'activity', tooltip: 'Activity', - children: content, + children: Activity, }); const button = screen.getByRole('tab'); @@ -146,7 +145,7 @@ describe('elements/content-sidebar/SidebarNavButton', () => { elementId, sidebarView, tooltip: 'test', - children: 'test button', + children: test button, }); const button = screen.getByRole('tab'); @@ -162,7 +161,7 @@ describe('elements/content-sidebar/SidebarNavButton', () => { ref, sidebarView: 'activity', tooltip: 'test', - children: 'test button', + children: test button, }); const button = screen.getByRole('tab'); @@ -183,7 +182,7 @@ describe('elements/content-sidebar/SidebarNavButton', () => { return render( - Activity + Activity , ); @@ -267,7 +266,7 @@ describe('elements/content-sidebar/SidebarNavButton - Router Disabled', () => { internalSidebarNavigation: { sidebar: 'skills' }, }; - const renderWithoutRouter = ({ children = 'test button', ref, ...props }) => + const renderWithoutRouter = ({ children = test button, ref, ...props }) => render( {children} @@ -291,29 +290,32 @@ describe('elements/content-sidebar/SidebarNavButton - Router Disabled', () => { }); test.each` - internalSidebarNavigation | expected - ${null} | ${false} - ${undefined} | ${false} - ${{ sidebar: 'skills' }} | ${false} - ${{ sidebar: 'activity' }} | ${true} - ${{ sidebar: 'activity', versionId: '123' }} | ${true} - `('should reflect active state ($expected) correctly based on internal navigation', ({ expected, internalSidebarNavigation }) => { - renderWithoutRouter({ - internalSidebarNavigation, - isOpen: true, - }); - const button = screen.getByRole('tab'); + internalSidebarNavigation | expected + ${null} | ${false} + ${undefined} | ${false} + ${{ sidebar: 'skills' }} | ${false} + ${{ sidebar: 'activity' }} | ${true} + ${{ sidebar: 'activity', versionId: '123' }} | ${true} + `( + 'should reflect active state ($expected) correctly based on internal navigation', + ({ expected, internalSidebarNavigation }) => { + renderWithoutRouter({ + internalSidebarNavigation, + isOpen: true, + }); + const button = screen.getByRole('tab'); - if (expected) { - expect(button).toHaveClass('bcs-is-selected'); - expect(button).toHaveAttribute('aria-selected', 'true'); - expect(button).toHaveAttribute('tabindex', '0'); - } else { - expect(button).not.toHaveClass('bcs-is-selected'); - expect(button).toHaveAttribute('aria-selected', 'false'); - expect(button).toHaveAttribute('tabindex', '-1'); - } - }); + if (expected) { + expect(button).toHaveClass('bcs-is-selected'); + expect(button).toHaveAttribute('aria-selected', 'true'); + expect(button).toHaveAttribute('tabindex', '0'); + } else { + expect(button).not.toHaveClass('bcs-is-selected'); + expect(button).toHaveAttribute('aria-selected', 'false'); + expect(button).toHaveAttribute('tabindex', '-1'); + } + }, + ); test('should call onClick with sidebarView when clicked', () => { const mockOnClick = jest.fn(); @@ -345,10 +347,13 @@ describe('elements/content-sidebar/SidebarNavButton - Router Disabled', () => { fireEvent.click(button); expect(mockOnClick).toBeCalledWith('activity'); - expect(mockInternalSidebarNavigationHandler).toBeCalledWith({ - sidebar: 'activity', - open: true, - }, false); + expect(mockInternalSidebarNavigationHandler).toBeCalledWith( + { + sidebar: 'activity', + open: true, + }, + false, + ); }); test('calls internalSidebarNavigationHandler with replace=true when exact match', () => { @@ -364,10 +369,13 @@ describe('elements/content-sidebar/SidebarNavButton - Router Disabled', () => { fireEvent.click(button); expect(mockOnClick).toBeCalledWith('activity'); - expect(mockInternalSidebarNavigationHandler).toBeCalledWith({ - sidebar: 'activity', - open: true, - }, true); + expect(mockInternalSidebarNavigationHandler).toBeCalledWith( + { + sidebar: 'activity', + open: true, + }, + true, + ); }); test('does not call internalSidebarNavigationHandler on right click', () => { diff --git a/src/elements/content-sidebar/__tests__/SidebarNavSignButton.test.tsx b/src/elements/content-sidebar/__tests__/SidebarNavSignButton.test.tsx index 1c9306c9b9..dcb072c429 100644 --- a/src/elements/content-sidebar/__tests__/SidebarNavSignButton.test.tsx +++ b/src/elements/content-sidebar/__tests__/SidebarNavSignButton.test.tsx @@ -8,7 +8,7 @@ import TargetedClickThroughGuideTooltip from '../../../features/targeting/Target import Tooltip from '../../../components/tooltip'; describe('elements/content-sidebar/SidebarNavSignButton', () => { - const getWrapper = (props = {}) => shallow().dive(); + const getWrapper = (props = {}) => shallow().dive(); test('should render the correct label', () => { const wrapper = getWrapper(); diff --git a/src/elements/content-sidebar/_mixins.scss b/src/elements/content-sidebar/_mixins.scss index 646eceb101..26f518fcc4 100644 --- a/src/elements/content-sidebar/_mixins.scss +++ b/src/elements/content-sidebar/_mixins.scss @@ -14,7 +14,7 @@ } &.bdl-is-disabled { - opacity: .5; + opacity: 0.5; } &.bdl-is-hidden { @@ -27,6 +27,11 @@ height: 24px; } +@mixin bdl-SidebarNavIconModernized { + width: var(--size-5); + height: var(--size-5); +} + @mixin bcs-SidebarSection { margin: 0 8px 20px 25px; diff --git a/src/elements/content-sidebar/additional-tabs/AdditionalTab.scss b/src/elements/content-sidebar/additional-tabs/AdditionalTab.scss index 1efb671a80..46b399ec6b 100644 --- a/src/elements/content-sidebar/additional-tabs/AdditionalTab.scss +++ b/src/elements/content-sidebar/additional-tabs/AdditionalTab.scss @@ -12,8 +12,18 @@ } } +.bcs-SidebarNav--modernized { + .bdl-AdditionalTab:not(.bdl-is-disabled):hover svg, + .bdl-AdditionalTab:not(.bdl-is-disabled):hover img, + .bdl-AdditionalTab:not(.bdl-is-disabled):focus svg, + .bdl-AdditionalTab:not(.bdl-is-disabled):focus img { + transform: scale(1.09); + transition: transform 150ms; + } +} + .bdl-AdditionalTab-icon { - @include bdl-openComponentAnimation(.5s); + @include bdl-openComponentAnimation(0.5s); @include bdl-SidebarNavIcon; border-radius: 5px; diff --git a/src/elements/content-sidebar/additional-tabs/AdditionalTabTooltip.js b/src/elements/content-sidebar/additional-tabs/AdditionalTabTooltip.js index 7185ab6899..318dcdc255 100644 --- a/src/elements/content-sidebar/additional-tabs/AdditionalTabTooltip.js +++ b/src/elements/content-sidebar/additional-tabs/AdditionalTabTooltip.js @@ -5,8 +5,10 @@ */ import * as React from 'react'; +import { Tooltip as BPTooltip } from '@box/blueprint-web'; import Tooltip from '../../common/Tooltip'; import TargetedClickThroughGuideTooltip from '../../../features/targeting/TargetedClickThroughGuideTooltip'; +import { useFeatureConfig } from '../../common/feature-checking'; import type { AdditionalSidebarTabFtuxData } from '../flowTypes'; import './AdditionalTabTooltip.scss'; @@ -18,7 +20,18 @@ type Props = { }; const AdditionalTabTooltip = ({ children, defaultTooltipText, isFtuxVisible, ftuxTooltipData }: Props) => { + const { enabled: isPreviewModernizationEnabled } = useFeatureConfig('previewModernization'); + if (!isFtuxVisible || !ftuxTooltipData || !ftuxTooltipData.targetingApi().canShow) { + if (isPreviewModernizationEnabled) { + return ( + + {/* Workaround to attach BP tooltip to legacy button */} + {children} + + ); + } + return ( {children} diff --git a/src/elements/content-sidebar/additional-tabs/AdditionalTabs.js b/src/elements/content-sidebar/additional-tabs/AdditionalTabs.js index d4579a05a5..9186dca084 100644 --- a/src/elements/content-sidebar/additional-tabs/AdditionalTabs.js +++ b/src/elements/content-sidebar/additional-tabs/AdditionalTabs.js @@ -5,6 +5,7 @@ */ import React, { PureComponent } from 'react'; +import classNames from 'classnames'; import AdditionalTab from './AdditionalTab'; import AdditionalTabsLoading from './AdditionalTabsLoading'; import type { AdditionalSidebarTab } from '../flowTypes'; @@ -13,6 +14,7 @@ import './AdditionalTabs.scss'; type Props = { tabs?: Array, + isPreviewModernizationEnabled?: boolean, }; type State = { @@ -53,11 +55,15 @@ class AdditionalTabs extends PureComponent { }; render() { - const { tabs } = this.props; + const { tabs, isPreviewModernizationEnabled } = this.props; const { isLoading } = this.state; return ( -
+
{isLoading && } {tabs && tabs.map(tabData => ( diff --git a/src/elements/content-sidebar/additional-tabs/AdditionalTabs.scss b/src/elements/content-sidebar/additional-tabs/AdditionalTabs.scss index 3ed6a9e01f..ce0999e997 100644 --- a/src/elements/content-sidebar/additional-tabs/AdditionalTabs.scss +++ b/src/elements/content-sidebar/additional-tabs/AdditionalTabs.scss @@ -1,4 +1,13 @@ +@import '../mixins'; + .bdl-AdditionalTabs { display: flex; flex-direction: column; + + &.bdl-AdditionalTabs--modernized { + .bdl-AdditionalTab-icon, + .bdl-AdditionalTabPlaceholder-icon { + @include bdl-SidebarNavIconModernized; + } + } }