Skip to content

Commit

Permalink
Merge branch 'main' into 8147-listbox-menu-icon-regression
Browse files Browse the repository at this point in the history
  • Loading branch information
kodiakhq[bot] authored Mar 23, 2021
2 parents ec315a1 + 8756867 commit 28a0833
Show file tree
Hide file tree
Showing 36 changed files with 941 additions and 557 deletions.
Binary file not shown.
6 changes: 6 additions & 0 deletions packages/components/src/components/button/_button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@
}
}

// Allow pointer events on tooltip when tooltip is visible
.#{$prefix}--btn.#{$prefix}--btn--icon-only:not(.#{$prefix}--tooltip--hidden)
.#{$prefix}--assistive-text {
pointer-events: all;
}

.#{$prefix}--btn.#{$prefix}--btn--icon-only.#{$prefix}--tooltip__trigger:focus {
border-color: $focus;

Expand Down
6 changes: 6 additions & 0 deletions packages/components/src/components/tooltip/_tooltip.scss
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,12 @@
@include tooltip--placement('icon', 'left', 'end');
}
}

// Allow pointer events on tooltip when tooltip is visible
.#{$prefix}--tooltip__trigger:not(.#{$prefix}--tooltip--hidden)
.#{$prefix}--assistive-text {
pointer-events: all;
}
}

@include exports('tooltip') {
Expand Down
50 changes: 40 additions & 10 deletions packages/components/src/components/treeview/_treeview.scss
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,34 @@
@include focus-outline('outline');
}

.#{$prefix}--tree-node--disabled {
color: $disabled-02;
background-color: $disabled-01;
pointer-events: none;
.#{$prefix}--tree-node--disabled:focus > .#{$prefix}--tree-node__label {
outline: none;
}

.#{$prefix}--tree-node--disabled .#{$prefix}--tree-node__label:hover {
.#{$prefix}--tree-node--disabled,
.#{$prefix}--tree-node--disabled .#{$prefix}--tree-node__label:hover,
.#{$prefix}--tree-node--disabled
.#{$prefix}--tree-node__label:hover
.#{$prefix}--tree-node__label__details {
color: $disabled-02;
background-color: $disabled-01;
}

.#{$prefix}--tree-node--disabled .#{$prefix}--tree-parent-node__toggle-icon,
.#{$prefix}--tree-node--disabled .#{$prefix}--tree-node__icon {
.#{$prefix}--tree-node--disabled .#{$prefix}--tree-node__icon,
.#{$prefix}--tree-node--disabled
.#{$prefix}--tree-node__label:hover
.#{$prefix}--tree-parent-node__toggle-icon,
.#{$prefix}--tree-node--disabled
.#{$prefix}--tree-node__label:hover
.#{$prefix}--tree-node__icon {
fill: $disabled-02;
}

.#{$prefix}--tree-node--disabled,
.#{$prefix}--tree-node--disabled
.#{$prefix}--tree-parent-node__toggle-icon:hover {
cursor: default;
cursor: not-allowed;
}

.#{$prefix}--tree-node__label {
Expand All @@ -62,10 +72,21 @@
min-height: rem(32px);

&:hover {
color: $text-01;
background-color: $hover-ui;
}
}

.#{$prefix}--tree-node__label:hover .#{$prefix}--tree-node__label__details {
color: $text-01;
}

.#{$prefix}--tree-node__label:hover
.#{$prefix}--tree-parent-node__toggle-icon,
.#{$prefix}--tree-node__label:hover .#{$prefix}--tree-node__icon {
fill: $icon-01;
}

.#{$prefix}--tree-leaf-node {
display: flex;
padding-left: $spacing-08;
Expand Down Expand Up @@ -101,7 +122,7 @@
.#{$prefix}--tree-parent-node__toggle-icon {
transform: rotate(-90deg);
transition: all $duration--fast-02 motion(standard, productive);
fill: $icon-01;
fill: $icon-02;
}

.#{$prefix}--tree-parent-node__toggle-icon--expanded {
Expand All @@ -110,7 +131,7 @@

.#{$prefix}--tree-node__icon {
margin-right: $spacing-03;
fill: $icon-01;
fill: $icon-02;
}

.#{$prefix}--tree-node--selected > .#{$prefix}--tree-node__label {
Expand All @@ -122,6 +143,15 @@
}
}

.#{$prefix}--tree-node--selected
> .#{$prefix}--tree-node__label
.#{$prefix}--tree-parent-node__toggle-icon,
.#{$prefix}--tree-node--selected
> .#{$prefix}--tree-node__label
.#{$prefix}--tree-node__icon {
fill: $icon-01;
}

.#{$prefix}--tree-node--active > .#{$prefix}--tree-node__label {
position: relative;

Expand All @@ -131,7 +161,7 @@
left: 0;
width: rem(4px);
height: 100%;
background-color: $interactive-01;
background-color: $interactive-04;
content: '';
}
}
Expand Down
33 changes: 33 additions & 0 deletions packages/components/src/globals/scss/_tooltip.scss
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,39 @@
$caret-width: rem(8px);
$body-spacing: $caret-spacing + $caret-height;

// Use pseudo element to create invisible hover area to keep tooltip open on hover
.#{$prefix}--assistive-text::after {
position: absolute;
display: block;
content: '';
// clip-path: polygon(50% 100%, 0 0, 100% 0);

@if ($position == 'top' or $position == 'bottom') {
left: 0;
width: 100%;
height: rem(12px);
}

@if ($position == 'left' or $position == 'right') {
top: 0;
width: rem(12px);
height: 100%;
}

@if ($position == 'top') {
bottom: rem(-12px);
}
@if ($position == 'right') {
left: rem(-12px);
}
@if ($position == 'bottom') {
top: rem(-12px);
}
@if ($position == 'left') {
right: rem(-12px);
}
}

// @todo Simplify CSS selectors on next major release
&::before,
&::after,
Expand Down
1 change: 1 addition & 0 deletions packages/icons/icons.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13010,6 +13010,7 @@
aliases:
- soccer
- sports
- football
sizes:
- 32
- name: soil-moisture
Expand Down
18 changes: 18 additions & 0 deletions packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,18 @@ Map {
"isRequired": true,
"type": "oneOf",
},
"onBlur": Object {
"type": "func",
},
"onFocus": Object {
"type": "func",
},
"onMouseEnter": Object {
"type": "func",
},
"onMouseLeave": Object {
"type": "func",
},
"renderIcon": Object {
"args": Array [
Array [
Expand Down Expand Up @@ -6351,12 +6363,18 @@ Map {
"id": Object {
"type": "string",
},
"onBlur": Object {
"type": "func",
},
"onFocus": Object {
"type": "func",
},
"onMouseEnter": Object {
"type": "func",
},
"onMouseLeave": Object {
"type": "func",
},
"tooltipText": Object {
"isRequired": true,
"type": "string",
Expand Down
1 change: 1 addition & 0 deletions packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"@carbon/icons-react": "^10.28.0",
"@carbon/telemetry": "0.0.0-alpha.6",
"classnames": "2.2.6",
"copy-to-clipboard": "^3.3.1",
"downshift": "5.2.1",
"flatpickr": "4.6.9",
"invariant": "^2.2.3",
Expand Down
110 changes: 108 additions & 2 deletions packages/react/src/components/Button/Button.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@
*/

import PropTypes from 'prop-types';
import React from 'react';
import React, { useState, useEffect, useRef } from 'react';
import classNames from 'classnames';
import { settings } from 'carbon-components';
import { ButtonKinds } from '../../prop-types/types';
import deprecate from '../../prop-types/deprecate';
import { composeEventHandlers } from '../../tools/events';
import { keys, matches } from '../../internal/keyboard';
import toggleClass from '../../tools/toggleClass';

const { prefix } = settings;
const Button = React.forwardRef(function Button(
Expand All @@ -31,10 +34,78 @@ const Button = React.forwardRef(function Button(
hasIconOnly,
tooltipPosition,
tooltipAlignment,
onBlur,
onFocus,
onMouseEnter,
onMouseLeave,
...other
},
ref
) {
const [allowTooltipVisibility, setAllowTooltipVisibility] = useState(true);
const [isHovered, setIsHovered] = useState(false);
const [isFocused, setIsFocused] = useState(false);
const tooltipRef = useRef(null);
const tooltipTimeout = useRef(null);

const closeTooltips = (evt) => {
const tooltipNode = document?.querySelectorAll(`.${prefix}--tooltip--a11y`);
[...tooltipNode].map((node) => {
toggleClass(
node,
`${prefix}--tooltip--hidden`,
node !== evt.currentTarget
);
});
};

const handleFocus = (evt) => {
closeTooltips(evt);
setIsHovered(!isHovered);
setIsFocused(true);
setAllowTooltipVisibility(true);
};

const handleBlur = () => {
setIsHovered(false);
setIsFocused(false);
setAllowTooltipVisibility(false);
};

const handleMouseEnter = (evt) => {
setIsHovered(true);
tooltipTimeout.current && clearTimeout(tooltipTimeout.current);

if (evt.target === tooltipRef.current) {
setAllowTooltipVisibility(true);
return;
}

closeTooltips(evt);

setAllowTooltipVisibility(true);
};

const handleMouseLeave = () => {
if (!isFocused) {
tooltipTimeout.current = setTimeout(() => {
setAllowTooltipVisibility(false);
setIsHovered(false);
}, 100);
}
};

useEffect(() => {
const handleEscKeyDown = (event) => {
if (matches(event, [keys.Escape])) {
setAllowTooltipVisibility(false);
setIsHovered(false);
}
};
document.addEventListener('keydown', handleEscKeyDown);
return () => document.removeEventListener('keydown', handleEscKeyDown);
}, []);

const buttonClasses = classNames(className, {
[`${prefix}--btn`]: true,
[`${prefix}--btn--field`]: size === 'field',
Expand All @@ -43,6 +114,8 @@ const Button = React.forwardRef(function Button(
[`${prefix}--btn--xl`]: size === 'xl',
[`${prefix}--btn--${kind}`]: kind,
[`${prefix}--btn--disabled`]: disabled,
[`${prefix}--tooltip--hidden`]: hasIconOnly && !allowTooltipVisibility,
[`${prefix}--tooltip--visible`]: isHovered,
[`${prefix}--btn--icon-only`]: hasIconOnly,
[`${prefix}--btn--selected`]: hasIconOnly && isSelected && kind === 'ghost',
[`${prefix}--tooltip__trigger`]: hasIconOnly,
Expand Down Expand Up @@ -76,7 +149,12 @@ const Button = React.forwardRef(function Button(
href,
};
const assistiveText = hasIconOnly ? (
<span className={`${prefix}--assistive-text`}>{iconDescription}</span>
<div
ref={tooltipRef}
onMouseEnter={handleMouseEnter}
className={`${prefix}--assistive-text`}>
{iconDescription}
</div>
) : null;
if (as) {
component = as;
Expand All @@ -91,6 +169,10 @@ const Button = React.forwardRef(function Button(
return React.createElement(
component,
{
onMouseEnter: composeEventHandlers([onMouseEnter, handleMouseEnter]),
onMouseLeave: composeEventHandlers([onMouseLeave, handleMouseLeave]),
onFocus: composeEventHandlers([onFocus, handleFocus]),
onBlur: composeEventHandlers([onBlur, handleBlur]),
...other,
...commonProps,
...otherProps,
Expand Down Expand Up @@ -161,6 +243,30 @@ Button.propTypes = {
*/
kind: PropTypes.oneOf(ButtonKinds).isRequired,

/**
* Provide an optional function to be called when the button element
* loses focus
*/
onBlur: PropTypes.func,

/**
* Provide an optional function to be called when the button element
* receives focus
*/
onFocus: PropTypes.func,

/**
* Provide an optional function to be called when the mouse
* enters the button element
*/
onMouseEnter: PropTypes.func,

/**
* Provide an optional function to be called when the mouse
* leaves the button element
*/
onMouseLeave: PropTypes.func,

/**
* Optional prop to allow overriding the icon rendering.
* Can be a React component class
Expand Down
Loading

0 comments on commit 28a0833

Please sign in to comment.