diff --git a/src/components/Label/Label.scss b/src/components/Label/Label.scss index cf4ce4ddbe..7afb5f2a59 100644 --- a/src/components/Label/Label.scss +++ b/src/components/Label/Label.scss @@ -1,4 +1,5 @@ @use '../variables'; +@use '../../../styles/mixins'; $block: '.#{variables.$ns}label'; $disabled: #{$block}_disabled; @@ -66,6 +67,21 @@ $hover-opacity: 0.7; margin: 0 4px; } + &__action-button { + @include mixins.button-reset(); + border-radius: inherit; + z-index: 1; + + &:focus-visible { + outline: 2px solid var(--g-color-line-focus); + } + + &:empty { + position: absolute; + inset: 0; + } + } + // & selector added to up priority over button styles & &__addon { display: flex; @@ -84,6 +100,7 @@ $hover-opacity: 0.7; &_side_right { inset-inline-end: 0; + z-index: 2; } &_interactive { @@ -118,11 +135,6 @@ $hover-opacity: 0.7; &_is-interactive { cursor: pointer; - outline: none; - } - - &_is-interactive:focus-visible { - outline: 2px solid var(--g-color-line-focus); } --_-bg-color: none; diff --git a/src/components/Label/Label.tsx b/src/components/Label/Label.tsx index 7aa664787f..9bbb955373 100644 --- a/src/components/Label/Label.tsx +++ b/src/components/Label/Label.tsx @@ -2,7 +2,6 @@ import React from 'react'; import {Xmark} from '@gravity-ui/icons'; -import {useActionHandlers} from '../../hooks'; import {Button} from '../Button'; import type {ButtonProps, ButtonSize} from '../Button'; import {ClipboardIcon} from '../ClipboardIcon'; @@ -32,7 +31,7 @@ const commonActionButtonProps: ButtonProps = { }), }; -interface LabelOwnProps extends QAProps { +export interface LabelProps extends QAProps { /** Label icon (at left) */ icon?: React.ReactNode; /** Disabled state */ @@ -48,7 +47,7 @@ interface LabelOwnProps extends QAProps { /** Handler for copy event */ onCopy?(text: string, result: boolean): void; /** Handler for click on label itself */ - onClick?(event: React.MouseEvent): void; + onClick?(event: React.MouseEvent): void; /** Class name */ className?: string; /** Content */ @@ -57,20 +56,18 @@ interface LabelOwnProps extends QAProps { interactive?: boolean; /** Label value (shows as "children : value") */ value?: string; -} - -interface LabelDefaultProps { /** Label color */ - theme: 'normal' | 'info' | 'danger' | 'warning' | 'success' | 'utility' | 'unknown' | 'clear'; + theme?: 'normal' | 'info' | 'danger' | 'warning' | 'success' | 'utility' | 'unknown' | 'clear'; /** Label type (plain, with copy text button or with close button) */ - type: 'default' | 'copy' | 'close'; + type?: 'default' | 'copy' | 'close'; /** Label size */ - size: 'xs' | 's' | 'm'; + size?: 'xs' | 's' | 'm'; } -export interface LabelProps extends LabelOwnProps, Partial {} - -export const Label = React.forwardRef(function Label(props, ref) { +export const Label = React.forwardRef(function Label( + props: LabelProps, + ref: React.Ref, +) { const { type = 'default', theme = 'normal', @@ -89,15 +86,12 @@ export const Label = React.forwardRef(function Label onClick, qa, } = props; - - const actionButtonRef = React.useRef(null); - const hasContent = Boolean(children !== '' && React.Children.count(children) > 0); const typeClose = type === 'close' && hasContent; const typeCopy = type === 'copy' && hasContent; - const hasOnClick = Boolean(onClick); + const hasOnClick = typeof onClick === 'function'; const hasCopy = Boolean(typeCopy && copyText); const isInteractive = (hasOnClick || hasCopy || interactive) && !disabled; const {copyIconSize, closeIconSize, buttonSize} = sizeMap[size]; @@ -117,38 +111,16 @@ export const Label = React.forwardRef(function Label ); - const handleCloseClick = (event: React.MouseEvent) => { - if (hasOnClick) { - /* preventing event from bubbling */ - event.stopPropagation(); - } - - if (onCloseClick) { - onCloseClick(event); - } - }; - - const handleClick = (event: React.MouseEvent) => { - /** - * Triggered only if the handler was triggered on the element itself, and not on the actionButton - * It is necessary that keyboard navigation works correctly - */ - if (!actionButtonRef.current?.contains(event.target as Node)) { - onClick?.(event); - } - }; - - const {onKeyDown} = useActionHandlers(handleClick); - const renderLabel = (status?: CopyToClipboardStatus) => { let actionButton: React.ReactNode; if (typeCopy) { actionButton = ( + ) : ( + content + )} {actionButton} ); diff --git a/src/components/Label/__stories__/Label.stories.tsx b/src/components/Label/__stories__/Label.stories.tsx index 4d97e10700..aac0960180 100644 --- a/src/components/Label/__stories__/Label.stories.tsx +++ b/src/components/Label/__stories__/Label.stories.tsx @@ -12,7 +12,7 @@ import {LabelShowcase} from './LabelShowcase'; const iconSizeMap = {xs: 12, s: 14, m: 16} as const; -export default { +const meta: Meta = { title: 'Components/Data Display/Label', component: Label, parameters: { @@ -28,7 +28,9 @@ export default { }, }, }, -} as Meta; +}; + +export default meta; type Story = StoryObj;