From 3a45f20d765d1df702cfed1cc25e117242672241 Mon Sep 17 00:00:00 2001 From: Elena Pravdina Date: Thu, 29 Jun 2023 14:20:28 +0300 Subject: [PATCH] =?UTF-8?q?refactor!:=20remove=20popup=20wrapper=20class,?= =?UTF-8?q?=20use=20content=20classes=20for=20popover=E2=80=A6=20(#711)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Popover/Popover.scss | 12 +- src/components/Popover/Popover.tsx | 2 + src/components/Popover/README.md | 63 ++++---- .../Popover/__stories__/Popover.stories.tsx | 1 + src/components/Popover/types.ts | 2 + src/components/Popup/Popup.scss | 147 +++++++++--------- src/components/Popup/Popup.tsx | 11 +- src/components/SharePopover/README.md | 33 ++-- src/components/SharePopover/SharePopover.scss | 2 +- src/components/SharePopover/SharePopover.tsx | 4 + src/components/Tooltip/Tooltip.scss | 18 ++- 11 files changed, 155 insertions(+), 140 deletions(-) diff --git a/src/components/Popover/Popover.scss b/src/components/Popover/Popover.scss index 29eb42090..bcb3498e8 100644 --- a/src/components/Popover/Popover.scss +++ b/src/components/Popover/Popover.scss @@ -26,11 +26,13 @@ $block: '.#{variables.$ns}popover'; $buttonGap: 5px; - box-sizing: border-box; - min-height: 40px; - max-width: var(--yc-popover-max-width); - padding: var(--yc-popover-padding); - cursor: default; + &-popup-content { + box-sizing: border-box; + min-height: 40px; + max-width: var(--yc-popover-max-width); + padding: var(--yc-popover-padding); + cursor: default; + } &-title { @include mixins.text-subheader-3(); diff --git a/src/components/Popover/Popover.tsx b/src/components/Popover/Popover.tsx index ad3d13586..4e3b6b2ce 100644 --- a/src/components/Popover/Popover.tsx +++ b/src/components/Popover/Popover.tsx @@ -31,6 +31,7 @@ export const Popover = React.forwardRef `{ top: 0, left: 0 }` | -| placement | `Array` | | | [`right`, `bottom`] | Tooltip's placement | -| hasArrow | `Boolean` | | | `true` | Whether tooltip has a tail | -| hasClose | `Boolean` | | | `false` | Whether tooltip has a close button | -| theme | `String` | | `info`, `special`, `announcement` | `info` | Tooltip's theme | -| size | `String` | | `s`, `l` | `s` | Tooltip's theme | -| behavior | `TooltipBehavior` | | `Immediate`, `Delayed`, `DelayedClosing` | `DelayedClosing` | Tooltip open/close behaviour when `openOnHover` (without a delay, with delay, with delay only when closing). Won't be applied if `delayOpening` or `delayClosing` are provided | -| delayOpening | `Number` | | | `0` | Tooltip's opening delay if `openOnHover`. We recommend to use `behavior` | -| delayClosing | `Number` | | | `300` | Tooltip's closing delay if `autoclosable`. We recommend to use `behavior` | -| anchorRef | `React.RefObject` | | | | Custom anchor. Disables `openByHover` and `onClick`. | -| children | `ReactNode` | | | | Content, over which tooltip is rendered | -| title | `String` | | | | Tooltip's title | -| content | `ReactNode` | | | | Tooltip's content | -| htmlContent | `String` | | | | Tooltip's html content (`dangerouslySetInnerHTML` will be used for rendering) | -| contentClassName | `String` | | | | Tooltip's content css class | -| links | `Array` | | | [] | Links under the content
`{ text: 'Link 1', href: 'https://yandex.ru'}` or
`{ text: 'Link 2', onClick: () => callbackOnLinkClick() }` | -| forceLinksAppearance | `boolean` | | | true | Force styles for links | -| tooltipActionButton | `Object` | | | | Action button properties (the button won't be rendered without it)
`{ text: 'Button', onClick: () => callbackOnClick() }` | -| tooltipCancelButton | `Object` | | | | Cancel button properties (the button won't be rendered without it)
`{ text: 'Button', onClick: () => callbackOnClick() }` | -| tooltipOffset | `[Number, Number]` | | | | Tooltip's offset related to the control | -| tooltipClassName | `String` | | | | Tooltip's css class | -| className | `String` | | | | Control's css class | -| onClick | `Function` | | | | Anchor click callback. If the function returns `true', the tooltip will be open, otherwise it won't be opened. | -| onOpenChange | `Function` | | | | Open state change callback. Can be useful for delayed tooltip's content rendering. | -| onCloseClick | `Function` | | | | Close button click handler | +| Property | Type | Required | Values | Default | Description | +| :---------------------- | :----------------- | :------- | :--------------------------------------- | :------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| initialOpen | `boolean` | | | false | Whether the tooltip initially opened | +| disabled | `boolean` | | | false | Disables open state changes | +| autoclosable | `Boolean` | | | `true` | Whether tooltip should automatically close when the cursor is outside | +| openOnHover | `Boolean` | | | `true` | Whether tooltip should open on hover | +| offset | `Object` | | | | Control's offset
`{ top: 0, left: 0 }` | +| placement | `Array` | | | [`right`, `bottom`] | Tooltip's placement | +| hasArrow | `Boolean` | | | `true` | Whether tooltip has a tail | +| hasClose | `Boolean` | | | `false` | Whether tooltip has a close button | +| theme | `String` | | `info`, `special`, `announcement` | `info` | Tooltip's theme | +| size | `String` | | `s`, `l` | `s` | Tooltip's theme | +| behavior | `TooltipBehavior` | | `Immediate`, `Delayed`, `DelayedClosing` | `DelayedClosing` | Tooltip open/close behaviour when `openOnHover` (without a delay, with delay, with delay only when closing). Won't be applied if `delayOpening` or `delayClosing` are provided | +| delayOpening | `Number` | | | `0` | Tooltip's opening delay if `openOnHover`. We recommend to use `behavior` | +| delayClosing | `Number` | | | `300` | Tooltip's closing delay if `autoclosable`. We recommend to use `behavior` | +| anchorRef | `React.RefObject` | | | | Custom anchor. Disables `openByHover` and `onClick`. | +| children | `ReactNode` | | | | Content, over which tooltip is rendered | +| title | `String` | | | | Tooltip's title | +| content | `ReactNode` | | | | Tooltip's content | +| htmlContent | `String` | | | | Tooltip's html content (`dangerouslySetInnerHTML` will be used for rendering) | +| contentClassName | `String` | | | | Tooltip's content css class | +| links | `Array` | | | [] | Links under the content
`{ text: 'Link 1', href: 'https://yandex.ru'}` or
`{ text: 'Link 2', onClick: () => callbackOnLinkClick() }` | +| forceLinksAppearance | `boolean` | | | true | Force styles for links | +| tooltipActionButton | `Object` | | | | Action button properties (the button won't be rendered without it)
`{ text: 'Button', onClick: () => callbackOnClick() }` | +| tooltipCancelButton | `Object` | | | | Cancel button properties (the button won't be rendered without it)
`{ text: 'Button', onClick: () => callbackOnClick() }` | +| tooltipOffset | `[Number, Number]` | | | | Tooltip's offset related to the control | +| tooltipClassName | `String` | | | | Tooltip's css class | +| tooltipContentClassName | `String` | | | | Tooltip's content css class | +| className | `String` | | | | Control's css class | +| onClick | `Function` | | | | Anchor click callback. If the function returns `true', the tooltip will be open, otherwise it won't be opened. | +| onOpenChange | `Function` | | | | Open state change callback. Can be useful for delayed tooltip's content rendering. | +| onCloseClick | `Function` | | | | Close button click handler | ### Instance properties diff --git a/src/components/Popover/__stories__/Popover.stories.tsx b/src/components/Popover/__stories__/Popover.stories.tsx index cc85ff597..ab364e02f 100644 --- a/src/components/Popover/__stories__/Popover.stories.tsx +++ b/src/components/Popover/__stories__/Popover.stories.tsx @@ -76,6 +76,7 @@ export default { tooltipCancelButton: {control: 'object'}, tooltipOffset: {control: 'array'}, tooltipClassName: {control: 'string '}, + tooltipContentClassName: {control: 'string '}, className: {control: 'string '}, onClick: {action: 'onClick'}, onOpenChange: {action: 'onOpenChange'}, diff --git a/src/components/Popover/types.ts b/src/components/Popover/types.ts index 559cb518b..cfe81a787 100644 --- a/src/components/Popover/types.ts +++ b/src/components/Popover/types.ts @@ -44,6 +44,8 @@ export type PopoverExternalProps = { tooltipOffset?: [number, number]; /** Tooltip's css class */ tooltipClassName?: string; + /** Tooltip's content css class */ + tooltipContentClassName?: string; /** css class for the control */ className?: string; /** diff --git a/src/components/Popup/Popup.scss b/src/components/Popup/Popup.scss index e701c2340..7f3589e92 100644 --- a/src/components/Popup/Popup.scss +++ b/src/components/Popup/Popup.scss @@ -1,7 +1,6 @@ @use '../variables'; $block: '.#{variables.$ns}popup'; -$blockWrapper: '.#{variables.$ns}popup-wrapper'; $arrow-size: 18px; $arrow-offset: 9px; @@ -16,67 +15,6 @@ $transition-distance: 10px; --yc-popup-border-color: var(--g-color-line-solid); --yc-popup-border-width: 1px; - position: relative; - animation-duration: 0.1s; - animation-timing-function: ease-out; - animation-fill-mode: forwards; - border-radius: 4px; - background-color: var(--yc-popup-background-color); - box-shadow: 0 0 0 var(--yc-popup-border-width) var(--yc-popup-border-color), - 0 8px 20px var(--yc-popup-border-width) var(--g-color-sfx-shadow); - outline: none; - - // Corners rounding for content - & > :first-child:not(&__arrow), - & > &__arrow + * { - border-top-left-radius: inherit; - border-top-right-radius: inherit; - } - - & > :last-child { - border-bottom-left-radius: inherit; - border-bottom-right-radius: inherit; - } - - &__arrow-content { - width: $arrow-size; - height: $arrow-size; - position: relative; - overflow: hidden; - display: flex; - } - - &__arrow-circle-wrapper { - background-color: transparent; - overflow: hidden; - width: 9px; - height: 9px; - position: relative; - } - - &__arrow-circle { - box-sizing: border-box; - border-radius: 50%; - box-shadow: inset 0 0 0 calc(#{$arrow-border} - var(--yc-popup-border-width)) - var(--yc-popup-background-color), - inset 0 0 0 $arrow-border var(--yc-popup-border-color); - width: $arrow-circle-width; - height: $arrow-circle-height; - position: absolute; - - &_left { - right: -5px; - bottom: -4px; - } - - &_right { - left: -5px; - bottom: -4px; - } - } -} - -#{$blockWrapper} { z-index: 1000; visibility: hidden; @@ -86,19 +24,19 @@ $transition-distance: 10px; } &_exit_active { - &[data-popper-placement*='bottom'] #{$block} { + &[data-popper-placement*='bottom'] #{$block}__content { animation-name: #{variables.$ns}popup-bottom; } - &[data-popper-placement*='top'] #{$block} { + &[data-popper-placement*='top'] #{$block}__content { animation-name: #{variables.$ns}popup-top; } - &[data-popper-placement*='left'] #{$block} { + &[data-popper-placement*='left'] #{$block}__content { animation-name: #{variables.$ns}popup-left; } - &[data-popper-placement*='right'] #{$block} { + &[data-popper-placement*='right'] #{$block}__content { animation-name: #{variables.$ns}popup-right; } } @@ -106,29 +44,29 @@ $transition-distance: 10px; // open state &_enter_active, &_appear_active { - &[data-popper-placement*='bottom'] #{$block} { + &[data-popper-placement*='bottom'] #{$block}__content { animation-name: #{variables.$ns}popup-bottom-open; } - &[data-popper-placement*='top'] #{$block} { + &[data-popper-placement*='top'] #{$block}__content { animation-name: #{variables.$ns}popup-top-open; } - &[data-popper-placement*='left'] #{$block} { + &[data-popper-placement*='left'] #{$block}__content { animation-name: #{variables.$ns}popup-left-open; } - &[data-popper-placement*='right'] #{$block} { + &[data-popper-placement*='right'] #{$block}__content { animation-name: #{variables.$ns}popup-right-open; } } // arrow - &[data-popper-placement*='bottom'] #{#{$block}}__arrow { + &[data-popper-placement*='bottom'] #{$block}__arrow { top: -$arrow-offset; } - &[data-popper-placement*='top'] #{#{$block}}__arrow { + &[data-popper-placement*='top'] #{$block}__arrow { bottom: -$arrow-offset; &-content { @@ -136,7 +74,7 @@ $transition-distance: 10px; } } - &[data-popper-placement*='left'] #{#{$block}}__arrow { + &[data-popper-placement*='left'] #{$block}__arrow { right: -$arrow-offset; &-content { @@ -144,13 +82,74 @@ $transition-distance: 10px; } } - &[data-popper-placement*='right'] #{#{$block}}__arrow { + &[data-popper-placement*='right'] #{$block}__arrow { left: -$arrow-offset; &-content { transform: rotate(-90deg); } } + + &__content { + position: relative; + animation-duration: 0.1s; + animation-timing-function: ease-out; + animation-fill-mode: forwards; + border-radius: 4px; + background-color: var(--yc-popup-background-color); + box-shadow: 0 0 0 var(--yc-popup-border-width) var(--yc-popup-border-color), + 0 8px 20px var(--yc-popup-border-width) var(--yc-color-sfx-shadow); + outline: none; + + // Corners rounding for content + & > :first-child:not(#{$block}__arrow), + & > #{$block}__arrow + * { + border-top-left-radius: inherit; + border-top-right-radius: inherit; + } + + & > :last-child { + border-bottom-left-radius: inherit; + border-bottom-right-radius: inherit; + } + } + + &__arrow-content { + width: $arrow-size; + height: $arrow-size; + position: relative; + overflow: hidden; + display: flex; + } + + &__arrow-circle-wrapper { + background-color: transparent; + overflow: hidden; + width: 9px; + height: 9px; + position: relative; + } + + &__arrow-circle { + box-sizing: border-box; + border-radius: 50%; + box-shadow: inset 0 0 0 calc(#{$arrow-border} - var(--yc-popup-border-width)) + var(--yc-popup-background-color), + inset 0 0 0 $arrow-border var(--yc-popup-border-color); + width: $arrow-circle-width; + height: $arrow-circle-height; + position: absolute; + + &_left { + right: -5px; + bottom: -4px; + } + + &_right { + left: -5px; + bottom: -4px; + } + } } @keyframes #{variables.$ns}popup-bottom { diff --git a/src/components/Popup/Popup.tsx b/src/components/Popup/Popup.tsx index dbb1f101c..7d10fa7e3 100644 --- a/src/components/Popup/Popup.tsx +++ b/src/components/Popup/Popup.tsx @@ -40,12 +40,12 @@ export interface PopupProps extends DOMProps, LayerExtendableProps, PopperProps, onMouseLeave?: React.MouseEventHandler; disablePortal?: boolean; container?: HTMLElement; + contentClassName?: string; restoreFocus?: boolean; restoreFocusRef?: React.RefObject; } const b = block('popup'); -const bWrapper = block('popup-wrapper'); const ARROW_SIZE = 8; export function Popup({ @@ -60,6 +60,7 @@ export function Popup({ disableLayer, style, className, + contentClassName, modifiers = [], children, onEscapeKeyDown, @@ -118,7 +119,7 @@ export function Popup({ addEndListener={(done) => containerRef.current?.addEventListener('animationend', done) } - classNames={getCSSTransitionClassNames(bWrapper)} + classNames={getCSSTransitionClassNames(b)} mountOnEnter={!keepMounted} unmountOnExit={!keepMounted} appear={true} @@ -128,16 +129,16 @@ export function Popup({ style={styles.popper} {...attributes.popper} {...containerProps} - className={bWrapper({open})} + className={b({open}, className)} + data-qa={qa} > {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
{hasArrow && ( ` | | `[]` | share options list | -| withCopyLink | `Boolean` | | `true` | display copy button | -| useWebShareApi | `Boolean` | | `false` | [Web Share API](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share) usage setting. If turned on default share dialog will be shown (if bbrowser supports it) | -| placement | `Array` | | `['bottom-end']` | tooltip openening direction | -| openByHover | `Boolean` | | `true` | should open tooltip with hover | -| autoclosable | `Boolean` | | `true` | should close tooltip when cursor is outside | -| closeDelay | `Number` | | `300` | delay before tooltip will be hidden when cursor is otside | -| iconSize | `Number` | | | icon-control size | -| iconClass | `String` | | | icon-control mixin | -| tooltipClassName | `String` | | | tooltip mixin | -| className | `String` | | | css class for control | +| Property | Type | Required | Default | Description | +| :---------------------- | :-------------------- | :------- | :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| url | `String` | ✔ | | share link | +| title | `String` | | | link title | +| text | `String` | | | link text | +| shareOptions | `Array` | | `[]` | share options list | +| withCopyLink | `Boolean` | | `true` | display copy button | +| useWebShareApi | `Boolean` | | `false` | [Web Share API](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share) usage setting. If turned on default share dialog will be shown (if bbrowser supports it) | +| placement | `Array` | | `['bottom-end']` | tooltip openening direction | +| openByHover | `Boolean` | | `true` | should open tooltip with hover | +| autoclosable | `Boolean` | | `true` | should close tooltip when cursor is outside | +| closeDelay | `Number` | | `300` | delay before tooltip will be hidden when cursor is otside | +| iconSize | `Number` | | | icon-control size | +| iconClass | `String` | | | icon-control mixin | +| tooltipClassName | `String` | | | tooltip mixin | +| tooltipContentClassName | `String` | | | tooltip content mixin | +| className | `String` | | | css class for control | ### Examples diff --git a/src/components/SharePopover/SharePopover.scss b/src/components/SharePopover/SharePopover.scss index f51141cac..1c609a5fd 100644 --- a/src/components/SharePopover/SharePopover.scss +++ b/src/components/SharePopover/SharePopover.scss @@ -5,7 +5,7 @@ $block: '.#{variables.$ns}share-popover'; #{$block} { position: relative; - &__tooltip { + &__tooltip-content { max-width: none; padding: 8px; } diff --git a/src/components/SharePopover/SharePopover.tsx b/src/components/SharePopover/SharePopover.tsx index 80b5537d0..c4f537224 100644 --- a/src/components/SharePopover/SharePopover.tsx +++ b/src/components/SharePopover/SharePopover.tsx @@ -38,6 +38,8 @@ export interface SharePopoverProps extends ShareListProps, Partial { iconSize, iconClass, tooltipClassName, + tooltipContentClassName, switcherClassName, className, direction, @@ -132,6 +135,7 @@ export class SharePopover extends React.PureComponent { content={content} className={b(null, className)} tooltipClassName={b('tooltip', tooltipClassName)} + tooltipContentClassName={b('tooltip-content', tooltipContentClassName)} onClick={this.handleClick} >
diff --git a/src/components/Tooltip/Tooltip.scss b/src/components/Tooltip/Tooltip.scss index 4e84b0e0b..9e0533ac6 100644 --- a/src/components/Tooltip/Tooltip.scss +++ b/src/components/Tooltip/Tooltip.scss @@ -3,17 +3,19 @@ $block: '.#{variables.$ns}tooltip'; #{$block} { - // prevent glitch between two nearby tooltip refs - pointer-events: none; + // [class] for increasing specificity + &[class] { + --yc-popup-border-width: 0; + --yc-popup-background-color: var(--g-color-base-float-heavy); + } + + &__popup-content { + // prevent glitch between two nearby tooltip refs + pointer-events: none; + } &__content { padding: 6px 12px; color: var(--g-color-text-light-primary); } } - -// [class] for increasing specificity -#{$block}[class] { - --yc-popup-border-width: 0; - --yc-popup-background-color: var(--g-color-base-float-heavy); -}