diff --git a/packages/components/docs/sass.md b/packages/components/docs/sass.md index 33b0ad3bab92..0b294bcf9e26 100644 --- a/packages/components/docs/sass.md +++ b/packages/components/docs/sass.md @@ -22387,8 +22387,6 @@ Tag styles // tags used for filtering .#{$prefix}--tag--filter { @include tag-theme($inverse-02, $inverse-01); - - cursor: pointer; padding-right: rem(2px); &:focus, @@ -22397,28 +22395,34 @@ Tag styles } } - .#{$prefix}--tag--filter > svg { + .#{$prefix}--tag__close-icon { flex-shrink: 0; width: rem(20px); height: rem(20px); margin: 0 0 0 rem(4px); padding: rem(2px); border: 0; - fill: $inverse-01; background-color: transparent; border-radius: 50%; + cursor: pointer; &:hover { background-color: $inverse-hover-ui; } } - .#{$prefix}--tag--filter:focus > svg { + .#{$prefix}--tag__close-icon svg { + fill: $inverse-01; + } + + .#{$prefix}--tag__close-icon:focus { + outline: none; box-shadow: inset 0 0 0 2px $inverse-focus-ui; border-radius: 50%; } - .#{$prefix}--tag--filter.#{$prefix}--tag--disabled svg:hover { + .#{$prefix}--tag--filter.#{$prefix}--tag--disabled + .#{$prefix}--tag__close-icon:hover { background-color: transparent; } diff --git a/packages/components/src/components/tag/_tag.scss b/packages/components/src/components/tag/_tag.scss index 218e6928f20d..0c44bdd2aa61 100644 --- a/packages/components/src/components/tag/_tag.scss +++ b/packages/components/src/components/tag/_tag.scss @@ -98,8 +98,6 @@ // tags used for filtering .#{$prefix}--tag--filter { @include tag-theme($inverse-02, $inverse-01); - - cursor: pointer; padding-right: rem(2px); &:focus, @@ -108,28 +106,34 @@ } } - .#{$prefix}--tag--filter > svg { + .#{$prefix}--tag__close-icon { flex-shrink: 0; width: rem(20px); height: rem(20px); margin: 0 0 0 rem(4px); padding: rem(2px); border: 0; - fill: $inverse-01; background-color: transparent; border-radius: 50%; + cursor: pointer; &:hover { background-color: $inverse-hover-ui; } } - .#{$prefix}--tag--filter:focus > svg { + .#{$prefix}--tag__close-icon svg { + fill: $inverse-01; + } + + .#{$prefix}--tag__close-icon:focus { + outline: none; box-shadow: inset 0 0 0 2px $inverse-focus-ui; border-radius: 50%; } - .#{$prefix}--tag--filter.#{$prefix}--tag--disabled svg:hover { + .#{$prefix}--tag--filter.#{$prefix}--tag--disabled + .#{$prefix}--tag__close-icon:hover { background-color: transparent; } diff --git a/packages/components/src/components/tag/tag.hbs b/packages/components/src/components/tag/tag.hbs index 7b413dc22b00..75336ce92c62 100644 --- a/packages/components/src/components/tag/tag.hbs +++ b/packages/components/src/components/tag/tag.hbs @@ -15,9 +15,11 @@
{{#if filter}} - + +
{{/if}} diff --git a/packages/components/src/components/ui-shell/_side-nav.scss b/packages/components/src/components/ui-shell/_side-nav.scss index c3879da74ca4..397b8286b358 100644 --- a/packages/components/src/components/ui-shell/_side-nav.scss +++ b/packages/components/src/components/ui-shell/_side-nav.scss @@ -110,7 +110,7 @@ width: 0; } - .#{$prefix}--side-nav:not(.#{$prefix}--side-nav--fixed):hover, + .#{$prefix}--side-nav.bx--side-nav--rail:not(.#{$prefix}--side-nav--fixed):hover, .#{$prefix}--side-nav--expanded { width: mini-units(32); } diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index 22c75d47d08d..d6f026cd816a 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -4721,6 +4721,9 @@ Map { "filter": Object { "type": "bool", }, + "onClose": Object { + "type": "func", + }, "title": Object { "type": "string", }, diff --git a/packages/react/src/components/Tag/Tag-story.js b/packages/react/src/components/Tag/Tag-story.js index 1b9ddcf8971a..7a3e2c261fb2 100644 --- a/packages/react/src/components/Tag/Tag-story.js +++ b/packages/react/src/components/Tag/Tag-story.js @@ -29,7 +29,11 @@ const props = { title: 'Clear Filter', }), filter() { - return { ...this.regular(), onClick: action('onClick') }; + return { + ...this.regular(), + onClick: action('onClick'), + onClose: action('onClose'), + }; }, }; diff --git a/packages/react/src/components/Tag/Tag.js b/packages/react/src/components/Tag/Tag.js index 2b484c81b6b8..60c54f0daf5f 100644 --- a/packages/react/src/components/Tag/Tag.js +++ b/packages/react/src/components/Tag/Tag.js @@ -10,9 +10,10 @@ import React from 'react'; import classNames from 'classnames'; import { settings } from 'carbon-components'; import { Close16 } from '@carbon/icons-react'; +import setupGetInstanceId from '../../tools/setupGetInstanceId'; const { prefix } = settings; - +const getInstanceId = setupGetInstanceId(); const TYPES = { red: 'Red', magenta: 'Magenta', @@ -29,32 +30,45 @@ const TYPES = { const Tag = ({ children, className, + id, type, filter, title, disabled, + onClose, ...other }) => { + const tagId = id || `tag-${getInstanceId()}`; const tagClass = `${prefix}--tag--${type}`; const tagClasses = classNames(`${prefix}--tag`, tagClass, className, { [`${prefix}--tag--disabled`]: disabled, [`${prefix}--tag--filter`]: filter, }); + const handleClose = event => { + event.stopPropagation(); + onClose(event); + }; return filter ? ( - + + ) : ( {children !== null && children !== undefined ? children : TYPES[type]} @@ -92,6 +106,11 @@ Tag.propTypes = { * Text to show on clear filters */ title: PropTypes.string, + + /** + * Click handler for filter tag close button. + */ + onClose: PropTypes.func, }; export const types = Object.keys(TYPES); diff --git a/packages/react/src/components/UIShell/SideNav.js b/packages/react/src/components/UIShell/SideNav.js index 6c566763e50e..066f2d3ba816 100644 --- a/packages/react/src/components/UIShell/SideNav.js +++ b/packages/react/src/components/UIShell/SideNav.js @@ -99,7 +99,7 @@ const SideNav = React.forwardRef(function SideNav(props, ref) { eventHandlers.onBlur = event => handleToggle(event, false); } - if (addMouseListeners) { + if (addMouseListeners && isRail) { eventHandlers.onMouseEnter = () => handleToggle(true, true); eventHandlers.onMouseLeave = () => handleToggle(false, false); } diff --git a/packages/react/src/components/UIShell/__tests__/SideNav-test.js b/packages/react/src/components/UIShell/__tests__/SideNav-test.js index 9c92bbb94580..4799ae27c89d 100644 --- a/packages/react/src/components/UIShell/__tests__/SideNav-test.js +++ b/packages/react/src/components/UIShell/__tests__/SideNav-test.js @@ -8,6 +8,7 @@ import React from 'react'; import { mount } from 'enzyme'; import SideNav from '../SideNav'; +import SideNavLink from '../SideNavLink'; describe('SideNav', () => { let mockProps, wrapper; @@ -15,7 +16,7 @@ describe('SideNav', () => { beforeEach(() => { mockProps = { 'aria-label': 'Navigation', - children:

Navigation

, + children: Navigation, }; }); @@ -28,12 +29,18 @@ describe('SideNav', () => { expect(wrapper).toMatchSnapshot(); }); - it('by default, all event listeners are added', () => { + it('by default, focus event listeners are added', () => { wrapper = mount(); expect(wrapper.find('nav').props().onFocus).toBeDefined(); expect(wrapper.find('nav').props().onBlur).toBeDefined(); - expect(wrapper.find('nav').props().onMouseEnter).toBeDefined(); - expect(wrapper.find('nav').props().onMouseLeave).toBeDefined(); + }); + + it('by default, mouse event listeners are not added', () => { + wrapper = mount(); + expect(wrapper.find('nav').props().onFocus).toBeDefined(); + expect(wrapper.find('nav').props().onBlur).toBeDefined(); + expect(wrapper.find('nav').props().onMouseEnter).not.toBeDefined(); + expect(wrapper.find('nav').props().onMouseLeave).not.toBeDefined(); }); it('if addFocusListeners is specified as false, no focus event listeners props are added', () => { @@ -41,6 +48,15 @@ describe('SideNav', () => { wrapper.setProps({ addFocusListeners: false }); expect(wrapper.find('nav').props().onFocus).not.toBeDefined(); expect(wrapper.find('nav').props().onBlur).not.toBeDefined(); + expect(wrapper.find('nav').props().onMouseEnter).not.toBeDefined(); + expect(wrapper.find('nav').props().onMouseLeave).not.toBeDefined(); + }); + + it('if addFocusListeners is specified as false in rail SideNav, no event listeners props are added', () => { + wrapper = mount(); + wrapper.setProps({ addFocusListeners: false }); + expect(wrapper.find('nav').props().onFocus).not.toBeDefined(); + expect(wrapper.find('nav').props().onBlur).not.toBeDefined(); expect(wrapper.find('nav').props().onMouseEnter).toBeDefined(); expect(wrapper.find('nav').props().onMouseLeave).toBeDefined(); }); diff --git a/packages/react/src/components/UIShell/__tests__/__snapshots__/SideNav-test.js.snap b/packages/react/src/components/UIShell/__tests__/__snapshots__/SideNav-test.js.snap index 895d20bd1db4..df53d1e1b86d 100644 --- a/packages/react/src/components/UIShell/__tests__/__snapshots__/SideNav-test.js.snap +++ b/packages/react/src/components/UIShell/__tests__/__snapshots__/SideNav-test.js.snap @@ -19,12 +19,39 @@ exports[`SideNav should render 1`] = ` className="bx--side-nav__navigation bx--side-nav bx--side-nav--ux" onBlur={[Function]} onFocus={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} > -

- Navigation -

+ + +
  • + + + + + Navigation + + + + +
  • +
    +
    `;