From 75646c07af61188113f8a4f844baa29f2b5643de Mon Sep 17 00:00:00 2001 From: Alessandra Davila Date: Wed, 6 Oct 2021 01:58:49 -0500 Subject: [PATCH 01/35] feat(props): update table expand header props (#9659) * feat(props): update accordion and table expand header props * chore(acordion-item): remove prop changes from accordion item * chore(data-table): remove changes * test(snapshot): update snapshots * chore(date-table): fix typo in table expand header Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../__snapshots__/PublicAPI-test.js.snap | 66 ++++++++++++++++--- .../src/components/Accordion/AccordionItem.js | 2 +- .../components/DataTable/TableExpandHeader.js | 32 +++++++-- 3 files changed, 85 insertions(+), 15 deletions(-) diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index 248de768906b..7390b283f019 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -1212,21 +1212,46 @@ Map { }, "TableExpandHeader": Object { "propTypes": Object { - "ariaLabel": [Function], + "ariaLabel": Object { + "args": Array [ + Array [ + [Function], + [Function], + ], + ], + "type": "oneOfType", + }, "children": Object { "type": "node", }, "className": Object { "type": "string", }, - "enableExpando": Object { + "enableExpando": [Function], + "enableToggle": Object { "type": "bool", }, "expandIconDescription": Object { "type": "string", }, - "isExpanded": [Function], - "onExpand": [Function], + "isExpanded": Object { + "args": Array [ + Array [ + [Function], + [Function], + ], + ], + "type": "oneOfType", + }, + "onExpand": Object { + "args": Array [ + Array [ + [Function], + [Function], + ], + ], + "type": "oneOfType", + }, }, }, "TableExpandRow": Object { @@ -1852,21 +1877,46 @@ Map { }, "TableExpandHeader" => Object { "propTypes": Object { - "ariaLabel": [Function], + "ariaLabel": Object { + "args": Array [ + Array [ + [Function], + [Function], + ], + ], + "type": "oneOfType", + }, "children": Object { "type": "node", }, "className": Object { "type": "string", }, - "enableExpando": Object { + "enableExpando": [Function], + "enableToggle": Object { "type": "bool", }, "expandIconDescription": Object { "type": "string", }, - "isExpanded": [Function], - "onExpand": [Function], + "isExpanded": Object { + "args": Array [ + Array [ + [Function], + [Function], + ], + ], + "type": "oneOfType", + }, + "onExpand": Object { + "args": Array [ + Array [ + [Function], + [Function], + ], + ], + "type": "oneOfType", + }, }, }, "TableExpandRow" => Object { diff --git a/packages/react/src/components/Accordion/AccordionItem.js b/packages/react/src/components/Accordion/AccordionItem.js index 79aa438a913d..c2c8a472f8cf 100644 --- a/packages/react/src/components/Accordion/AccordionItem.js +++ b/packages/react/src/components/Accordion/AccordionItem.js @@ -13,7 +13,7 @@ import React, { useState } from 'react'; import { Text } from '../Text'; import { match, keys } from '../../internal/keyboard'; import { useId } from '../../internal/useId'; -import deprecate from '../../prop-types/deprecate.js'; +import deprecate from '../../prop-types/deprecate'; const { prefix } = settings; const defaultRenderExpando = (props) => - )} + ) : null} {children} ); @@ -56,15 +58,27 @@ TableExpandHeader.propTypes = { * Specify the string read by a voice reader when the expand trigger is * focused */ - ariaLabel: requiredIfGivenPropIsTruthy('enableExpando', PropTypes.string), + ariaLabel: PropTypes.oneOfType([ + requiredIfGivenPropIsTruthy('enableExpando', PropTypes.string), + requiredIfGivenPropIsTruthy('enableToggle', PropTypes.string), + ]), + children: PropTypes.node, className: PropTypes.string, + /** + * The enableExpando prop is being replaced by enableToggle + */ + enableExpando: deprecate( + PropTypes.bool, + 'The `enableExpando` prop has been deprecated in favor of `enableToggle`. This prop will be removed in the next major release.' + ), + /** * Specify whether an expand all button should be displayed */ - enableExpando: PropTypes.bool, + enableToggle: PropTypes.bool, /** * The description of the chevron right icon, to be put in its SVG `` element. @@ -75,12 +89,18 @@ TableExpandHeader.propTypes = { * Specify whether this row is expanded or not. This helps coordinate data * attributes so that `TableExpandRow` and `TableExpandedRow` work together */ - isExpanded: requiredIfGivenPropIsTruthy('enableExpando', PropTypes.bool), + isExpanded: PropTypes.oneOfType([ + requiredIfGivenPropIsTruthy('enableExpando', PropTypes.bool), + requiredIfGivenPropIsTruthy('enableToggle', PropTypes.bool), + ]), /** * Hook for when a listener initiates a request to expand the given row */ - onExpand: requiredIfGivenPropIsTruthy('enableExpando', PropTypes.func), + onExpand: PropTypes.oneOfType([ + requiredIfGivenPropIsTruthy('enableExpando', PropTypes.func), + requiredIfGivenPropIsTruthy('enableToggle', PropTypes.func), + ]), }; export default TableExpandHeader; From 3af8a9422a5edd77e71baceef73e425aabf59cfe Mon Sep 17 00:00:00 2001 From: Harry Liversedge <harryliversedge@gmail.com> Date: Wed, 6 Oct 2021 08:19:02 +0100 Subject: [PATCH 02/35] fix(tooltip): Fix tooltip alignment aligned on right hand side of container (#9606) * fix(tooltip): add auto-update on set state * fix(tooltip): safely check the size is different Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- packages/react/src/internal/FloatingMenu.js | 43 +++++++++++++-------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/packages/react/src/internal/FloatingMenu.js b/packages/react/src/internal/FloatingMenu.js index cd8f53c9867e..a64b952533fc 100644 --- a/packages/react/src/internal/FloatingMenu.js +++ b/packages/react/src/internal/FloatingMenu.js @@ -261,7 +261,7 @@ class FloatingMenu extends React.Component { * * @private */ - _updateMenuSize = (prevProps = {}) => { + _updateMenuSize = (prevProps = {}, isAdjustment = false) => { const menuBody = this._menuBody; warning( menuBody, @@ -279,7 +279,8 @@ class FloatingMenu extends React.Component { if ( hasChangeInOffset(oldMenuOffset, menuOffset) || - oldMenuDirection !== menuDirection + oldMenuDirection !== menuDirection || + isAdjustment ) { const { flipped, triggerRef } = this.props; const { current: triggerEl } = triggerRef; @@ -293,20 +294,30 @@ class FloatingMenu extends React.Component { // a) Menu body has `display:none` // b) `menuOffset` as a callback returns `undefined` (The callback saw that it couldn't calculate the value) if ((menuSize.width > 0 && menuSize.height > 0) || !offset) { - this.setState({ - floatingPosition: getFloatingPosition({ - menuSize, - refPosition, - direction: menuDirection, - offset, - scrollX: window.pageXOffset, - scrollY: window.pageYOffset, - container: { - rect: this.props.target().getBoundingClientRect(), - position: getComputedStyle(this.props.target()).position, - }, - }), - }); + this.setState( + { + floatingPosition: getFloatingPosition({ + menuSize, + refPosition, + direction: menuDirection, + offset, + scrollX: window.pageXOffset, + scrollY: window.pageYOffset, + container: { + rect: this.props.target().getBoundingClientRect(), + position: getComputedStyle(this.props.target()).position, + }, + }), + }, + () => { + if (!isAdjustment) { + const newMenuSize = menuBody.getBoundingClientRect(); + if (newMenuSize !== menuSize) { + this._updateMenuSize(this.props, true); + } + } + } + ); } } }; From 6e523982a9131c8cf340582eea4f12414f570b64 Mon Sep 17 00:00:00 2001 From: DAK <40970507+dakahn@users.noreply.github.com> Date: Wed, 6 Oct 2021 02:40:00 -0500 Subject: [PATCH 03/35] =?UTF-8?q?fix(MultiSelect):=20fix=20phantom=20selec?= =?UTF-8?q?tion=20on=20MenuKeyDownEnter=20=F0=9F=91=BB=20(#9765)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(MultiSelect): fix phantom selection on MenuKeyDownEnter * fix(MultiSelect): fix phantom selection on MenuKeyDownEnter Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- packages/react/src/components/MultiSelect/MultiSelect.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/react/src/components/MultiSelect/MultiSelect.js b/packages/react/src/components/MultiSelect/MultiSelect.js index 392bc95476c3..aa148aa2cb46 100644 --- a/packages/react/src/components/MultiSelect/MultiSelect.js +++ b/packages/react/src/components/MultiSelect/MultiSelect.js @@ -190,6 +190,9 @@ const MultiSelect = React.forwardRef(function MultiSelect( case ItemClick: case MenuKeyDownSpaceButton: case MenuKeyDownEnter: + if (changes.selectedItem === undefined) { + break; + } onItemChange(changes.selectedItem); break; case MenuKeyDownArrowDown: From 2612bbdadede026cb9f26b913825276b4f76fa3a Mon Sep 17 00:00:00 2001 From: ColbyJohnIBM <colbyj@us.ibm.com> Date: Thu, 7 Oct 2021 10:37:44 -0400 Subject: [PATCH 04/35] fix(Modal): fix Formik bug in Modal (#9797) * fix(Modal): fix Formik bug in Modal - Remove SecondaryButtonSet sub-component (causing re-renders w/ Formik) * fix(modal): formatting issues Co-authored-by: Alessandra Davila <aledavila@ibm.com> Co-authored-by: Scott Strubberg <sstrubberg@us.ibm.com> --- .all-contributorsrc | 9 ++++ README.md | 1 + packages/react/src/components/Modal/Modal.js | 46 ++++++++---------- .../__snapshots__/ModalWrapper-test.js.snap | 48 +++++++++---------- 4 files changed, 52 insertions(+), 52 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 444d90530529..438d1bb8bd25 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -801,6 +801,15 @@ "contributions": [ "code" ] + }, + { + "login": "ColbyJohnIBM", + "name": "ColbyJohnIBM", + "avatar_url": "https://avatars.githubusercontent.com/u/19613692?v=4", + "profile": "https://github.com/ColbyJohnIBM", + "contributions": [ + "code" + ] } ], "commitConvention": "none" diff --git a/README.md b/README.md index 1cd859141ab4..935208018c02 100644 --- a/README.md +++ b/README.md @@ -187,6 +187,7 @@ check out our [Contributing Guide](/.github/CONTRIBUTING.md) and our <td align="center"><a href="https://github.com/adamalston"><img src="https://avatars.githubusercontent.com/u/18297826?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Adam Alston</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=adamalston" title="Documentation">📖</a></td> <td align="center"><a href="https://github.com/Kiittyka"><img src="https://avatars.githubusercontent.com/u/41021851?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Krithika S Udupa</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=Kiittyka" title="Documentation">📖</a></td> <td align="center"><a href="https://github.com/egriff38"><img src="https://avatars.githubusercontent.com/u/6627718?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Eshin Griffith</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=egriff38" title="Code">💻</a></td> + <td align="center"><a href="https://github.com/ColbyJohnIBM"><img src="https://avatars.githubusercontent.com/u/19613692?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ColbyJohnIBM</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=ColbyJohnIBM" title="Code">💻</a></td> </tr> </table> diff --git a/packages/react/src/components/Modal/Modal.js b/packages/react/src/components/Modal/Modal.js index 1b14c8e5ac80..012baa8e1216 100644 --- a/packages/react/src/components/Modal/Modal.js +++ b/packages/react/src/components/Modal/Modal.js @@ -451,32 +451,6 @@ export default class Modal extends Component { alertDialogProps['aria-describedby'] = this.modalBodyId; } - const SecondaryButtonSet = () => { - if (Array.isArray(secondaryButtons) && secondaryButtons.length <= 2) { - return secondaryButtons.map( - ({ buttonText, onClick: onButtonClick }, i) => ( - <Button - key={`${buttonText}-${i}`} - kind="secondary" - onClick={onButtonClick}> - {buttonText} - </Button> - ) - ); - } - if (secondaryButtonText) { - return ( - <Button - kind="secondary" - onClick={onSecondaryButtonClick} - ref={this.secondaryButton}> - {secondaryButtonText} - </Button> - ); - } - return null; - }; - const modalBody = ( <div ref={this.innerModal} @@ -514,7 +488,25 @@ export default class Modal extends Component { )} {!passiveModal && ( <ButtonSet className={footerClasses}> - <SecondaryButtonSet /> + {Array.isArray(secondaryButtons) && secondaryButtons.length <= 2 + ? secondaryButtons.map( + ({ buttonText, onClick: onButtonClick }, i) => ( + <Button + key={`${buttonText}-${i}`} + kind="secondary" + onClick={onButtonClick}> + {buttonText} + </Button> + ) + ) + : secondaryButtonText && ( + <Button + kind="secondary" + onClick={onSecondaryButtonClick} + ref={this.secondaryButton}> + {secondaryButtonText} + </Button> + )} <Button kind={danger ? 'danger' : 'primary'} disabled={primaryButtonDisabled} diff --git a/packages/react/src/components/ModalWrapper/__snapshots__/ModalWrapper-test.js.snap b/packages/react/src/components/ModalWrapper/__snapshots__/ModalWrapper-test.js.snap index 4d504e9133ad..deffd66f96e6 100644 --- a/packages/react/src/components/ModalWrapper/__snapshots__/ModalWrapper-test.js.snap +++ b/packages/react/src/components/ModalWrapper/__snapshots__/ModalWrapper-test.js.snap @@ -167,36 +167,34 @@ exports[`ModalWrapper should render 1`] = ` <div className="bx--modal-footer bx--btn-set" > - <SecondaryButtonSet> - <Button - dangerDescription="danger" + <Button + dangerDescription="danger" + disabled={false} + isExpressive={false} + kind="secondary" + onClick={[Function]} + size="default" + tabIndex={0} + tooltipAlignment="center" + tooltipPosition="top" + type="button" + > + <button + aria-describedby={null} + aria-pressed={null} + className="bx--btn bx--btn--secondary" disabled={false} - isExpressive={false} - kind="secondary" + onBlur={[Function]} onClick={[Function]} - size="default" + onFocus={[Function]} + onMouseEnter={[Function]} + onMouseLeave={[Function]} tabIndex={0} - tooltipAlignment="center" - tooltipPosition="top" type="button" > - <button - aria-describedby={null} - aria-pressed={null} - className="bx--btn bx--btn--secondary" - disabled={false} - onBlur={[Function]} - onClick={[Function]} - onFocus={[Function]} - onMouseEnter={[Function]} - onMouseLeave={[Function]} - tabIndex={0} - type="button" - > - Cancel - </button> - </Button> - </SecondaryButtonSet> + Cancel + </button> + </Button> <Button dangerDescription="danger" disabled={false} From c53e70818d9d01cb2e386c4e15c86d4371743141 Mon Sep 17 00:00:00 2001 From: Rosie Z <35401262+rzhekova@users.noreply.github.com> Date: Thu, 7 Oct 2021 16:44:25 +0100 Subject: [PATCH 05/35] fix(OverflowMenu): add stopPropagation call to handleClick method (#9816) --- .../src/components/OverflowMenu/OverflowMenu-test.js | 9 +++++++++ .../react/src/components/OverflowMenu/OverflowMenu.js | 1 + 2 files changed, 10 insertions(+) diff --git a/packages/react/src/components/OverflowMenu/OverflowMenu-test.js b/packages/react/src/components/OverflowMenu/OverflowMenu-test.js index 7235879fad81..d670e58b5a99 100644 --- a/packages/react/src/components/OverflowMenu/OverflowMenu-test.js +++ b/packages/react/src/components/OverflowMenu/OverflowMenu-test.js @@ -160,6 +160,15 @@ describe('OverflowMenu', () => { ); }); + it('fires onClick only once per button click', () => { + const mockOnClick = jest.fn(); + const rootWrapper = mount(<OverflowMenu onClick={mockOnClick} />); + + rootWrapper.find('button').simulate('click'); + + expect(mockOnClick).toHaveBeenCalledTimes(1); + }); + it('should NOT toggle state in response to Enter or Space when the menu is open', () => { const enterKey = 13; const spaceKey = 32; diff --git a/packages/react/src/components/OverflowMenu/OverflowMenu.js b/packages/react/src/components/OverflowMenu/OverflowMenu.js index 596c68c3ea05..fa39310e553a 100644 --- a/packages/react/src/components/OverflowMenu/OverflowMenu.js +++ b/packages/react/src/components/OverflowMenu/OverflowMenu.js @@ -278,6 +278,7 @@ class OverflowMenu extends Component { } handleClick = (evt) => { + evt.stopPropagation(); if (!this._menuBody || !this._menuBody.contains(evt.target)) { this.setState({ open: !this.state.open }); this.props.onClick(evt); From 113bcf54ceee7879e81a65e628099cf90361734e Mon Sep 17 00:00:00 2001 From: Jan Hassel <jan.hassel@ibm.com> Date: Thu, 7 Oct 2021 22:58:23 +0200 Subject: [PATCH 06/35] fix: add shadow token, update overlay token (#9812) * fix: add shadow token, update overlay token * chore: run prettier * fix(tokens): update overlay token in g80 theme Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- packages/components/src/globals/scss/_helper-mixins.scss | 2 +- .../src/__tests__/__snapshots__/PublicAPI-test.js.snap | 1 + packages/styles/scss/__tests__/theme-test.js | 1 + packages/styles/scss/utilities/_box-shadow.scss | 4 +++- packages/themes/src/g10.js | 2 ++ packages/themes/src/g100.js | 4 +++- packages/themes/src/g80.js | 4 +++- packages/themes/src/g90.js | 4 +++- packages/themes/src/next/g10.js | 1 + packages/themes/src/next/g100.js | 7 ++++++- packages/themes/src/next/g90.js | 7 ++++++- .../next/tokens/__tests__/__snapshots__/v11-test.js.snap | 1 + packages/themes/src/next/tokens/v11TokenGroup.js | 3 +++ packages/themes/src/next/white.js | 1 + packages/themes/src/tokens.js | 2 ++ packages/themes/src/v9.js | 3 ++- packages/themes/src/white.js | 2 ++ 17 files changed, 41 insertions(+), 8 deletions(-) diff --git a/packages/components/src/globals/scss/_helper-mixins.scss b/packages/components/src/globals/scss/_helper-mixins.scss index 8bbb63d3a663..9d928cb6e322 100644 --- a/packages/components/src/globals/scss/_helper-mixins.scss +++ b/packages/components/src/globals/scss/_helper-mixins.scss @@ -55,7 +55,7 @@ /// @example @include box-shadow; /// @group global-helpers @mixin box-shadow { - box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); + box-shadow: 0 2px 6px $shadow; } /// Adds outline styles depending on specific type diff --git a/packages/elements/src/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/elements/src/__tests__/__snapshots__/PublicAPI-test.js.snap index 8d62e1a6b1db..875bace53a77 100644 --- a/packages/elements/src/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/elements/src/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -318,6 +318,7 @@ Array [ "scale", "selectedLightUI", "selectedUI", + "shadow", "size2XLarge", "sizeLarge", "sizeMedium", diff --git a/packages/styles/scss/__tests__/theme-test.js b/packages/styles/scss/__tests__/theme-test.js index 244b21093666..c31873150bcd 100644 --- a/packages/styles/scss/__tests__/theme-test.js +++ b/packages/styles/scss/__tests__/theme-test.js @@ -126,6 +126,7 @@ Array [ "highlight", "overlay", "toggle-off", + "shadow", "focus", "focus-inset", "focus-inverse", diff --git a/packages/styles/scss/utilities/_box-shadow.scss b/packages/styles/scss/utilities/_box-shadow.scss index cd309cb4016f..273f6bc12c3a 100644 --- a/packages/styles/scss/utilities/_box-shadow.scss +++ b/packages/styles/scss/utilities/_box-shadow.scss @@ -5,10 +5,12 @@ // LICENSE file in the root directory of this source tree. // +@use '../theme'; + /// Adds box shadow /// @access public /// @example @include box-shadow; /// @group utilities @mixin box-shadow { - box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); + box-shadow: 0 2px 6px theme.$shadow; } diff --git a/packages/themes/src/g10.js b/packages/themes/src/g10.js index 93631086aa35..4ab4b3ec91f9 100644 --- a/packages/themes/src/g10.js +++ b/packages/themes/src/g10.js @@ -37,6 +37,7 @@ import { // Constants white, + black, // Tools rgba, @@ -182,6 +183,7 @@ export const supportInfoInverse = inverseSupport04; export const overlay = overlay01; export const toggleOff = ui04; +export const shadow = rgba(black, 0.3); export const buttonPrimary = interactive01; export const buttonSecondary = interactive02; diff --git a/packages/themes/src/g100.js b/packages/themes/src/g100.js index 75aeba2352a1..e26fa82520a2 100644 --- a/packages/themes/src/g100.js +++ b/packages/themes/src/g100.js @@ -36,6 +36,7 @@ import { // Constants white, + black, // Tools rgba, @@ -86,7 +87,7 @@ export const inverseSupport02 = green50; export const inverseSupport03 = yellow; export const inverseSupport04 = blue60; -export const overlay01 = rgba(gray100, 0.7); +export const overlay01 = rgba(black, 0.65); export const danger01 = red60; export const danger02 = red50; @@ -181,6 +182,7 @@ export const supportInfoInverse = inverseSupport04; export const overlay = overlay01; export const toggleOff = ui04; +export const shadow = rgba(black, 0.8); export const buttonPrimary = interactive01; export const buttonSecondary = interactive02; diff --git a/packages/themes/src/g80.js b/packages/themes/src/g80.js index a3fd1c306bcb..48a407ebf097 100644 --- a/packages/themes/src/g80.js +++ b/packages/themes/src/g80.js @@ -37,6 +37,7 @@ import { // Constants white, + black, // Tools rgba, @@ -86,8 +87,9 @@ export const supportSuccessInverse = green50; export const supportWarningInverse = yellow30; export const supportInfoInverse = blue60; -export const overlay = rgba(gray100, 0.7); +export const overlay = rgba(black, 0.65); export const toggleOff = gray50; +export const shadow = rgba(black, 0.8); export const buttonPrimary = blue60; export const buttonSecondary = gray60; diff --git a/packages/themes/src/g90.js b/packages/themes/src/g90.js index 8a402752d663..1c82f1ee96bd 100644 --- a/packages/themes/src/g90.js +++ b/packages/themes/src/g90.js @@ -38,6 +38,7 @@ import { // Constants white, + black, // Tools rgba, @@ -88,7 +89,7 @@ export const inverseSupport02 = green50; export const inverseSupport03 = yellow; export const inverseSupport04 = blue60; -export const overlay01 = rgba(gray100, 0.7); +export const overlay01 = rgba(black, 0.65); export const danger01 = red60; export const danger02 = red40; @@ -183,6 +184,7 @@ export const supportInfoInverse = inverseSupport04; export const overlay = overlay01; export const toggleOff = ui04; +export const shadow = rgba(black, 0.8); export const buttonPrimary = interactive01; export const buttonSecondary = interactive02; diff --git a/packages/themes/src/next/g10.js b/packages/themes/src/next/g10.js index 036f585d0f92..9f56a2c37369 100644 --- a/packages/themes/src/next/g10.js +++ b/packages/themes/src/next/g10.js @@ -192,6 +192,7 @@ export const interactive = blue60; export const highlight = blue20; export const overlay = 'rgba(22, 22, 22, 0.5)'; export const toggleOff = gray50; +export const shadow = 'rgba(0, 0, 0, 0.3)'; export { // Type diff --git a/packages/themes/src/next/g100.js b/packages/themes/src/next/g100.js index 9f94922376f0..e4025736c52f 100644 --- a/packages/themes/src/next/g100.js +++ b/packages/themes/src/next/g100.js @@ -41,6 +41,10 @@ import { // Constants white, + black, + + // Tools + rgba, } from '@carbon/colors'; import { adjustLightness } from '../tools'; @@ -193,8 +197,9 @@ export const skeletonElement = gray80; // Misc export const interactive = blue50; export const highlight = blue20; -export const overlay = 'rgba(22, 22, 22, 0.5)'; +export const overlay = rgba(black, 0.65); export const toggleOff = gray50; +export const shadow = rgba(black, 0.8); export { // Type diff --git a/packages/themes/src/next/g90.js b/packages/themes/src/next/g90.js index 6ca00c2bee2f..8606bdb7930a 100644 --- a/packages/themes/src/next/g90.js +++ b/packages/themes/src/next/g90.js @@ -40,6 +40,10 @@ import { // Constants white, + black, + + // Tools + rgba, } from '@carbon/colors'; import { adjustLightness } from '../tools'; @@ -192,8 +196,9 @@ export const skeletonElement = gray70; // Misc export const interactive = blue50; export const highlight = blue70; -export const overlay = 'rgba(22, 22, 22, 0.7)'; +export const overlay = rgba(black, 0.65); export const toggleOff = gray50; +export const shadow = rgba(black, 0.8); export { // Type diff --git a/packages/themes/src/next/tokens/__tests__/__snapshots__/v11-test.js.snap b/packages/themes/src/next/tokens/__tests__/__snapshots__/v11-test.js.snap index 181d9068e21e..ff737aea4135 100644 --- a/packages/themes/src/next/tokens/__tests__/__snapshots__/v11-test.js.snap +++ b/packages/themes/src/next/tokens/__tests__/__snapshots__/v11-test.js.snap @@ -233,6 +233,7 @@ Array [ "highlight", "overlay", "toggle-off", + "shadow", "focus", "focus-inset", "focus-inverse", diff --git a/packages/themes/src/next/tokens/v11TokenGroup.js b/packages/themes/src/next/tokens/v11TokenGroup.js index 937a633dac75..d70bab34dff2 100644 --- a/packages/themes/src/next/tokens/v11TokenGroup.js +++ b/packages/themes/src/next/tokens/v11TokenGroup.js @@ -350,6 +350,9 @@ export const group = TokenGroup.create({ { name: 'toggle-off', }, + { + name: 'shadow', + }, focus, skeleton, diff --git a/packages/themes/src/next/white.js b/packages/themes/src/next/white.js index 6bbddd37bb67..d930c5f9cda1 100644 --- a/packages/themes/src/next/white.js +++ b/packages/themes/src/next/white.js @@ -191,6 +191,7 @@ export const interactive = blue60; export const highlight = blue20; export const overlay = 'rgba(22, 22, 22, 0.5)'; export const toggleOff = gray50; +export const shadow = 'rgba(0, 0, 0, 0.3)'; // Type export { diff --git a/packages/themes/src/tokens.js b/packages/themes/src/tokens.js index 2140cdaf82d0..9a65ea2f0852 100644 --- a/packages/themes/src/tokens.js +++ b/packages/themes/src/tokens.js @@ -150,6 +150,7 @@ const colors = [ 'overlay', 'toggleOff', + 'shadow', 'buttonPrimary', 'buttonSecondary', @@ -346,6 +347,7 @@ export const unstable__meta = { 'overlay', 'toggleOff', + 'shadow', 'buttonPrimary', 'buttonSecondary', diff --git a/packages/themes/src/v9.js b/packages/themes/src/v9.js index 3b18d198b9f0..09009202ec20 100644 --- a/packages/themes/src/v9.js +++ b/packages/themes/src/v9.js @@ -6,7 +6,7 @@ */ import { adjustLightness } from './tools'; -import { white, red60, gray40 } from '@carbon/colors'; +import { white, red60, gray40, black, rgba } from '@carbon/colors'; export const interactive01 = '#3d70b2'; export const interactive02 = '#4d5358'; @@ -147,6 +147,7 @@ export const supportInfoInverse = inverseSupport04; export const overlay = overlay01; export const toggleOff = ui04; +export const shadow = rgba(black, 0.3); export const buttonPrimary = interactive01; export const buttonSecondary = interactive02; diff --git a/packages/themes/src/white.js b/packages/themes/src/white.js index c928676bf532..19fe02f00ae5 100644 --- a/packages/themes/src/white.js +++ b/packages/themes/src/white.js @@ -37,6 +37,7 @@ import { // Constants white, + black, // Tools rgba, @@ -182,6 +183,7 @@ export const supportInfoInverse = inverseSupport04; export const overlay = overlay01; export const toggleOff = ui04; +export const shadow = rgba(black, 0.3); export const buttonPrimary = interactive01; export const buttonSecondary = interactive02; From 269867cdfc8282fd6298e475a9293bf7ea07c54f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 21:22:34 +0000 Subject: [PATCH 07/35] chore(deps): bump url-parse in /packages/type/examples/styled-components (#9810) Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.4.3 to 1.5.3. - [Release notes](https://github.com/unshiftio/url-parse/releases) - [Commits](https://github.com/unshiftio/url-parse/compare/1.4.3...1.5.3) --- updated-dependencies: - dependency-name: url-parse dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../type/examples/styled-components/yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/type/examples/styled-components/yarn.lock b/packages/type/examples/styled-components/yarn.lock index 48a7c0cd9dd4..5b3dc59cc7af 100644 --- a/packages/type/examples/styled-components/yarn.lock +++ b/packages/type/examples/styled-components/yarn.lock @@ -7724,10 +7724,10 @@ querystring@0.2.0: resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= -querystringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.0.tgz#7ded8dfbf7879dcc60d0a644ac6754b283ad17ef" - integrity sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg== +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== raf@3.4.0: version "3.4.0" @@ -9378,11 +9378,11 @@ url-loader@1.1.1: schema-utils "^1.0.0" url-parse@^1.1.8, url-parse@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.3.tgz#bfaee455c889023219d757e045fa6a684ec36c15" - integrity sha512-rh+KuAW36YKo0vClhQzLLveoj8FwPJNu65xLb7Mrt+eZht0IPT0IXgSv8gcMegZ6NvjJUALf6Mf25POlMwD1Fw== + version "1.5.3" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.3.tgz#71c1303d38fb6639ade183c2992c8cc0686df862" + integrity sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ== dependencies: - querystringify "^2.0.0" + querystringify "^2.1.1" requires-port "^1.0.0" url@^0.11.0: From 0152e7416e6f60e40b155a8f058a6f999bf81e2c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Oct 2021 21:48:57 +0000 Subject: [PATCH 08/35] chore(deps): bump url-parse (#9806) Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.4.4 to 1.5.3. - [Release notes](https://github.com/unshiftio/url-parse/releases) - [Commits](https://github.com/unshiftio/url-parse/compare/1.4.4...1.5.3) --- updated-dependencies: - dependency-name: url-parse dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Abbey Hart <abbeyhrt@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../react/examples/custom-css-prefix/yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/react/examples/custom-css-prefix/yarn.lock b/packages/react/examples/custom-css-prefix/yarn.lock index 2e9774cdcf69..e61c8fa42bc3 100644 --- a/packages/react/examples/custom-css-prefix/yarn.lock +++ b/packages/react/examples/custom-css-prefix/yarn.lock @@ -3076,10 +3076,10 @@ qs@6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== -querystringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.0.tgz#7ded8dfbf7879dcc60d0a644ac6754b283ad17ef" - integrity sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg== +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== range-parser@^1.0.3, range-parser@~1.2.0: version "1.2.0" @@ -3835,11 +3835,11 @@ urix@^0.1.0: integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= url-parse@^1.4.3: - version "1.4.4" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.4.tgz#cac1556e95faa0303691fec5cf9d5a1bc34648f8" - integrity sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg== + version "1.5.3" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.3.tgz#71c1303d38fb6639ade183c2992c8cc0686df862" + integrity sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ== dependencies: - querystringify "^2.0.0" + querystringify "^2.1.1" requires-port "^1.0.0" use@^3.1.0: From 3e0231dd76b0b1f95082121f3072c82e9240ea99 Mon Sep 17 00:00:00 2001 From: Kevin Perrine <kperrine@gmail.com> Date: Thu, 7 Oct 2021 18:13:02 -0400 Subject: [PATCH 09/35] feat(search): add onClear callback prop to Search/DataTableSearch (#9737) * feat(search): add onClear callback prop to Search/DataTableSearch * feat(data-table-search): add onClear default * feat(search): add onClear actions to stories * fix(search): adjust test to account for shallow rendering Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com> Co-authored-by: Abbey Hart <abbeyhrt@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../__snapshots__/PublicAPI-test.js.snap | 15 +++++++++++++++ .../src/components/DataTable/DataTable-story.js | 5 ++++- .../components/DataTable/TableToolbarSearch.js | 8 ++++++++ .../__snapshots__/DataTable-test.js.snap | 6 ++++++ .../__snapshots__/TableToolbarSearch-test.js.snap | 2 ++ .../react/src/components/Search/Search-story.js | 1 + .../react/src/components/Search/Search-test.js | 13 +++++++++++++ packages/react/src/components/Search/Search.js | 9 +++++++++ 8 files changed, 58 insertions(+), 1 deletion(-) diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index 7390b283f019..6b87038a912d 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -1527,6 +1527,7 @@ Map { }, "TableToolbarSearch": Object { "defaultProps": Object { + "onClear": [Function], "persistent": false, "tabIndex": "0", "translateWithId": [Function], @@ -1559,6 +1560,9 @@ Map { "onChange": Object { "type": "func", }, + "onClear": Object { + "type": "func", + }, "onExpand": Object { "type": "func", }, @@ -2157,6 +2161,7 @@ Map { }, "TableToolbarSearch" => Object { "defaultProps": Object { + "onClear": [Function], "persistent": false, "tabIndex": "0", "translateWithId": [Function], @@ -2189,6 +2194,9 @@ Map { "onChange": Object { "type": "func", }, + "onClear": Object { + "type": "func", + }, "onExpand": Object { "type": "func", }, @@ -5314,6 +5322,7 @@ Map { "defaultProps": Object { "closeButtonLabelText": "Clear search input", "onChange": [Function], + "onClear": [Function], "placeholder": "", "type": "text", }, @@ -5353,6 +5362,9 @@ Map { "onChange": Object { "type": "func", }, + "onClear": Object { + "type": "func", + }, "onKeyDown": Object { "type": "func", }, @@ -5484,6 +5496,9 @@ Map { "onChange": Object { "type": "func", }, + "onClear": Object { + "type": "func", + }, "onKeyDown": Object { "type": "func", }, diff --git a/packages/react/src/components/DataTable/DataTable-story.js b/packages/react/src/components/DataTable/DataTable-story.js index 9db6d7c27a35..f256cfdb83d5 100644 --- a/packages/react/src/components/DataTable/DataTable-story.js +++ b/packages/react/src/components/DataTable/DataTable-story.js @@ -213,7 +213,10 @@ export const WithToolbar = () => ( {...getTableContainerProps()}> <TableToolbar {...getToolbarProps()} aria-label="data table toolbar"> <TableToolbarContent> - <TableToolbarSearch onChange={onInputChange} /> + <TableToolbarSearch + onChange={onInputChange} + onClear={action('onClear')} + /> <TableToolbarMenu light> <TableToolbarAction onClick={action('Action 1 Click')}> Action 1 diff --git a/packages/react/src/components/DataTable/TableToolbarSearch.js b/packages/react/src/components/DataTable/TableToolbarSearch.js index 2e227cdabbfd..43549222b7ab 100644 --- a/packages/react/src/components/DataTable/TableToolbarSearch.js +++ b/packages/react/src/components/DataTable/TableToolbarSearch.js @@ -26,6 +26,7 @@ const TableToolbarSearch = ({ className, searchContainerClass, onChange: onChangeProp, + onClear, translateWithId: t, placeHolderText, placeholder, @@ -108,6 +109,7 @@ const TableToolbarSearch = ({ t('carbon.table.toolbar.search.placeholder') } onChange={onChange} + onClear={onClear} onFocus={(event) => handleExpand(event, true)} onBlur={(event) => !value && handleExpand(event, false)} {...rest} @@ -158,6 +160,11 @@ TableToolbarSearch.propTypes = { */ onChange: PropTypes.func, + /** + * Optional callback called when the search value is cleared. + */ + onClear: PropTypes.func, + /** * Provide an optional hook that is called each time the input is expanded */ @@ -205,6 +212,7 @@ TableToolbarSearch.defaultProps = { tabIndex: '0', translateWithId, persistent: false, + onClear: () => {}, }; export default TableToolbarSearch; diff --git a/packages/react/src/components/DataTable/__tests__/__snapshots__/DataTable-test.js.snap b/packages/react/src/components/DataTable/__tests__/__snapshots__/DataTable-test.js.snap index 3b24ce4a8d31..be0ae31e078e 100644 --- a/packages/react/src/components/DataTable/__tests__/__snapshots__/DataTable-test.js.snap +++ b/packages/react/src/components/DataTable/__tests__/__snapshots__/DataTable-test.js.snap @@ -1870,6 +1870,7 @@ exports[`DataTable should render 1`] = ` <TableToolbarSearch id="custom-id" onChange={[Function]} + onClear={[Function]} persistent={true} tabIndex="0" translateWithId={[Function]} @@ -2331,6 +2332,7 @@ exports[`DataTable should render 1`] = ` <TableToolbarSearch id="custom-id" onChange={[Function]} + onClear={[Function]} persistent={true} tabIndex="0" translateWithId={[Function]} @@ -2342,6 +2344,7 @@ exports[`DataTable should render 1`] = ` labelText="Filter table" onBlur={[Function]} onChange={[Function]} + onClear={[Function]} onFocus={[Function]} placeholder="Filter table" tabIndex="0" @@ -2928,6 +2931,7 @@ exports[`DataTable sticky header should render 1`] = ` <TableToolbarSearch id="custom-id" onChange={[Function]} + onClear={[Function]} persistent={true} tabIndex="0" translateWithId={[Function]} @@ -3392,6 +3396,7 @@ exports[`DataTable sticky header should render 1`] = ` <TableToolbarSearch id="custom-id" onChange={[Function]} + onClear={[Function]} persistent={true} tabIndex="0" translateWithId={[Function]} @@ -3403,6 +3408,7 @@ exports[`DataTable sticky header should render 1`] = ` labelText="Filter table" onBlur={[Function]} onChange={[Function]} + onClear={[Function]} onFocus={[Function]} placeholder="Filter table" tabIndex="0" diff --git a/packages/react/src/components/DataTable/__tests__/__snapshots__/TableToolbarSearch-test.js.snap b/packages/react/src/components/DataTable/__tests__/__snapshots__/TableToolbarSearch-test.js.snap index 82c69f41cce4..16c5d3a0092f 100644 --- a/packages/react/src/components/DataTable/__tests__/__snapshots__/TableToolbarSearch-test.js.snap +++ b/packages/react/src/components/DataTable/__tests__/__snapshots__/TableToolbarSearch-test.js.snap @@ -5,6 +5,7 @@ exports[`DataTable.TableToolbarSearch should render 1`] = ` className="custom-class" id="custom-id" onChange={[MockFunction]} + onClear={[Function]} persistent={false} tabIndex="0" translateWithId={[Function]} @@ -16,6 +17,7 @@ exports[`DataTable.TableToolbarSearch should render 1`] = ` labelText="Filter table" onBlur={[Function]} onChange={[Function]} + onClear={[Function]} onFocus={[Function]} placeholder="Filter table" tabIndex="0" diff --git a/packages/react/src/components/Search/Search-story.js b/packages/react/src/components/Search/Search-story.js index a43bd79ce169..a48c1e04a00e 100644 --- a/packages/react/src/components/Search/Search-story.js +++ b/packages/react/src/components/Search/Search-story.js @@ -46,6 +46,7 @@ const props = () => ({ placeholder: text('Placeholder text (placeholder)', 'Search'), onChange: action('onChange'), onKeyDown: action('onKeyDown'), + onClear: action('onClear'), }); export default { diff --git a/packages/react/src/components/Search/Search-test.js b/packages/react/src/components/Search/Search-test.js index cc87cf9849df..acb878cd7efa 100644 --- a/packages/react/src/components/Search/Search-test.js +++ b/packages/react/src/components/Search/Search-test.js @@ -182,6 +182,7 @@ describe('Search', () => { describe('enabled textinput', () => { const onClick = jest.fn(); const onChange = jest.fn(); + const onClear = jest.fn(); const wrapper = shallow( <Search @@ -189,6 +190,7 @@ describe('Search', () => { labelText="testlabel" onClick={onClick} onChange={onChange} + onClear={onClear} /> ); @@ -208,6 +210,17 @@ describe('Search', () => { input.simulate('change', eventObject); expect(onChange).toHaveBeenCalledWith(eventObject); }); + + it('should invoke onClear when input value is cleared', () => { + wrapper.setProps({ value: 'test' }); + const focus = jest.fn(); + input.getElement().ref({ + focus, + }); + wrapper.find('button').simulate('click', { target: { value: 'test' } }); + expect(onClear).toHaveBeenCalled(); + expect(focus).toHaveBeenCalled(); + }); }); }); }); diff --git a/packages/react/src/components/Search/Search.js b/packages/react/src/components/Search/Search.js index b3255f333260..fb041e351c79 100644 --- a/packages/react/src/components/Search/Search.js +++ b/packages/react/src/components/Search/Search.js @@ -59,6 +59,11 @@ export default class Search extends Component { */ onChange: PropTypes.func, + /** + * Optional callback called when the search value is cleared. + */ + onClear: PropTypes.func, + /** * Provide a handler that is invoked on the key down event for the input */ @@ -120,6 +125,7 @@ export default class Search extends Component { placeholder: '', closeButtonLabelText: 'Clear search input', onChange: () => {}, + onClear: () => {}, }; state = { @@ -150,6 +156,8 @@ export default class Search extends Component { this.props.onChange(clearedEvt); } + this.props.onClear(); + this.setState({ hasContent: false }, () => this.input.focus()); }; @@ -183,6 +191,7 @@ export default class Search extends Component { onChange, onKeyDown, renderIcon, + onClear, // eslint-disable-line no-unused-vars ...other } = this.props; From a82d3f4c9da7a5ef55b78f17bb1b4ce191b35e0e Mon Sep 17 00:00:00 2001 From: Harry Liversedge <harryliversedge@gmail.com> Date: Fri, 8 Oct 2021 18:15:06 +0100 Subject: [PATCH 10/35] feat(tooltip): Add optional prop to auto orientate within parent bounds (#9556) * feat(tooltip): add test story * feat(tooltip): add ability to update orientation * feat(tooltip): implement updates for direction * feat(tooltip): update orientation logic change * feat(tooltip): add prop to control behaviour * feat(tooltip): add remaining orientation checks * feat(tooltip): update naming * feat(tooltip): move logic into tooltip * feat(tooltip): fix tests * feat(tooltip): remove console statements * feat(tooltip): standarize comments in functions * feat(tooltip): add tooltips to all corners for clarity Co-authored-by: Harry-Liversedge <Harry.Liversedge@ibm.com> Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com> --- .../src/components/Tooltip/Tooltip-story.js | 98 +++++++++ .../react/src/components/Tooltip/Tooltip.js | 191 +++++++++++++++++- packages/react/src/internal/FloatingMenu.js | 26 ++- 3 files changed, 306 insertions(+), 9 deletions(-) diff --git a/packages/react/src/components/Tooltip/Tooltip-story.js b/packages/react/src/components/Tooltip/Tooltip-story.js index 03e25e764ca9..f0c26ecf9134 100644 --- a/packages/react/src/components/Tooltip/Tooltip-story.js +++ b/packages/react/src/components/Tooltip/Tooltip-story.js @@ -44,6 +44,17 @@ const props = { '' ), }), + autoOrientation: () => ({ + align: select('Tooltip alignment (align)', alignments, 'center'), + direction: select('Tooltip direction (direction)', directions, 'bottom'), + triggerText: text('Trigger text (triggerText)', 'Test'), + tabIndex: number('Tab index (tabIndex in <Tooltip>)', 0), + selectorPrimaryFocus: text( + 'Primary focus element selector (selectorPrimaryFocus)', + '' + ), + autoOrientation: boolean('Auto orientation', true), + }), withoutIcon: () => ({ showIcon: false, align: select('Tooltip alignment (align)', alignments, 'center'), @@ -178,6 +189,93 @@ DefaultBottom.parameters = { }, }; +export const AutoOrientation = () => ( + <div + style={{ + ...containerStyles, + justifyContent: 'unset', + alignItems: 'unset', + flexWrap: 'wrap', + }}> + {/* Top Left */} + <div style={{ flex: '50%' }}> + <Tooltip {...props.autoOrientation()} tooltipBodyId="tooltip-body"> + <p id="tooltip-body"> + This is some tooltip text. This box shows the maximum amount of text + that should appear inside. If more room is needed please use a modal + instead. + </p> + <div className={`${prefix}--tooltip__footer`}> + <a href="/" className={`${prefix}--link`}> + Learn More + </a> + <Button size="small">Create</Button> + </div> + </Tooltip> + </div> + {/* Top Right */} + <div style={{ flex: '50%', textAlign: 'right' }}> + <Tooltip {...props.autoOrientation()} tooltipBodyId="tooltip-body"> + <p id="tooltip-body"> + This is some tooltip text. This box shows the maximum amount of text + that should appear inside. If more room is needed please use a modal + instead. + </p> + <div className={`${prefix}--tooltip__footer`}> + <a href="/" className={`${prefix}--link`}> + Learn More + </a> + <Button size="small">Create</Button> + </div> + </Tooltip> + </div> + {/* Bottom Left */} + <div style={{ flex: '50%', marginTop: 'auto' }}> + <Tooltip {...props.autoOrientation()} tooltipBodyId="tooltip-body"> + <p id="tooltip-body"> + This is some tooltip text. This box shows the maximum amount of text + that should appear inside. If more room is needed please use a modal + instead. + </p> + <div className={`${prefix}--tooltip__footer`}> + <a href="/" className={`${prefix}--link`}> + Learn More + </a> + <Button size="small">Create</Button> + </div> + </Tooltip> + </div> + {/* Bottom Right */} + <div style={{ flex: '50%', textAlign: 'right', marginTop: 'auto' }}> + <Tooltip {...props.autoOrientation()} tooltipBodyId="tooltip-body"> + <p id="tooltip-body"> + This is some tooltip text. This box shows the maximum amount of text + that should appear inside. If more room is needed please use a modal + instead. + </p> + <div className={`${prefix}--tooltip__footer`}> + <a href="/" className={`${prefix}--link`}> + Learn More + </a> + <Button size="small">Create</Button> + </div> + </Tooltip> + </div> + </div> +); + +AutoOrientation.storyName = 'auto orientation'; + +AutoOrientation.parameters = { + info: { + text: ` + Interactive tooltip should be used if there are actions a user can take in the tooltip (e.g. a link or a button). + For more regular use case, e.g. giving the user more text information about something, use definition tooltip or icon tooltip. + By default, the tooltip will render above the element. The example below shows the default scenario. + `, + }, +}; + export const NoIcon = () => ( <div style={containerStyles}> <Tooltip {...props.withoutIcon()}> diff --git a/packages/react/src/components/Tooltip/Tooltip.js b/packages/react/src/components/Tooltip/Tooltip.js index 751f13f6bb87..0ec8ba2924d5 100644 --- a/packages/react/src/components/Tooltip/Tooltip.js +++ b/packages/react/src/components/Tooltip/Tooltip.js @@ -83,7 +83,11 @@ class Tooltip extends Component { return; } const open = useControlledStateWithValue ? props.defaultOpen : props.open; - this.state = { open }; + this.state = { + open, + storedDirection: props.direction, + storedAlign: props.align, + }; } static propTypes = { @@ -93,6 +97,11 @@ class Tooltip extends Component { */ align: PropTypes.oneOf(['start', 'center', 'end']), + /** + * Whether or not to re-orientate the tooltip if it goes outside, + * of the bounds of the parent. + */ + autoOrientation: PropTypes.bool, /** * Contents to put into the tooltip. */ @@ -263,6 +272,172 @@ class Tooltip extends Component { document.addEventListener('keydown', this.handleEscKeyPress, false); } + componentDidUpdate(prevProps, prevState) { + if (prevProps.direction != this.props.direction) { + this.setState({ storedDirection: this.props.direction }); + } + if (prevProps.align != this.props.align) { + this.setState({ storedAlign: this.props.align }); + } + if (prevState.open && !this.state.open) { + // Reset orientation when closing + this.setState({ + storedDirection: this.props.direction, + storedAlign: this.props.align, + }); + } + } + + updateOrientation = (params) => { + if (this.props.autoOrientation) { + const newOrientation = this.getBestDirection(params); + const { direction, align } = newOrientation; + + if (direction !== this.state.storedDirection) { + this.setState({ open: false }, () => { + this.setState({ open: true, storedDirection: direction }); + }); + } + + if (align === 'original') { + this.setState({ storedAlign: this.props.align }); + } else { + this.setState({ storedAlign: align }); + } + } + }; + + getBestDirection = ({ + menuSize, + refPosition = {}, + offset = {}, + direction = DIRECTION_BOTTOM, + scrollX: pageXOffset = 0, + scrollY: pageYOffset = 0, + container, + }) => { + const { + left: refLeft = 0, + top: refTop = 0, + right: refRight = 0, + bottom: refBottom = 0, + } = refPosition; + const scrollX = container.position !== 'static' ? 0 : pageXOffset; + const scrollY = container.position !== 'static' ? 0 : pageYOffset; + const relativeDiff = { + top: container.position !== 'static' ? container.rect.top : 0, + left: container.position !== 'static' ? container.rect.left : 0, + }; + const { width, height } = menuSize; + const { top = 0, left = 0 } = offset; + const refCenterHorizontal = (refLeft + refRight) / 2; + const refCenterVertical = (refTop + refBottom) / 2; + + // Calculate whether a new direction is needed to stay in parent. + // It will switch the current direction to the opposite i.e. + // If the direction="top" and the top boundary is overflowed + // then it switches the direction to "bottom". + const newDirection = () => { + switch (direction) { + case DIRECTION_LEFT: + return refLeft - width + scrollX - left - relativeDiff.left < 0 + ? DIRECTION_RIGHT + : direction; + case DIRECTION_TOP: + return refTop - height + scrollY - top - relativeDiff.top < 0 + ? DIRECTION_BOTTOM + : direction; + case DIRECTION_RIGHT: + return refRight + scrollX + left - relativeDiff.left + width > + container.rect.width + ? DIRECTION_LEFT + : direction; + case DIRECTION_BOTTOM: + return refBottom + scrollY + top - relativeDiff.top + height > + container.rect.height + ? DIRECTION_TOP + : direction; + default: + // If there is a new direction then ignore the logic above + return direction; + } + }; + + // Calculate whether a new alignment is needed to stay in parent + // If the direction is left or right this involves checking the + // overflow in the vertical direction. If the direction is top or + // bottom, this involves checking overflow in the horizontal direction. + // "original" is used to signify no change. + const newAlignment = () => { + switch (direction) { + case DIRECTION_LEFT: + case DIRECTION_RIGHT: + if ( + refCenterVertical - + height / 2 + + scrollY + + top - + 9 - + relativeDiff.top < + 0 + ) { + // If goes above the top boundary + return 'start'; + } else if ( + refCenterVertical - + height / 2 + + scrollY + + top - + 9 - + relativeDiff.top + + height > + container.rect.height + ) { + // If goes below the bottom boundary + return 'end'; + } else { + // No need to change alignment + return 'original'; + } + case DIRECTION_TOP: + case DIRECTION_BOTTOM: + if ( + refCenterHorizontal - + width / 2 + + scrollX + + left - + relativeDiff.left < + 0 + ) { + // If goes below the left boundary + return 'start'; + } else if ( + refCenterHorizontal - + width / 2 + + scrollX + + left - + relativeDiff.left + + width > + container.rect.width + ) { + // If it goes over the right boundary + return 'end'; + } else { + // No need to change alignment + return 'original'; + } + default: + // No need to change alignment + return 'original'; + } + }; + + return { + direction: newDirection(), + align: newAlignment(), + }; + }; + componentWillUnmount() { if (this._debouncedHandleFocus) { this._debouncedHandleFocus.cancel(); @@ -430,8 +605,6 @@ class Tooltip extends Component { children, className, triggerClassName, - direction, - align, focusTrap, triggerText, showIcon, @@ -447,13 +620,14 @@ class Tooltip extends Component { } = this.props; const { open } = this.isControlled ? this.props : this.state; + const { storedDirection, storedAlign } = this.state; const tooltipClasses = classNames( `${prefix}--tooltip`, { [`${prefix}--tooltip--shown`]: open, - [`${prefix}--tooltip--${direction}`]: direction, - [`${prefix}--tooltip--align-${align}`]: align, + [`${prefix}--tooltip--${storedDirection}`]: storedDirection, + [`${prefix}--tooltip--align-${storedAlign}`]: storedAlign, }, className ); @@ -523,16 +697,17 @@ class Tooltip extends Component { selectorPrimaryFocus={this.props.selectorPrimaryFocus} target={this._getTarget} triggerRef={this._triggerRef} - menuDirection={direction} + menuDirection={storedDirection} menuOffset={menuOffset} menuRef={(node) => { this._tooltipEl = node; - }}> + }} + updateOrientation={this.updateOrientation}> <div className={tooltipClasses} {...other} id={this._tooltipId} - data-floating-menu-direction={direction} + data-floating-menu-direction={storedDirection} onMouseOver={this.handleMouse} onMouseOut={this.handleMouse} onFocus={this.handleMouse} diff --git a/packages/react/src/internal/FloatingMenu.js b/packages/react/src/internal/FloatingMenu.js index a64b952533fc..5631d9f102ab 100644 --- a/packages/react/src/internal/FloatingMenu.js +++ b/packages/react/src/internal/FloatingMenu.js @@ -210,11 +210,17 @@ class FloatingMenu extends React.Component { current: PropTypes.any, }), ]), + + /** + * Optional function to change orientation of tooltip based on parent + */ + updateOrientation: PropTypes.func, }; static defaultProps = { menuOffset: {}, menuDirection: DIRECTION_BOTTOM, + updateOrientation: null, }; // `true` if the menu body is mounted and calculation of the position is in progress. @@ -282,7 +288,8 @@ class FloatingMenu extends React.Component { oldMenuDirection !== menuDirection || isAdjustment ) { - const { flipped, triggerRef } = this.props; + const { flipped, triggerRef, updateOrientation } = this.props; + const { current: triggerEl } = triggerRef; const menuSize = menuBody.getBoundingClientRect(); const refPosition = triggerEl && triggerEl.getBoundingClientRect(); @@ -290,6 +297,23 @@ class FloatingMenu extends React.Component { typeof menuOffset !== 'function' ? menuOffset : menuOffset(menuBody, menuDirection, triggerEl, flipped); + + // Optional function to allow parent component to check + // if the orientation needs to be changed based on params + if (updateOrientation) { + updateOrientation({ + menuSize, + refPosition, + direction: menuDirection, + offset, + scrollX: window.pageXOffset, + scrollY: window.pageYOffset, + container: { + rect: this.props.target().getBoundingClientRect(), + position: getComputedStyle(this.props.target()).position, + }, + }); + } // Skips if either in the following condition: // a) Menu body has `display:none` // b) `menuOffset` as a callback returns `undefined` (The callback saw that it couldn't calculate the value) From 19256b33cc78868da2df9fa055179e8fe6282971 Mon Sep 17 00:00:00 2001 From: Taylor Jones <tay1orjones@users.noreply.github.com> Date: Mon, 11 Oct 2021 10:21:46 -0500 Subject: [PATCH 11/35] chore(repo): add design defect issue template (#9826) --- .github/ISSUE_TEMPLATE/DESIGN_DEFECT.yaml | 93 +++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/DESIGN_DEFECT.yaml diff --git a/.github/ISSUE_TEMPLATE/DESIGN_DEFECT.yaml b/.github/ISSUE_TEMPLATE/DESIGN_DEFECT.yaml new file mode 100644 index 000000000000..804f5e773cef --- /dev/null +++ b/.github/ISSUE_TEMPLATE/DESIGN_DEFECT.yaml @@ -0,0 +1,93 @@ +name: Design defect 🎨 +description: Report a visual design issue +title: '[Bug]: ' +labels: 'type: bug 🐛' +body: + - type: markdown + attributes: + value: '## Welcome!' + - type: markdown + attributes: + value: + Thanks for taking the time to fill out the details below for this design + defect. + - type: dropdown + id: package + attributes: + label: Package + description: Which package(s) are you using? + multiple: true + options: + - 'carbon-components' + - 'carbon-components-react' + - '@carbon/colors' + - '@carbon/elements' + - '@carbon/grid' + - '@carbon/icons' + - '@carbon/icons-react' + - '@carbon/icons-vue' + - '@carbon/layout' + - '@carbon/motion' + - '@carbon/pictograms' + - '@carbon/pictograms-react' + - '@carbon/themes' + - '@carbon/type' + - '@carbon/upgrade' + validations: + required: true + - type: dropdown + id: browser + attributes: + label: Browser + description: Which browser(s) are you experiencing the issue? + multiple: true + options: + - Chrome + - Safari + - Firefox + - Edge + - type: input + id: version + attributes: + label: Package version + description: 'Which version(s) are you using?' + placeholder: e.g. v10.42.0 + validations: + required: true + - type: textarea + id: description + attributes: + label: Description + description: "Tell us more about the problem that you're running into" + placeholder: What did you see? What did you expect to see? + validations: + required: true + - type: input + id: example-url + attributes: + label: Screenshots + description: 'Provide screenshots of the problem' + validations: + required: true + - type: textarea + id: reproduce + attributes: + label: Steps to reproduce + description: + 'How do we reproduce the problem displayed in the screenshots above?' + validations: + required: true + - type: checkboxes + id: terms + attributes: + label: Code of Conduct + description: Please confirm the following + options: + - label: + I agree to follow this project's [Code of + Conduct](https://github.com/carbon-design-system/carbon/blob/f555616971a03fd454c0f4daea184adf41fff05b/.github/CODE_OF_CONDUCT.md) + required: true + - label: + I checked the [current + issues](https://github.com/carbon-design-system/carbon/issues) for + duplicate problems From 1a6eaf254d622341998f95c64740b86bfd6b326d Mon Sep 17 00:00:00 2001 From: Taylor Jones <tay1orjones@users.noreply.github.com> Date: Tue, 12 Oct 2021 11:00:53 -0500 Subject: [PATCH 12/35] fix(slider): correct input width (#9829) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- packages/components/src/components/slider/_slider.scss | 2 +- packages/styles/scss/components/slider/_slider.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/src/components/slider/_slider.scss b/packages/components/src/components/slider/_slider.scss index 36427087b781..5707cf6eabea 100644 --- a/packages/components/src/components/slider/_slider.scss +++ b/packages/components/src/components/slider/_slider.scss @@ -116,7 +116,7 @@ .#{$prefix}--slider-text-input, .#{$prefix}-slider-text-input { - width: auto; + width: rem(64px); height: rem(40px); -moz-appearance: textfield; text-align: center; diff --git a/packages/styles/scss/components/slider/_slider.scss b/packages/styles/scss/components/slider/_slider.scss index 35b83349914b..c99db693c0bc 100644 --- a/packages/styles/scss/components/slider/_slider.scss +++ b/packages/styles/scss/components/slider/_slider.scss @@ -124,7 +124,7 @@ .#{$prefix}--slider-text-input, .#{$prefix}-slider-text-input { - width: auto; + width: rem(64px); height: rem(40px); -moz-appearance: textfield; text-align: center; From 1730d730f0170ff92ed79b8b06f4d72551960d83 Mon Sep 17 00:00:00 2001 From: Taylor Jones <tay1orjones@users.noreply.github.com> Date: Tue, 12 Oct 2021 11:34:50 -0500 Subject: [PATCH 13/35] chore(release): v10.46.0-rc.0 (#9849) --- packages/carbon-react/package.json | 12 +++--- packages/components/package.json | 8 ++-- packages/elements/package.json | 6 +-- packages/icons-handlebars/package.json | 4 +- packages/icons-react/package.json | 4 +- packages/icons-vue/package.json | 4 +- packages/icons/package.json | 2 +- packages/react/package.json | 6 +-- packages/sketch/package.json | 6 +-- packages/styles/package.json | 4 +- packages/themes/package.json | 2 +- yarn.lock | 52 +++++++++++++------------- 12 files changed, 55 insertions(+), 55 deletions(-) diff --git a/packages/carbon-react/package.json b/packages/carbon-react/package.json index 27bc40c6442a..e3a5dad823c3 100644 --- a/packages/carbon-react/package.json +++ b/packages/carbon-react/package.json @@ -1,7 +1,7 @@ { "name": "@carbon/react", "description": "React components for the Carbon Design System", - "version": "0.6.0", + "version": "0.7.0-rc.0", "license": "Apache-2.0", "main": "lib/index.js", "module": "es/index.js", @@ -43,11 +43,11 @@ }, "dependencies": { "@carbon/feature-flags": "^0.6.0", - "@carbon/icons-react": "^10.40.0", - "@carbon/styles": "^0.6.0", + "@carbon/icons-react": "^10.41.0-rc.0", + "@carbon/styles": "^0.7.0-rc.0", "@carbon/telemetry": "0.0.0-alpha.6", - "carbon-components": "^10.45.0", - "carbon-components-react": "^7.45.0", + "carbon-components": "^10.46.0-rc.0", + "carbon-components-react": "^7.46.0-rc.0", "carbon-icons": "^7.0.7" }, "devDependencies": { @@ -58,7 +58,7 @@ "@babel/plugin-transform-react-constant-elements": "^7.14.5", "@babel/preset-env": "^7.14.7", "@babel/preset-react": "^7.14.5", - "@carbon/themes": "^10.44.0", + "@carbon/themes": "^10.45.0-rc.0", "@rollup/plugin-babel": "^5.3.0", "@rollup/plugin-commonjs": "^18.0.0", "@rollup/plugin-node-resolve": "^11.2.1", diff --git a/packages/components/package.json b/packages/components/package.json index 486a29520cda..c087684ea15a 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,7 +1,7 @@ { "name": "carbon-components", "description": "The Carbon Design System is IBM’s open-source design system for products and experiences.", - "version": "10.45.0", + "version": "10.46.0-rc.0", "license": "Apache-2.0", "main": "umd/index.js", "module": "es/index.js", @@ -81,9 +81,9 @@ "@babel/preset-react": "^7.14.5", "@babel/runtime": "^7.14.6", "@carbon/cli": "^10.30.0", - "@carbon/elements": "^10.44.0", - "@carbon/icons-handlebars": "^10.40.0", - "@carbon/icons-react": "^10.40.0", + "@carbon/elements": "^10.45.0-rc.0", + "@carbon/icons-handlebars": "^10.41.0-rc.0", + "@carbon/icons-react": "^10.41.0-rc.0", "@carbon/test-utils": "^10.19.0", "@frctl/fractal": "^1.1.0", "@rollup/plugin-babel": "^5.3.0", diff --git a/packages/elements/package.json b/packages/elements/package.json index 260d641e77d2..892de971d79b 100644 --- a/packages/elements/package.json +++ b/packages/elements/package.json @@ -1,7 +1,7 @@ { "name": "@carbon/elements", "description": "A collection of design elements in code for the IBM Design Language", - "version": "10.44.0", + "version": "10.45.0-rc.0", "license": "Apache-2.0", "main": "lib/index.js", "module": "es/index.js", @@ -37,11 +37,11 @@ "dependencies": { "@carbon/colors": "^10.33.0", "@carbon/grid": "^10.37.0", - "@carbon/icons": "^10.40.0", + "@carbon/icons": "^10.41.0-rc.0", "@carbon/import-once": "^10.6.0", "@carbon/layout": "^10.33.0", "@carbon/motion": "^10.25.0", - "@carbon/themes": "^10.44.0", + "@carbon/themes": "^10.45.0-rc.0", "@carbon/type": "^10.37.0" }, "devDependencies": { diff --git a/packages/icons-handlebars/package.json b/packages/icons-handlebars/package.json index 67fe47865128..a96e7f77bbba 100644 --- a/packages/icons-handlebars/package.json +++ b/packages/icons-handlebars/package.json @@ -1,7 +1,7 @@ { "name": "@carbon/icons-handlebars", "description": "Handlebars helpers for IBM Design Language icons in digital and software products using the Carbon Design System", - "version": "10.40.0", + "version": "10.41.0-rc.0", "license": "Apache-2.0", "main": "index.js", "repository": { @@ -27,7 +27,7 @@ }, "dependencies": { "@carbon/icon-helpers": "^10.24.0", - "@carbon/icons": "^10.40.0" + "@carbon/icons": "^10.41.0-rc.0" }, "devDependencies": { "handlebars": "^4.0.12" diff --git a/packages/icons-react/package.json b/packages/icons-react/package.json index ec90a6358937..306b3f218f67 100644 --- a/packages/icons-react/package.json +++ b/packages/icons-react/package.json @@ -1,7 +1,7 @@ { "name": "@carbon/icons-react", "description": "React components for icons in digital and software products using the Carbon Design System", - "version": "10.40.0", + "version": "10.41.0-rc.0", "license": "Apache-2.0", "main": "lib/index.js", "module": "es/index.js", @@ -44,7 +44,7 @@ }, "devDependencies": { "@carbon/icon-build-helpers": "^0.29.0", - "@carbon/icons": "^10.40.0", + "@carbon/icons": "^10.41.0-rc.0", "rimraf": "^3.0.2" }, "sideEffects": false diff --git a/packages/icons-vue/package.json b/packages/icons-vue/package.json index d73e3f6a6fbc..478de5ccf0d3 100644 --- a/packages/icons-vue/package.json +++ b/packages/icons-vue/package.json @@ -1,7 +1,7 @@ { "name": "@carbon/icons-vue", "description": "Vue components for icons in digital and software products using the Carbon Design System", - "version": "10.40.0", + "version": "10.41.0-rc.0", "license": "Apache-2.0", "main": "lib/index.js", "module": "es/index.js", @@ -32,7 +32,7 @@ }, "devDependencies": { "@carbon/cli-reporter": "^10.5.0", - "@carbon/icons": "^10.40.0", + "@carbon/icons": "^10.41.0-rc.0", "fs-extra": "^8.1.0", "prettier": "^2.2.1", "rimraf": "^3.0.0", diff --git a/packages/icons/package.json b/packages/icons/package.json index 3f1454418d90..72613eb5f205 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -1,7 +1,7 @@ { "name": "@carbon/icons", "description": "Icons for digital and software products using the Carbon Design System", - "version": "10.40.0", + "version": "10.41.0-rc.0", "license": "Apache-2.0", "main": "lib/index.js", "module": "es/index.js", diff --git a/packages/react/package.json b/packages/react/package.json index a91e7e1a9f2a..3249cd1ea899 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,7 +1,7 @@ { "name": "carbon-components-react", "description": "The Carbon Design System is IBM’s open-source design system for products and experiences.", - "version": "7.45.0", + "version": "7.46.0-rc.0", "license": "Apache-2.0", "main": "lib/index.js", "module": "es/index.js", @@ -46,7 +46,7 @@ }, "dependencies": { "@carbon/feature-flags": "^0.6.0", - "@carbon/icons-react": "^10.40.0", + "@carbon/icons-react": "^10.41.0-rc.0", "@carbon/telemetry": "0.0.0-alpha.6", "classnames": "2.3.1", "copy-to-clipboard": "^3.3.1", @@ -100,7 +100,7 @@ "babel-plugin-react-docgen": "^4.2.1", "babel-plugin-transform-inline-environment-variables": "^0.4.3", "browserslist-config-carbon": "^10.6.1", - "carbon-components": "^10.45.0", + "carbon-components": "^10.46.0-rc.0", "carbon-icons": "^7.0.5", "chalk": "^4.1.1", "cli-table": "^0.3.0", diff --git a/packages/sketch/package.json b/packages/sketch/package.json index 9b4e3d79b3f5..39d8f789b696 100644 --- a/packages/sketch/package.json +++ b/packages/sketch/package.json @@ -2,7 +2,7 @@ "name": "@carbon/sketch", "private": true, "description": "Tooling for generating a sketch plugin to bring code to design", - "version": "10.43.0", + "version": "10.44.0-rc.0", "license": "Apache-2.0", "repository": { "type": "git", @@ -30,8 +30,8 @@ "dependencies": { "@carbon/colors": "^10.33.0", "@carbon/icon-helpers": "^10.24.0", - "@carbon/icons": "^10.40.0", - "@carbon/themes": "^10.44.0", + "@carbon/icons": "^10.41.0-rc.0", + "@carbon/themes": "^10.45.0-rc.0", "@carbon/type": "^10.37.0", "@skpm/builder": "^0.7.0", "color-string": "^1.5.3", diff --git a/packages/styles/package.json b/packages/styles/package.json index 0c752f3c04bb..8d7da05ce069 100644 --- a/packages/styles/package.json +++ b/packages/styles/package.json @@ -1,7 +1,7 @@ { "name": "@carbon/styles", "description": "Styles for the Carbon Design System", - "version": "0.6.0", + "version": "0.7.0-rc.0", "license": "Apache-2.0", "repository": { "type": "git", @@ -25,7 +25,7 @@ "@carbon/grid": "^10.37.0", "@carbon/layout": "^10.33.0", "@carbon/motion": "^10.25.0", - "@carbon/themes": "^10.44.0", + "@carbon/themes": "^10.45.0-rc.0", "@carbon/type": "^10.37.0", "@ibm/plex": "6.0.0-next.6" }, diff --git a/packages/themes/package.json b/packages/themes/package.json index 33f2bb17a087..22400fd0409c 100644 --- a/packages/themes/package.json +++ b/packages/themes/package.json @@ -1,7 +1,7 @@ { "name": "@carbon/themes", "description": "Themes for applying color in the Carbon Design System", - "version": "10.44.0", + "version": "10.45.0-rc.0", "license": "Apache-2.0", "main": "lib/index.js", "module": "es/index.js", diff --git a/yarn.lock b/yarn.lock index cbfd24beaeda..006c57e1667b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1768,18 +1768,18 @@ __metadata: languageName: unknown linkType: soft -"@carbon/elements@^10.44.0, @carbon/elements@workspace:packages/elements": +"@carbon/elements@^10.45.0-rc.0, @carbon/elements@workspace:packages/elements": version: 0.0.0-use.local resolution: "@carbon/elements@workspace:packages/elements" dependencies: "@carbon/cli": ^10.30.0 "@carbon/colors": ^10.33.0 "@carbon/grid": ^10.37.0 - "@carbon/icons": ^10.40.0 + "@carbon/icons": ^10.41.0-rc.0 "@carbon/import-once": ^10.6.0 "@carbon/layout": ^10.33.0 "@carbon/motion": ^10.25.0 - "@carbon/themes": ^10.44.0 + "@carbon/themes": ^10.45.0-rc.0 "@carbon/type": ^10.37.0 fs-extra: ^8.1.0 klaw-sync: ^6.0.0 @@ -1870,25 +1870,25 @@ __metadata: languageName: node linkType: hard -"@carbon/icons-handlebars@^10.40.0, @carbon/icons-handlebars@workspace:packages/icons-handlebars": +"@carbon/icons-handlebars@^10.41.0-rc.0, @carbon/icons-handlebars@workspace:packages/icons-handlebars": version: 0.0.0-use.local resolution: "@carbon/icons-handlebars@workspace:packages/icons-handlebars" dependencies: "@carbon/icon-helpers": ^10.24.0 - "@carbon/icons": ^10.40.0 + "@carbon/icons": ^10.41.0-rc.0 handlebars: ^4.0.12 peerDependencies: handlebars: ^4.0.12 languageName: unknown linkType: soft -"@carbon/icons-react@^10.40.0, @carbon/icons-react@workspace:packages/icons-react": +"@carbon/icons-react@^10.41.0-rc.0, @carbon/icons-react@workspace:packages/icons-react": version: 0.0.0-use.local resolution: "@carbon/icons-react@workspace:packages/icons-react" dependencies: "@carbon/icon-build-helpers": ^0.29.0 "@carbon/icon-helpers": ^10.24.0 - "@carbon/icons": ^10.40.0 + "@carbon/icons": ^10.41.0-rc.0 "@carbon/telemetry": 0.0.0-alpha.6 prop-types: ^15.7.2 rimraf: ^3.0.2 @@ -1913,7 +1913,7 @@ __metadata: dependencies: "@carbon/cli-reporter": ^10.5.0 "@carbon/icon-helpers": ^10.24.0 - "@carbon/icons": ^10.40.0 + "@carbon/icons": ^10.41.0-rc.0 fs-extra: ^8.1.0 prettier: ^2.2.1 rimraf: ^3.0.0 @@ -1922,7 +1922,7 @@ __metadata: languageName: unknown linkType: soft -"@carbon/icons@^10.40.0, @carbon/icons@workspace:packages/icons": +"@carbon/icons@^10.41.0-rc.0, @carbon/icons@workspace:packages/icons": version: 0.0.0-use.local resolution: "@carbon/icons@workspace:packages/icons" dependencies: @@ -1996,10 +1996,10 @@ __metadata: "@babel/preset-env": ^7.14.7 "@babel/preset-react": ^7.14.5 "@carbon/feature-flags": ^0.6.0 - "@carbon/icons-react": ^10.40.0 - "@carbon/styles": ^0.6.0 + "@carbon/icons-react": ^10.41.0-rc.0 + "@carbon/styles": ^0.7.0-rc.0 "@carbon/telemetry": 0.0.0-alpha.6 - "@carbon/themes": ^10.44.0 + "@carbon/themes": ^10.45.0-rc.0 "@rollup/plugin-babel": ^5.3.0 "@rollup/plugin-commonjs": ^18.0.0 "@rollup/plugin-node-resolve": ^11.2.1 @@ -2013,8 +2013,8 @@ __metadata: babel-plugin-dev-expression: ^0.2.2 babel-preset-carbon: ^0.1.0 browserslist-config-carbon: ^10.6.1 - carbon-components: ^10.45.0 - carbon-components-react: ^7.45.0 + carbon-components: ^10.46.0-rc.0 + carbon-components-react: ^7.46.0-rc.0 carbon-icons: ^7.0.7 css-loader: ^5.2.4 fs-extra: ^10.0.0 @@ -2054,8 +2054,8 @@ __metadata: dependencies: "@carbon/colors": ^10.33.0 "@carbon/icon-helpers": ^10.24.0 - "@carbon/icons": ^10.40.0 - "@carbon/themes": ^10.44.0 + "@carbon/icons": ^10.41.0-rc.0 + "@carbon/themes": ^10.45.0-rc.0 "@carbon/type": ^10.37.0 "@skpm/builder": ^0.7.0 color-string: ^1.5.3 @@ -2067,7 +2067,7 @@ __metadata: languageName: unknown linkType: soft -"@carbon/styles@^0.6.0, @carbon/styles@workspace:packages/styles": +"@carbon/styles@^0.7.0-rc.0, @carbon/styles@workspace:packages/styles": version: 0.0.0-use.local resolution: "@carbon/styles@workspace:packages/styles" dependencies: @@ -2077,7 +2077,7 @@ __metadata: "@carbon/layout": ^10.33.0 "@carbon/motion": ^10.25.0 "@carbon/test-utils": ^10.19.0 - "@carbon/themes": ^10.44.0 + "@carbon/themes": ^10.45.0-rc.0 "@carbon/type": ^10.37.0 "@ibm/plex": 6.0.0-next.6 css: ^3.0.0 @@ -2121,7 +2121,7 @@ __metadata: languageName: unknown linkType: soft -"@carbon/themes@^10.44.0, @carbon/themes@workspace:packages/themes": +"@carbon/themes@^10.45.0-rc.0, @carbon/themes@workspace:packages/themes": version: 0.0.0-use.local resolution: "@carbon/themes@workspace:packages/themes" dependencies: @@ -10293,7 +10293,7 @@ __metadata: languageName: node linkType: hard -"carbon-components-react@^7.45.0, carbon-components-react@workspace:packages/react": +"carbon-components-react@^7.46.0-rc.0, carbon-components-react@workspace:packages/react": version: 0.0.0-use.local resolution: "carbon-components-react@workspace:packages/react" dependencies: @@ -10309,7 +10309,7 @@ __metadata: "@babel/preset-env": ^7.14.7 "@babel/preset-react": ^7.14.5 "@carbon/feature-flags": ^0.6.0 - "@carbon/icons-react": ^10.40.0 + "@carbon/icons-react": ^10.41.0-rc.0 "@carbon/telemetry": 0.0.0-alpha.6 "@carbon/test-utils": ^10.19.0 "@cypress/react": ^5.4.0 @@ -10336,7 +10336,7 @@ __metadata: babel-plugin-react-docgen: ^4.2.1 babel-plugin-transform-inline-environment-variables: ^0.4.3 browserslist-config-carbon: ^10.6.1 - carbon-components: ^10.45.0 + carbon-components: ^10.46.0-rc.0 carbon-icons: ^7.0.5 chalk: ^4.1.1 classnames: 2.3.1 @@ -10420,7 +10420,7 @@ __metadata: languageName: node linkType: hard -"carbon-components@^10.45.0, carbon-components@workspace:packages/components": +"carbon-components@^10.46.0-rc.0, carbon-components@workspace:packages/components": version: 0.0.0-use.local resolution: "carbon-components@workspace:packages/components" dependencies: @@ -10433,9 +10433,9 @@ __metadata: "@babel/preset-react": ^7.14.5 "@babel/runtime": ^7.14.6 "@carbon/cli": ^10.30.0 - "@carbon/elements": ^10.44.0 - "@carbon/icons-handlebars": ^10.40.0 - "@carbon/icons-react": ^10.40.0 + "@carbon/elements": ^10.45.0-rc.0 + "@carbon/icons-handlebars": ^10.41.0-rc.0 + "@carbon/icons-react": ^10.41.0-rc.0 "@carbon/telemetry": 0.0.0-alpha.6 "@carbon/test-utils": ^10.19.0 "@frctl/fractal": ^1.1.0 From dd1d0373462c166874ba26814ff251f90fb85496 Mon Sep 17 00:00:00 2001 From: Taylor Jones <tay1orjones@users.noreply.github.com> Date: Tue, 12 Oct 2021 13:51:20 -0500 Subject: [PATCH 14/35] feat(checkbox): add onClick prop (#9827) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../__snapshots__/PublicAPI-test.js.snap | 4 ++++ .../src/components/Checkbox/Checkbox-story.js | 1 + .../react/src/components/Checkbox/Checkbox.js | 20 ++++++++++++++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index 6b87038a912d..05d39d9412c2 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -322,6 +322,7 @@ Map { "defaultProps": Object { "indeterminate": false, "onChange": [Function], + "onClick": [Function], }, "displayName": "Checkbox", "propTypes": Object { @@ -354,6 +355,9 @@ Map { "onChange": Object { "type": "func", }, + "onClick": Object { + "type": "func", + }, "title": Object { "type": "string", }, diff --git a/packages/react/src/components/Checkbox/Checkbox-story.js b/packages/react/src/components/Checkbox/Checkbox-story.js index 6b43a8ec950f..a3ca825d7fd3 100644 --- a/packages/react/src/components/Checkbox/Checkbox-story.js +++ b/packages/react/src/components/Checkbox/Checkbox-story.js @@ -76,6 +76,7 @@ const props = () => ({ hideLabel: boolean('No label (hideLabel)', false), wrapperClassName: text('Wrapper CSS class name (wrapperClassName)', ''), onChange: action('onChange'), + onClick: action('onClick'), }); export const playground = () => ( diff --git a/packages/react/src/components/Checkbox/Checkbox.js b/packages/react/src/components/Checkbox/Checkbox.js index b1c7ae13f8ed..866239d26d51 100644 --- a/packages/react/src/components/Checkbox/Checkbox.js +++ b/packages/react/src/components/Checkbox/Checkbox.js @@ -19,6 +19,7 @@ const Checkbox = React.forwardRef(function Checkbox( id, labelText, onChange, + onClick, indeterminate, hideLabel, wrapperClassName, @@ -44,7 +45,15 @@ const Checkbox = React.forwardRef(function Checkbox( ); return ( - <div className={wrapperClasses}> + /* + The a11y rules below are disabled because <div> element has checkbox + input and label elements as children that allows keyboard interaction. + The onClick handler facilitates consumers' ability to stop click events + from bubbling beyond the checkbox without having to implement their own + wrapper element around <Checkbox>. + */ + /* eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */ + <div className={wrapperClasses} onClick={(evt) => onClick(evt)}> <input {...other} type="checkbox" @@ -123,6 +132,14 @@ Checkbox.propTypes = { */ onChange: PropTypes.func, + /** + * Provide an optional click handler that is applied to the wrapper div + * containing both the input and the span label. As such, this will be + * called twice for every click - once for the input, a second time for the label. + * Receives the dom event as its only argument. + */ + onClick: PropTypes.func, + /** * Specify a title for the <label> node for the Checkbox */ @@ -139,6 +156,7 @@ Checkbox.propTypes = { Checkbox.defaultProps = { onChange: () => {}, + onClick: () => {}, indeterminate: false, }; From 83f26589275aa42edb713c17af77c99f3412fa4e Mon Sep 17 00:00:00 2001 From: Scott Strubberg <sstrubberg@protonmail.com> Date: Wed, 13 Oct 2021 13:27:38 -0500 Subject: [PATCH 15/35] chore(tile): refactor to functional component (#9721) * chore(tile): refactor to functional component * fix(tile): build errors * fix(tile): working with storybook * fix(tile): added prefixes * feat(tile): refactoring-feature-flags * feat(tile): removed custom styling * Update packages/react/.storybook/preview.js Co-authored-by: Josh Black <josh@josh.black> * Update packages/react/src/components/Tile/next/Tile.js Co-authored-by: Josh Black <josh@josh.black> * Update packages/react/src/components/Tile/next/Tile.js Co-authored-by: Josh Black <josh@josh.black> * Update packages/react/src/components/Tile/next/Tile.js Co-authored-by: Josh Black <josh@josh.black> * Update packages/react/src/components/Tile/next/Tile.js Co-authored-by: Josh Black <josh@josh.black> * Update packages/react/src/components/Tile/next/Tile.js Co-authored-by: Josh Black <josh@josh.black> * fix(tile): removed useEffect hook * fix(tile): alphabetized things * fix(tile): syntax * fix(Tile): added deprecation warning for the light prop * feat(tile): added tests * feat(tile): added rtl * feat(tile): removed debug * feat(tile): hammering on testing * feat(tile): added more tests * feat(tile): hammering on tests * feat(tile): fixed an aria-label Co-authored-by: Josh Black <josh@josh.black> --- packages/react/package.json | 1 + packages/react/src/components/Tile/index.js | 43 +- .../src/components/Tile/next/Tile-test.js | 126 ++++ .../react/src/components/Tile/next/Tile.js | 704 ++++++++++++++++++ 4 files changed, 873 insertions(+), 1 deletion(-) create mode 100644 packages/react/src/components/Tile/next/Tile-test.js create mode 100644 packages/react/src/components/Tile/next/Tile.js diff --git a/packages/react/package.json b/packages/react/package.json index 3249cd1ea899..cd6a35def526 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -34,6 +34,7 @@ "postinstall": "carbon-telemetry collect --install", "prepublish": "yarn build", "start": "yarn storybook", + "start:v11": "CARBON_ENABLE_V11_RELEASE=true yarn storybook", "storybook": "rimraf node_modules/.cache/storybook && start-storybook -p 9000 -s ./.storybook/assets", "snapshot": "build-storybook && percy-storybook --widths=320,1280", "test:e2e": "cypress run-ct --config video=false,screenshotOnRunFailure=false" diff --git a/packages/react/src/components/Tile/index.js b/packages/react/src/components/Tile/index.js index 941915717a0d..5841eb962766 100644 --- a/packages/react/src/components/Tile/index.js +++ b/packages/react/src/components/Tile/index.js @@ -5,4 +5,45 @@ * LICENSE file in the root directory of this source tree. */ -export * from './Tile'; +import * as FeatureFlags from '@carbon/feature-flags'; +import { + Tile as TileNext, + ClickableTile as ClickableTileNext, + SelectableTile as SelectableTileNext, + TileAboveTheFoldContent as TileAboveTheFoldContentNext, + TileBelowTheFoldContent as TileBelowTheFoldContentNext, +} from './next/Tile'; +import { + Tile as TileClassic, + ClickableTile as ClickableTileClassic, + SelectableTile as SelectableTileClassic, + ExpandableTile, + TileAboveTheFoldContent as TileAboveTheFoldContentClassic, + TileBelowTheFoldContent as TileBelowTheFoldContentClassic, +} from './Tile'; + +export const Tile = FeatureFlags.enabled('enable-v11-release') + ? TileNext + : TileClassic; + +export const ClickableTile = FeatureFlags.enabled('enable-v11-release') + ? ClickableTileNext + : ClickableTileClassic; + +export const SelectableTile = FeatureFlags.enabled('enable-v11-release') + ? SelectableTileNext + : SelectableTileClassic; + +export { ExpandableTile }; + +export const TileAboveTheFoldContent = FeatureFlags.enabled( + 'enable-v11-release' +) + ? TileAboveTheFoldContentNext + : TileAboveTheFoldContentClassic; + +export const TileBelowTheFoldContent = FeatureFlags.enabled( + 'enable-v11-release' +) + ? TileBelowTheFoldContentNext + : TileBelowTheFoldContentClassic; diff --git a/packages/react/src/components/Tile/next/Tile-test.js b/packages/react/src/components/Tile/next/Tile-test.js new file mode 100644 index 000000000000..423fcd72548d --- /dev/null +++ b/packages/react/src/components/Tile/next/Tile-test.js @@ -0,0 +1,126 @@ +/** + * Copyright IBM Corp. 2016, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import { Tile, ClickableTile, SelectableTile } from './Tile'; + +import Link from '../../Link'; +import { render, cleanup, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import '@testing-library/jest-dom'; + +describe('Default', () => { + afterEach(cleanup); + + it('adds extra classes that are passed via className', () => { + render( + <Tile className="🚀"> + Default tile + <br /> + <br /> + <Link href="https://www.carbondesignsystem.com">Link</Link> + </Tile> + ); + + expect(screen.getByText('Default tile').classList.contains('🚀')).toBe( + true + ); + }); +}); + +describe('ClickableTile', () => { + afterEach(cleanup); + + it('renders with a link', () => { + render( + <ClickableTile href="https://www.carbondesignsystem.com"> + Clickable Tile + </ClickableTile> + ); + expect(screen.getByRole('link')).toBeInTheDocument(); + }); +}); + +describe('Multi Select', () => { + afterEach(cleanup); + + it('does not invoke the click handler if SelectableTile is disabled', () => { + const onClick = jest.fn(); + render( + <div role="group" aria-label="selectable tiles"> + <SelectableTile + id="tile-1" + name="tiles" + value="value" + onClick={onClick} + disabled> + <span role="img" aria-label="vertical traffic light"> + 🚦 + </span> + </SelectableTile> + </div> + ); + const tile = screen.getByText('🚦'); + userEvent.click(tile); + expect(onClick).not.toHaveBeenCalled(); + }); + + it('should cycle elements in document tab order', () => { + render( + <div role="group" aria-label="selectable tiles"> + <SelectableTile + data-testid="element" + id="tile-1" + name="tiles" + value="value"> + tile 1 + </SelectableTile> + <SelectableTile + data-testid="element" + id="tile-2" + name="tiles" + value="value"> + tile 2 + </SelectableTile> + <SelectableTile + data-testid="element" + id="tile-3" + name="tiles" + value="value"> + tile 3 + </SelectableTile> + </div> + ); + const [id1, id2, id3] = screen.getAllByTestId('element'); + expect(document.body).toHaveFocus(); + + userEvent.tab(); + + expect(id1).toHaveFocus(); + + userEvent.tab(); + + expect(id2).toHaveFocus(); + + userEvent.tab(); + + expect(id3).toHaveFocus(); + + userEvent.tab(); + + // cycle goes back to the body element + expect(document.body).toHaveFocus(); + + userEvent.tab(); + + expect(id1).toHaveFocus(); + }); +}); + +// Todo: Testing for a disabled ClickableTile +// Todo: Testing for ExpandableTile +// Todo: Testing for RadioTile diff --git a/packages/react/src/components/Tile/next/Tile.js b/packages/react/src/components/Tile/next/Tile.js new file mode 100644 index 000000000000..9dd9976b96b3 --- /dev/null +++ b/packages/react/src/components/Tile/next/Tile.js @@ -0,0 +1,704 @@ +/** + * Copyright IBM Corp. 2016, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, { Component, useState } from 'react'; +import PropTypes from 'prop-types'; +import cx from 'classnames'; +import Link from '../../Link'; +import { + Checkbox16, + CheckboxCheckedFilled16, + ChevronDown16, +} from '@carbon/icons-react'; +import { keys, matches } from '../../../internal/keyboard'; +import deprecate from '../../../prop-types/deprecate'; +import { composeEventHandlers } from '../../../tools/events'; +import { PrefixContext, usePrefix } from '../../../internal/usePrefix'; + +export const Tile = React.forwardRef(function Tile( + { children, className, light = false, ...rest }, + ref +) { + const prefix = usePrefix(); + + const tileClasses = cx( + `${prefix}--tile`, + { + [`${prefix}--tile--light`]: light, + }, + className + ); + return ( + <div className={tileClasses} ref={ref} {...rest}> + {children} + </div> + ); +}); + +Tile.displayName = 'Tile'; +Tile.propTypes = { + /** + * The child nodes. + */ + children: PropTypes.node, + + /** + * The CSS class names. + */ + className: PropTypes.string, + + /** + * `true` to use the light version. For use on $ui-01 backgrounds only. + * Don't use this to make tile background color same as container background color. + */ + light: deprecate( + PropTypes.bool, + 'The `light` prop for `Tile` is no longer needed and has been deprecated. It will be removed in the next major release. Use the Layer component instead.' + ), +}; + +export const ClickableTile = React.forwardRef(function ClickableTile( + { + children, + className, + clicked = false, + handleClick, + handleKeyDown, + href, + light = false, + onClick = () => {}, + onKeyDown = () => {}, + ...rest + }, + ref +) { + const prefix = usePrefix(); + + const classes = cx( + `${prefix}--tile`, + `${prefix}--tile--clickable`, + { + [`${prefix}--tile--is-clicked`]: clicked, + [`${prefix}--tile--light`]: light, + }, + className + ); + + const [isSelected, setIsSelected] = useState(clicked); + + // TODO: replace with onClick when handleClick prop is deprecated + const clickHandler = handleClick || onClick; + + // TODO: replace with onClick when handleClick prop is deprecated + const keyDownHandler = handleKeyDown || onKeyDown; + + function handleOnClick(evt) { + evt.persist(); + setIsSelected(!isSelected); + clickHandler(evt); + } + + function handleOnKeyDown(evt) { + evt.persist(); + if (matches(evt, [keys.Enter, keys.Space])) { + evt.preventDefault(); + setIsSelected(!isSelected); + keyDownHandler(evt); + } + keyDownHandler(evt); + } + + return ( + <Link + className={classes} + href={href} + onClick={handleOnClick} + onKeyDown={handleOnKeyDown} + ref={ref} + {...rest}> + {children} + </Link> + ); +}); + +ClickableTile.displayName = 'ClickableTile'; +ClickableTile.propTypes = { + /** + * The child nodes. + */ + children: PropTypes.node, + + /** + * The CSS class names. + */ + className: PropTypes.string, + + /** + * Boolean for whether a tile has been clicked. + */ + clicked: PropTypes.bool, + + /** + * Deprecated in v11. Use 'onClick' instead. + */ + handleClick: deprecate( + PropTypes.func, + 'The handleClick prop for ClickableTile has been deprecated in favor of onClick. It will be removed in the next major release.' + ), + + /** + * Specify the function to run when the ClickableTile is interacted with via a keyboard + */ + handleKeyDown: deprecate( + PropTypes.func, + 'The handleKeyDown prop for ClickableTile has been deprecated in favor of onKeyDown. It will be removed in the next major release.' + ), + + /** + * The href for the link. + */ + href: PropTypes.string, + + /** + * `true` to use the light version. For use on $ui-01 backgrounds only. + * Don't use this to make tile background color same as container background color. + */ + light: deprecate( + PropTypes.bool, + 'The `light` prop for `Tile` is no longer needed and has been deprecated. It will be removed in the next major release. Use the Layer component instead.' + ), + + /** + * Specify the function to run when the ClickableTile is clicked + */ + onClick: PropTypes.func, + + /** + * Specify the function to run when the ClickableTile is interacted with via a keyboard + */ + onKeyDown: PropTypes.func, + + /** + * The rel property for the link. + */ + rel: PropTypes.string, +}; + +export const SelectableTile = React.forwardRef(function SelectableTile( + { + children, + className, + disabled, + handleClick, + handleKeyDown, + // TODO: Remove iconDescription prop in the next major release + // eslint-disable-next-line no-unused-vars + iconDescription, + id, + light = false, + name, + onClick = () => {}, + onChange = () => {}, + onKeyDown = () => {}, + selected = false, + tabIndex = 0, + title = 'title', + value = 'value', + ...rest + }, + ref +) { + const prefix = usePrefix(); + + // TODO: replace with onClick when handleClick prop is deprecated + const clickHandler = handleClick || onClick; + + // TODO: replace with onKeyDown when handleKeyDown prop is deprecated + const keyDownHandler = handleKeyDown || onKeyDown; + + const [isSelected, setIsSelected] = useState(selected); + const [prevSelected, setPrevSelected] = useState(selected); + + const classes = cx( + `${prefix}--tile`, + `${prefix}--tile--selectable`, + { + [`${prefix}--tile--is-selected`]: isSelected, + [`${prefix}--tile--light`]: light, + [`${prefix}--tile--disabled`]: disabled, + }, + className + ); + const inputClasses = cx(`${prefix}--tile-input`, { + [`${prefix}--tile-input--checked`]: isSelected, + }); + + // TODO: rename to handleClick when handleClick prop is deprecated + function handleOnClick(evt) { + evt.preventDefault(); + evt.persist(); + setIsSelected(!isSelected); + clickHandler(evt); + onChange(evt); + } + + // TODO: rename to handleKeyDown when handleKeyDown prop is deprecated + function handleOnKeyDown(evt) { + evt.persist(); + if (matches(evt, [keys.Enter, keys.Space])) { + evt.preventDefault(); + setIsSelected(!isSelected); + onChange(evt); + } + keyDownHandler(evt); + } + + function handleChange(event) { + setIsSelected(event.target.checked); + onChange(event); + } + + if (selected !== prevSelected) { + setIsSelected(selected); + setPrevSelected(selected); + } + + return ( + <> + <input + checked={isSelected} + className={inputClasses} + disabled={disabled} + id={id} + name={name} + onChange={!disabled ? handleChange : null} + ref={ref} + tabIndex={-1} + title={title} + type="checkbox" + value={value} + /> + {/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */} + <label + className={classes} + htmlFor={id} + onClick={!disabled ? handleOnClick : null} + onKeyDown={!disabled ? handleOnKeyDown : null} + // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex + tabIndex={!disabled ? tabIndex : null} + {...rest}> + <span + className={`${prefix}--tile__checkmark ${prefix}--tile__checkmark--persistent`}> + {isSelected ? <CheckboxCheckedFilled16 /> : <Checkbox16 />} + </span> + <span className={`${prefix}--tile-content`}>{children}</span> + </label> + </> + ); +}); + +SelectableTile.displayName = 'SelectableTile'; +SelectableTile.propTypes = { + /** + * The child nodes. + */ + children: PropTypes.node, + + /** + * The CSS class names. + */ + className: PropTypes.string, + + /** + * Specify whether the SelectableTile should be disabled + */ + disabled: PropTypes.bool, + + /** + * Specify the function to run when the SelectableTile is clicked + */ + handleClick: deprecate( + PropTypes.func, + 'The `handleClick` prop for `SelectableTile` has been deprecated in favor of `onClick`. It will be removed in the next major release.' + ), + + /** + * Specify the function to run when the SelectableTile is interacted with via a keyboard + */ + handleKeyDown: deprecate( + PropTypes.func, + 'The `handleKeyDown` prop for `SelectableTile` has been deprecated in favor of `onKeyDown`. It will be removed in the next major release.' + ), + + /** + * The description of the checkmark icon. + */ + iconDescription: deprecate( + PropTypes.string, + 'The `iconDescription` prop for `SelectableTile` is no longer needed and has ' + + 'been deprecated. It will be removed in the next major release.' + ), + + /** + * The ID of the `<input>`. + */ + id: PropTypes.string, + + /** + * `true` to use the light version. For use on $ui-01 backgrounds only. + * Don't use this to make tile background color same as container background color. + */ + light: deprecate( + PropTypes.bool, + 'The `light` prop for `Tile` is no longer needed and has been deprecated. It will be removed in the next major release. Use the Layer component instead.' + ), + + /** + * The `name` of the `<input>`. + */ + name: PropTypes.string, + + /** + * The empty handler of the `<input>`. + */ + onChange: PropTypes.func, + + /** + * Specify the function to run when the SelectableTile is clicked + */ + onClick: PropTypes.func, + + /** + * Specify the function to run when the SelectableTile is interacted with via a keyboard + */ + onKeyDown: PropTypes.func, + + /** + * `true` to select this tile. + */ + selected: PropTypes.bool, + + /** + * Specify the tab index of the wrapper element + */ + tabIndex: PropTypes.number, + + /** + * The `title` of the `<input>`. + */ + title: PropTypes.string, + + /** + * The value of the `<input>`. + */ + value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, +}; + +export class ExpandableTile extends Component { + state = {}; + + static propTypes = { + /** + * The child nodes. + */ + children: PropTypes.node, + + /** + * The CSS class names. + */ + className: PropTypes.string, + + /** + * `true` if the tile is expanded. + */ + expanded: PropTypes.bool, + + /** + * Deprecated in v11. Use 'onClick' instead. + */ + handleClick: deprecate( + PropTypes.func, + 'The handleClick prop for ClickableTile has been deprecated in favor of onClick. It will be removed in the next major release.' + ), + + /** + * An ID that can be provided to aria-labelledby + */ + id: PropTypes.string, + + /** + * `true` to use the light version. For use on $ui-01 backgrounds only. + * Don't use this to make tile background color same as container background color. + */ + light: deprecate( + PropTypes.bool, + 'The `light` prop for `Tile` is no longer needed and has been deprecated. It will be removed in the next major release. Use the Layer component instead.' + ), + + /** + * optional handler to decide whether to ignore a click. returns false if click should be ignored + */ + onBeforeClick: PropTypes.func, + + /** + * Specify the function to run when the ExpandableTile is clicked + + */ + onClick: PropTypes.func, + + /** + * optional handler to trigger a function when a key is pressed + */ + onKeyUp: PropTypes.func, + + /** + * The `tabindex` attribute. + */ + tabIndex: PropTypes.number, + + /** + * The description of the "collapsed" icon that can be read by screen readers. + */ + tileCollapsedIconText: PropTypes.string, + + /** + * When "collapsed", a label to appear next to the chevron (e.g., "View more"). + */ + tileCollapsedLabel: PropTypes.string, + + /** + * The description of the "expanded" icon that can be read by screen readers. + */ + tileExpandedIconText: PropTypes.string, + + /** + * When "expanded", a label to appear next to the chevron (e.g., "View less"). + */ + tileExpandedLabel: PropTypes.string, + }; + + static defaultProps = { + tabIndex: 0, + expanded: false, + tileMaxHeight: 0, + tilePadding: 0, + onBeforeClick: () => true, + onClick: () => {}, + tileCollapsedIconText: 'Interact to expand Tile', + tileExpandedIconText: 'Interact to collapse Tile', + light: false, + }; + + static contextType = PrefixContext; + + static getDerivedStateFromProps( + // eslint-disable-next-line react/prop-types + { expanded, tileMaxHeight, tilePadding }, + state + ) { + const { + prevExpanded, + prevTileMaxHeight, + prevTilePadding, + expanded: currentExpanded, + tileMaxHeight: currentTileMaxHeight, + tilePadding: currentTilePadding, + } = state; + const expandedChanged = prevExpanded !== expanded; + const tileMaxHeightChanged = prevTileMaxHeight !== tileMaxHeight; + const tilePaddingChanged = prevTilePadding !== tilePadding; + return !expandedChanged && !tileMaxHeightChanged && !tilePaddingChanged + ? null + : { + expanded: !expandedChanged ? currentExpanded : expanded, + tileMaxHeight: !tileMaxHeightChanged + ? currentTileMaxHeight + : tileMaxHeight, + tilePadding: !tilePaddingChanged ? currentTilePadding : tilePadding, + prevExpanded: expanded, + prevTileMaxHeight: tileMaxHeight, + prevTilePadding: tilePadding, + }; + } + + componentDidMount = () => { + if (this.tile) { + const getStyle = window.getComputedStyle(this.tile, null); + + if (this.aboveTheFold) { + this.setState({ + tileMaxHeight: this.aboveTheFold.getBoundingClientRect().height, + tilePadding: + parseInt(getStyle.getPropertyValue('padding-top'), 10) + + parseInt(getStyle.getPropertyValue('padding-bottom'), 10), + }); + } + } + }; + + componentDidUpdate = (prevProps) => { + if (prevProps.expanded !== this.props.expanded) { + this.setMaxHeight(); + } + }; + + setMaxHeight = () => { + if (this.state.expanded ? this.tileContent : this.aboveTheFold) { + this.setState({ + tileMaxHeight: this.state.expanded + ? this.tileContent.getBoundingClientRect().height + : this.aboveTheFold.getBoundingClientRect().height, + }); + } + }; + + handleClick = (evt) => { + if (!this.props.onBeforeClick(evt) || evt.target.tagName === 'INPUT') { + return; + } + evt.persist(); + this.setState( + { + expanded: !this.state.expanded, + }, + () => { + this.setMaxHeight(); + // TODO: Remove handleClick prop when handleClick is deprecated + this.props.handleClick?.(evt) || this.props.onClick?.(evt); + } + ); + }; + + handleKeyUp = (evt) => { + if (evt.target !== this.tile) { + if (matches(evt, [keys.Enter, keys.Space])) { + evt.preventDefault(); + } + } + }; + + getChildren = () => { + return React.Children.toArray(this.props.children); + }; + + render() { + const { + tabIndex, + className, + expanded, // eslint-disable-line + tileMaxHeight, // eslint-disable-line + tilePadding, // eslint-disable-line + handleClick, // eslint-disable-line + onClick, + onKeyUp, + tileCollapsedIconText, + tileExpandedIconText, + tileCollapsedLabel, + tileExpandedLabel, + onBeforeClick, // eslint-disable-line + light, + ...rest + } = this.props; + + const prefix = this.context; + + const { expanded: isExpanded } = this.state; + + const classes = cx( + `${prefix}--tile`, + `${prefix}--tile--expandable`, + { + [`${prefix}--tile--is-expanded`]: isExpanded, + [`${prefix}--tile--light`]: light, + }, + className + ); + + const tileStyle = { + maxHeight: isExpanded + ? null + : this.state.tileMaxHeight + this.state.tilePadding, + }; + + const childrenAsArray = this.getChildren(); + + return ( + // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions + <button + type="button" + ref={(tile) => { + this.tile = tile; + }} + style={tileStyle} + className={classes} + aria-expanded={isExpanded} + title={isExpanded ? tileExpandedIconText : tileCollapsedIconText} + {...rest} + onKeyUp={composeEventHandlers([onKeyUp, this.handleKeyUp])} + onClick={composeEventHandlers([onClick, this.handleClick])} + tabIndex={tabIndex}> + <div + ref={(tileContent) => { + this.tileContent = tileContent; + }}> + <div + ref={(aboveTheFold) => { + this.aboveTheFold = aboveTheFold; + }} + className={`${prefix}--tile-content`}> + {childrenAsArray[0]} + </div> + <div className={`${prefix}--tile__chevron`}> + <span>{isExpanded ? tileExpandedLabel : tileCollapsedLabel}</span> + <ChevronDown16 /> + </div> + <div className={`${prefix}--tile-content`}>{childrenAsArray[1]}</div> + </div> + </button> + ); + } +} + +export const TileAboveTheFoldContent = React.forwardRef( + function TileAboveTheFoldContent({ children }, ref) { + const prefix = usePrefix(); + + return ( + <span ref={ref} className={`${prefix}--tile__above-the-fold`}> + {children} + </span> + ); + } +); + +TileAboveTheFoldContent.displayName = 'TileAboveTheFoldContent'; +TileAboveTheFoldContent.propTypes = { + /** + * The child nodes. + */ + children: PropTypes.node, +}; + +export const TileBelowTheFoldContent = React.forwardRef( + function TileBelowTheFoldContent({ children }, ref) { + const prefix = usePrefix(); + + return ( + <span ref={ref} className={`${prefix}--tile-content__below-the-fold`}> + {children} + </span> + ); + } +); + +TileBelowTheFoldContent.displayName = 'TileBelowTheFoldContent'; +TileBelowTheFoldContent.propTypes = { + /** + * The child nodes. + */ + children: PropTypes.node, +}; From 9f558cf7e0c8bcbbefe46b78c249f01530a70f73 Mon Sep 17 00:00:00 2001 From: Jan Hassel <jan.hassel@ibm.com> Date: Wed, 13 Oct 2021 21:32:36 +0200 Subject: [PATCH 16/35] fix(grid): make subgrid work with grid offset (#9803) * fix(grid): make subgrid work with grid offset * docs(grid): fix storybook styles prefix Co-authored-by: Taylor Jones <taylor.jones826@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../src/components/Grid/Grid.stories.scss | 24 +++++++++---------- packages/grid/scss/modules/_css-grid.scss | 12 ++-------- packages/react/src/components/Grid/Column.js | 6 +---- 3 files changed, 15 insertions(+), 27 deletions(-) diff --git a/packages/carbon-react/src/components/Grid/Grid.stories.scss b/packages/carbon-react/src/components/Grid/Grid.stories.scss index 734f3e73056e..6db1000777c2 100644 --- a/packages/carbon-react/src/components/Grid/Grid.stories.scss +++ b/packages/carbon-react/src/components/Grid/Grid.stories.scss @@ -2,54 +2,54 @@ @use '@carbon/styles/scss/type' as *; // Grid modes -.bx--css-grid { +.cds--css-grid { background-color: $blue-20; outline: 1px dashed $blue-40; } -.bx--css-grid p { +.cds--css-grid p { @include type-style('code-02'); } -.bx--css-grid p:first-of-type { +.cds--css-grid p:first-of-type { //messing up progress indicator stories margin-top: 0; } -.bx--css-grid.bx--css-grid--narrow { +.cds--css-grid.cds--css-grid--narrow { background-color: $teal-20; outline: 1px dashed $teal-40; } -.bx--css-grid.bx--css-grid--condensed { +.cds--css-grid.cds--css-grid--condensed { background-color: $purple-20; outline: 1px dashed $purple-40; } // Only use background for subgrid example, not other subgrids in "mixed modes" story or others -.bx--subgrid.example { +.cds--subgrid.example { background-color: $green-20; } // Columns -.bx--css-grid > [class*='col'], -.bx--subgrid > [class*='col'] { +.cds--css-grid > [class*='col'], +.cds--subgrid > [class*='col'] { min-height: 80px; } -.bx--css-grid > [class*='col'] { +.cds--css-grid > [class*='col'] { background: $blue-10; } -.bx--subgrid > [class*='col'] { +.cds--subgrid > [class*='col'] { background: $green-10; outline: 1px dashed $green-30; } -.bx--css-grid.bx--css-grid--narrow > [class*='col'] { +.cds--css-grid.cds--css-grid--narrow > [class*='col'] { background: $teal-10; } -.bx--css-grid.bx--css-grid--condensed > [class*='col'] { +.cds--css-grid.cds--css-grid--condensed > [class*='col'] { background: $purple-10; } diff --git a/packages/grid/scss/modules/_css-grid.scss b/packages/grid/scss/modules/_css-grid.scss index f0f39373567f..0362b2a8876c 100644 --- a/packages/grid/scss/modules/_css-grid.scss +++ b/packages/grid/scss/modules/_css-grid.scss @@ -254,10 +254,6 @@ .#{$prefix}--col-start-#{$i} { grid-column-start: $i; } - - .#{$prefix}--col-end-#{$i} { - grid-column-end: $i; - } } .#{$prefix}--col-start-auto { @@ -272,17 +268,13 @@ $columns: map.get($value, columns); @include breakpoint($name) { - // The `grid-column-end` and `grid-column-start` properties are *not* inclusive. - // It starts/ends the column *at* the column, not *on* the column. We must + // The `grid-column-start` property is *not* inclusive. + // It starts the column *at* the column, not *on* the column. We must // ensure that there is one additional class available for each breakpoint. @for $i from 1 through $columns + 1 { .#{$prefix}--#{$name}\:col-start-#{$i} { grid-column-start: $i; } - - .#{$prefix}--#{$name}\:col-end-#{$i} { - grid-column-end: $i; - } } .#{$prefix}--#{$name}\:col-start-auto { diff --git a/packages/react/src/components/Grid/Column.js b/packages/react/src/components/Grid/Column.js index 71dfb825bae3..bfba3b29dcb8 100644 --- a/packages/react/src/components/Grid/Column.js +++ b/packages/react/src/components/Grid/Column.js @@ -150,11 +150,7 @@ function getClassNameForBreakpoints(breakpoints, prefix) { } if (typeof span === 'number') { - if (typeof offset === 'number' && offset > 0) { - classNames.push(`${prefix}--${name}:col-end-${offset + span + 1}`); - } else { - classNames.push(`${prefix}--${name}:col-span-${span}`); - } + classNames.push(`${prefix}--${name}:col-span-${span}`); } if (span === true) { From 2fe7fbe6de38c1df19836dc68e6e044282b7d085 Mon Sep 17 00:00:00 2001 From: Kin Ueng <github@kinueng.com> Date: Thu, 14 Oct 2021 04:26:56 -0500 Subject: [PATCH 17/35] feat(MultiSelect): new hideLabel prop (#9840) * feat(MultiSelect): new hideLabel prop * feat(FilterableMultiSelect): new hideLabel prop - Add `hideLabel` prop to the filterable MultiSelect to make it consistant with the default MultiSelect. - Fix up `PublicAPI-test.js.snap` file using command `yarn test packages/react/__tests__/PublicAPI-test.js -u`. First the file was restored to commit 3e0231dd76b0b1f95082121f3072c82e9240ea99, then the `yarn test` was used to make changes to `PublicAPI-test.js.snap`. - Fix format issue (spaces) in MultiSelect.js Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../react/__tests__/__snapshots__/PublicAPI-test.js.snap | 9 +++++++++ .../src/components/MultiSelect/FilterableMultiSelect.js | 7 +++++++ .../src/components/MultiSelect/MultiSelect-story.js | 1 + packages/react/src/components/MultiSelect/MultiSelect.js | 7 +++++++ 4 files changed, 24 insertions(+) diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index 05d39d9412c2..6ac36a38f0a8 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -3246,6 +3246,9 @@ Map { ], "type": "shape", }, + "hideLabel": Object { + "type": "bool", + }, "id": Object { "isRequired": true, "type": "string", @@ -4209,6 +4212,9 @@ Map { ], "type": "shape", }, + "hideLabel": Object { + "type": "bool", + }, "id": Object { "isRequired": true, "type": "string", @@ -4453,6 +4459,9 @@ Map { ], "type": "shape", }, + "hideLabel": Object { + "type": "bool", + }, "id": Object { "isRequired": true, "type": "string", diff --git a/packages/react/src/components/MultiSelect/FilterableMultiSelect.js b/packages/react/src/components/MultiSelect/FilterableMultiSelect.js index cb24c8682785..8e5b11491691 100644 --- a/packages/react/src/components/MultiSelect/FilterableMultiSelect.js +++ b/packages/react/src/components/MultiSelect/FilterableMultiSelect.js @@ -51,6 +51,11 @@ export default class FilterableMultiSelect extends React.Component { */ downshiftProps: PropTypes.shape(Downshift.propTypes), + /** + * Specify whether the title text should be hidden or not + */ + hideLabel: PropTypes.bool, + /** * Specify a custom `id` */ @@ -299,6 +304,7 @@ export default class FilterableMultiSelect extends React.Component { itemToElement, itemToString, titleText, + hideLabel, helperText, type, initialSelectedItems, @@ -350,6 +356,7 @@ export default class FilterableMultiSelect extends React.Component { const titleClasses = cx({ [`${prefix}--label`]: true, [`${prefix}--label--disabled`]: disabled, + [`${prefix}--visually-hidden`]: hideLabel, }); const helperClasses = cx({ [`${prefix}--form__helper-text`]: true, diff --git a/packages/react/src/components/MultiSelect/MultiSelect-story.js b/packages/react/src/components/MultiSelect/MultiSelect-story.js index b83299725350..7b6189191402 100644 --- a/packages/react/src/components/MultiSelect/MultiSelect-story.js +++ b/packages/react/src/components/MultiSelect/MultiSelect-story.js @@ -71,6 +71,7 @@ const directions = { const props = () => ({ id: text('MultiSelect ID (id)', 'carbon-multiselect-example'), titleText: text('Title (titleText)', 'Multiselect title'), + hideLabel: boolean('No title text shown (hideLabel)', false), helperText: text('Helper text (helperText)', 'This is helper text'), disabled: boolean('Disabled (disabled)', false), light: boolean('Light variant (light)', false), diff --git a/packages/react/src/components/MultiSelect/MultiSelect.js b/packages/react/src/components/MultiSelect/MultiSelect.js index aa148aa2cb46..1f38ef456a2c 100644 --- a/packages/react/src/components/MultiSelect/MultiSelect.js +++ b/packages/react/src/components/MultiSelect/MultiSelect.js @@ -44,6 +44,7 @@ const MultiSelect = React.forwardRef(function MultiSelect( itemToElement, itemToString, titleText, + hideLabel, helperText, label, type, @@ -142,6 +143,7 @@ const MultiSelect = React.forwardRef(function MultiSelect( ); const titleClasses = cx(`${prefix}--label`, { [`${prefix}--label--disabled`]: disabled, + [`${prefix}--visually-hidden`]: hideLabel, }); const helperId = !helperText ? undefined @@ -349,6 +351,11 @@ MultiSelect.propTypes = { */ downshiftProps: PropTypes.shape(Downshift.propTypes), + /** + * Specify whether the title text should be hidden or not + */ + hideLabel: PropTypes.bool, + /** * Specify a custom `id` */ From 3c9fdbcc12116759c47605ad562aa4d3be78b9d5 Mon Sep 17 00:00:00 2001 From: Taylor Jones <tay1orjones@users.noreply.github.com> Date: Thu, 14 Oct 2021 11:28:12 -0500 Subject: [PATCH 18/35] chore(release): v10.46.0 (#9868) --- packages/carbon-react/package.json | 12 +++--- packages/components/package.json | 8 ++-- packages/elements/package.json | 8 ++-- packages/grid/package.json | 2 +- packages/icons-handlebars/package.json | 4 +- packages/icons-react/package.json | 4 +- packages/icons-vue/package.json | 4 +- packages/icons/package.json | 2 +- packages/react/package.json | 6 +-- packages/sketch/package.json | 6 +-- packages/styles/package.json | 6 +-- packages/themes/package.json | 2 +- yarn.lock | 58 +++++++++++++------------- 13 files changed, 61 insertions(+), 61 deletions(-) diff --git a/packages/carbon-react/package.json b/packages/carbon-react/package.json index e3a5dad823c3..06c0702f3ab5 100644 --- a/packages/carbon-react/package.json +++ b/packages/carbon-react/package.json @@ -1,7 +1,7 @@ { "name": "@carbon/react", "description": "React components for the Carbon Design System", - "version": "0.7.0-rc.0", + "version": "0.7.0", "license": "Apache-2.0", "main": "lib/index.js", "module": "es/index.js", @@ -43,11 +43,11 @@ }, "dependencies": { "@carbon/feature-flags": "^0.6.0", - "@carbon/icons-react": "^10.41.0-rc.0", - "@carbon/styles": "^0.7.0-rc.0", + "@carbon/icons-react": "^10.41.0", + "@carbon/styles": "^0.7.0", "@carbon/telemetry": "0.0.0-alpha.6", - "carbon-components": "^10.46.0-rc.0", - "carbon-components-react": "^7.46.0-rc.0", + "carbon-components": "^10.46.0", + "carbon-components-react": "^7.46.0", "carbon-icons": "^7.0.7" }, "devDependencies": { @@ -58,7 +58,7 @@ "@babel/plugin-transform-react-constant-elements": "^7.14.5", "@babel/preset-env": "^7.14.7", "@babel/preset-react": "^7.14.5", - "@carbon/themes": "^10.45.0-rc.0", + "@carbon/themes": "^10.45.0", "@rollup/plugin-babel": "^5.3.0", "@rollup/plugin-commonjs": "^18.0.0", "@rollup/plugin-node-resolve": "^11.2.1", diff --git a/packages/components/package.json b/packages/components/package.json index c087684ea15a..a1b34200eedb 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,7 +1,7 @@ { "name": "carbon-components", "description": "The Carbon Design System is IBM’s open-source design system for products and experiences.", - "version": "10.46.0-rc.0", + "version": "10.46.0", "license": "Apache-2.0", "main": "umd/index.js", "module": "es/index.js", @@ -81,9 +81,9 @@ "@babel/preset-react": "^7.14.5", "@babel/runtime": "^7.14.6", "@carbon/cli": "^10.30.0", - "@carbon/elements": "^10.45.0-rc.0", - "@carbon/icons-handlebars": "^10.41.0-rc.0", - "@carbon/icons-react": "^10.41.0-rc.0", + "@carbon/elements": "^10.45.0", + "@carbon/icons-handlebars": "^10.41.0", + "@carbon/icons-react": "^10.41.0", "@carbon/test-utils": "^10.19.0", "@frctl/fractal": "^1.1.0", "@rollup/plugin-babel": "^5.3.0", diff --git a/packages/elements/package.json b/packages/elements/package.json index 892de971d79b..538aabcda699 100644 --- a/packages/elements/package.json +++ b/packages/elements/package.json @@ -1,7 +1,7 @@ { "name": "@carbon/elements", "description": "A collection of design elements in code for the IBM Design Language", - "version": "10.45.0-rc.0", + "version": "10.45.0", "license": "Apache-2.0", "main": "lib/index.js", "module": "es/index.js", @@ -36,12 +36,12 @@ }, "dependencies": { "@carbon/colors": "^10.33.0", - "@carbon/grid": "^10.37.0", - "@carbon/icons": "^10.41.0-rc.0", + "@carbon/grid": "^10.38.0", + "@carbon/icons": "^10.41.0", "@carbon/import-once": "^10.6.0", "@carbon/layout": "^10.33.0", "@carbon/motion": "^10.25.0", - "@carbon/themes": "^10.45.0-rc.0", + "@carbon/themes": "^10.45.0", "@carbon/type": "^10.37.0" }, "devDependencies": { diff --git a/packages/grid/package.json b/packages/grid/package.json index 8f30a0d20deb..177cb8be0fe9 100644 --- a/packages/grid/package.json +++ b/packages/grid/package.json @@ -1,7 +1,7 @@ { "name": "@carbon/grid", "description": "Grid for digital and software products using the Carbon Design System", - "version": "10.37.0", + "version": "10.38.0", "license": "Apache-2.0", "repository": { "type": "git", diff --git a/packages/icons-handlebars/package.json b/packages/icons-handlebars/package.json index a96e7f77bbba..8367378b50c1 100644 --- a/packages/icons-handlebars/package.json +++ b/packages/icons-handlebars/package.json @@ -1,7 +1,7 @@ { "name": "@carbon/icons-handlebars", "description": "Handlebars helpers for IBM Design Language icons in digital and software products using the Carbon Design System", - "version": "10.41.0-rc.0", + "version": "10.41.0", "license": "Apache-2.0", "main": "index.js", "repository": { @@ -27,7 +27,7 @@ }, "dependencies": { "@carbon/icon-helpers": "^10.24.0", - "@carbon/icons": "^10.41.0-rc.0" + "@carbon/icons": "^10.41.0" }, "devDependencies": { "handlebars": "^4.0.12" diff --git a/packages/icons-react/package.json b/packages/icons-react/package.json index 306b3f218f67..905a566d11d1 100644 --- a/packages/icons-react/package.json +++ b/packages/icons-react/package.json @@ -1,7 +1,7 @@ { "name": "@carbon/icons-react", "description": "React components for icons in digital and software products using the Carbon Design System", - "version": "10.41.0-rc.0", + "version": "10.41.0", "license": "Apache-2.0", "main": "lib/index.js", "module": "es/index.js", @@ -44,7 +44,7 @@ }, "devDependencies": { "@carbon/icon-build-helpers": "^0.29.0", - "@carbon/icons": "^10.41.0-rc.0", + "@carbon/icons": "^10.41.0", "rimraf": "^3.0.2" }, "sideEffects": false diff --git a/packages/icons-vue/package.json b/packages/icons-vue/package.json index 478de5ccf0d3..e006fe9c40f0 100644 --- a/packages/icons-vue/package.json +++ b/packages/icons-vue/package.json @@ -1,7 +1,7 @@ { "name": "@carbon/icons-vue", "description": "Vue components for icons in digital and software products using the Carbon Design System", - "version": "10.41.0-rc.0", + "version": "10.41.0", "license": "Apache-2.0", "main": "lib/index.js", "module": "es/index.js", @@ -32,7 +32,7 @@ }, "devDependencies": { "@carbon/cli-reporter": "^10.5.0", - "@carbon/icons": "^10.41.0-rc.0", + "@carbon/icons": "^10.41.0", "fs-extra": "^8.1.0", "prettier": "^2.2.1", "rimraf": "^3.0.0", diff --git a/packages/icons/package.json b/packages/icons/package.json index 72613eb5f205..a898f4148496 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -1,7 +1,7 @@ { "name": "@carbon/icons", "description": "Icons for digital and software products using the Carbon Design System", - "version": "10.41.0-rc.0", + "version": "10.41.0", "license": "Apache-2.0", "main": "lib/index.js", "module": "es/index.js", diff --git a/packages/react/package.json b/packages/react/package.json index cd6a35def526..4bf686a4db43 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,7 +1,7 @@ { "name": "carbon-components-react", "description": "The Carbon Design System is IBM’s open-source design system for products and experiences.", - "version": "7.46.0-rc.0", + "version": "7.46.0", "license": "Apache-2.0", "main": "lib/index.js", "module": "es/index.js", @@ -47,7 +47,7 @@ }, "dependencies": { "@carbon/feature-flags": "^0.6.0", - "@carbon/icons-react": "^10.41.0-rc.0", + "@carbon/icons-react": "^10.41.0", "@carbon/telemetry": "0.0.0-alpha.6", "classnames": "2.3.1", "copy-to-clipboard": "^3.3.1", @@ -101,7 +101,7 @@ "babel-plugin-react-docgen": "^4.2.1", "babel-plugin-transform-inline-environment-variables": "^0.4.3", "browserslist-config-carbon": "^10.6.1", - "carbon-components": "^10.46.0-rc.0", + "carbon-components": "^10.46.0", "carbon-icons": "^7.0.5", "chalk": "^4.1.1", "cli-table": "^0.3.0", diff --git a/packages/sketch/package.json b/packages/sketch/package.json index 39d8f789b696..93a245e37185 100644 --- a/packages/sketch/package.json +++ b/packages/sketch/package.json @@ -2,7 +2,7 @@ "name": "@carbon/sketch", "private": true, "description": "Tooling for generating a sketch plugin to bring code to design", - "version": "10.44.0-rc.0", + "version": "10.44.0", "license": "Apache-2.0", "repository": { "type": "git", @@ -30,8 +30,8 @@ "dependencies": { "@carbon/colors": "^10.33.0", "@carbon/icon-helpers": "^10.24.0", - "@carbon/icons": "^10.41.0-rc.0", - "@carbon/themes": "^10.45.0-rc.0", + "@carbon/icons": "^10.41.0", + "@carbon/themes": "^10.45.0", "@carbon/type": "^10.37.0", "@skpm/builder": "^0.7.0", "color-string": "^1.5.3", diff --git a/packages/styles/package.json b/packages/styles/package.json index 8d7da05ce069..5a2680ac0589 100644 --- a/packages/styles/package.json +++ b/packages/styles/package.json @@ -1,7 +1,7 @@ { "name": "@carbon/styles", "description": "Styles for the Carbon Design System", - "version": "0.7.0-rc.0", + "version": "0.7.0", "license": "Apache-2.0", "repository": { "type": "git", @@ -22,10 +22,10 @@ "dependencies": { "@carbon/colors": "^10.33.0", "@carbon/feature-flags": "^0.6.0", - "@carbon/grid": "^10.37.0", + "@carbon/grid": "^10.38.0", "@carbon/layout": "^10.33.0", "@carbon/motion": "^10.25.0", - "@carbon/themes": "^10.45.0-rc.0", + "@carbon/themes": "^10.45.0", "@carbon/type": "^10.37.0", "@ibm/plex": "6.0.0-next.6" }, diff --git a/packages/themes/package.json b/packages/themes/package.json index 22400fd0409c..fe4f3f8d8a3b 100644 --- a/packages/themes/package.json +++ b/packages/themes/package.json @@ -1,7 +1,7 @@ { "name": "@carbon/themes", "description": "Themes for applying color in the Carbon Design System", - "version": "10.45.0-rc.0", + "version": "10.45.0", "license": "Apache-2.0", "main": "lib/index.js", "module": "es/index.js", diff --git a/yarn.lock b/yarn.lock index 006c57e1667b..552b3fee685f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1768,18 +1768,18 @@ __metadata: languageName: unknown linkType: soft -"@carbon/elements@^10.45.0-rc.0, @carbon/elements@workspace:packages/elements": +"@carbon/elements@^10.45.0, @carbon/elements@workspace:packages/elements": version: 0.0.0-use.local resolution: "@carbon/elements@workspace:packages/elements" dependencies: "@carbon/cli": ^10.30.0 "@carbon/colors": ^10.33.0 - "@carbon/grid": ^10.37.0 - "@carbon/icons": ^10.41.0-rc.0 + "@carbon/grid": ^10.38.0 + "@carbon/icons": ^10.41.0 "@carbon/import-once": ^10.6.0 "@carbon/layout": ^10.33.0 "@carbon/motion": ^10.25.0 - "@carbon/themes": ^10.45.0-rc.0 + "@carbon/themes": ^10.45.0 "@carbon/type": ^10.37.0 fs-extra: ^8.1.0 klaw-sync: ^6.0.0 @@ -1809,7 +1809,7 @@ __metadata: languageName: unknown linkType: soft -"@carbon/grid@^10.37.0, @carbon/grid@workspace:packages/grid": +"@carbon/grid@^10.38.0, @carbon/grid@workspace:packages/grid": version: 0.0.0-use.local resolution: "@carbon/grid@workspace:packages/grid" dependencies: @@ -1870,25 +1870,25 @@ __metadata: languageName: node linkType: hard -"@carbon/icons-handlebars@^10.41.0-rc.0, @carbon/icons-handlebars@workspace:packages/icons-handlebars": +"@carbon/icons-handlebars@^10.41.0, @carbon/icons-handlebars@workspace:packages/icons-handlebars": version: 0.0.0-use.local resolution: "@carbon/icons-handlebars@workspace:packages/icons-handlebars" dependencies: "@carbon/icon-helpers": ^10.24.0 - "@carbon/icons": ^10.41.0-rc.0 + "@carbon/icons": ^10.41.0 handlebars: ^4.0.12 peerDependencies: handlebars: ^4.0.12 languageName: unknown linkType: soft -"@carbon/icons-react@^10.41.0-rc.0, @carbon/icons-react@workspace:packages/icons-react": +"@carbon/icons-react@^10.41.0, @carbon/icons-react@workspace:packages/icons-react": version: 0.0.0-use.local resolution: "@carbon/icons-react@workspace:packages/icons-react" dependencies: "@carbon/icon-build-helpers": ^0.29.0 "@carbon/icon-helpers": ^10.24.0 - "@carbon/icons": ^10.41.0-rc.0 + "@carbon/icons": ^10.41.0 "@carbon/telemetry": 0.0.0-alpha.6 prop-types: ^15.7.2 rimraf: ^3.0.2 @@ -1913,7 +1913,7 @@ __metadata: dependencies: "@carbon/cli-reporter": ^10.5.0 "@carbon/icon-helpers": ^10.24.0 - "@carbon/icons": ^10.41.0-rc.0 + "@carbon/icons": ^10.41.0 fs-extra: ^8.1.0 prettier: ^2.2.1 rimraf: ^3.0.0 @@ -1922,7 +1922,7 @@ __metadata: languageName: unknown linkType: soft -"@carbon/icons@^10.41.0-rc.0, @carbon/icons@workspace:packages/icons": +"@carbon/icons@^10.41.0, @carbon/icons@workspace:packages/icons": version: 0.0.0-use.local resolution: "@carbon/icons@workspace:packages/icons" dependencies: @@ -1996,10 +1996,10 @@ __metadata: "@babel/preset-env": ^7.14.7 "@babel/preset-react": ^7.14.5 "@carbon/feature-flags": ^0.6.0 - "@carbon/icons-react": ^10.41.0-rc.0 - "@carbon/styles": ^0.7.0-rc.0 + "@carbon/icons-react": ^10.41.0 + "@carbon/styles": ^0.7.0 "@carbon/telemetry": 0.0.0-alpha.6 - "@carbon/themes": ^10.45.0-rc.0 + "@carbon/themes": ^10.45.0 "@rollup/plugin-babel": ^5.3.0 "@rollup/plugin-commonjs": ^18.0.0 "@rollup/plugin-node-resolve": ^11.2.1 @@ -2013,8 +2013,8 @@ __metadata: babel-plugin-dev-expression: ^0.2.2 babel-preset-carbon: ^0.1.0 browserslist-config-carbon: ^10.6.1 - carbon-components: ^10.46.0-rc.0 - carbon-components-react: ^7.46.0-rc.0 + carbon-components: ^10.46.0 + carbon-components-react: ^7.46.0 carbon-icons: ^7.0.7 css-loader: ^5.2.4 fs-extra: ^10.0.0 @@ -2054,8 +2054,8 @@ __metadata: dependencies: "@carbon/colors": ^10.33.0 "@carbon/icon-helpers": ^10.24.0 - "@carbon/icons": ^10.41.0-rc.0 - "@carbon/themes": ^10.45.0-rc.0 + "@carbon/icons": ^10.41.0 + "@carbon/themes": ^10.45.0 "@carbon/type": ^10.37.0 "@skpm/builder": ^0.7.0 color-string: ^1.5.3 @@ -2067,17 +2067,17 @@ __metadata: languageName: unknown linkType: soft -"@carbon/styles@^0.7.0-rc.0, @carbon/styles@workspace:packages/styles": +"@carbon/styles@^0.7.0, @carbon/styles@workspace:packages/styles": version: 0.0.0-use.local resolution: "@carbon/styles@workspace:packages/styles" dependencies: "@carbon/colors": ^10.33.0 "@carbon/feature-flags": ^0.6.0 - "@carbon/grid": ^10.37.0 + "@carbon/grid": ^10.38.0 "@carbon/layout": ^10.33.0 "@carbon/motion": ^10.25.0 "@carbon/test-utils": ^10.19.0 - "@carbon/themes": ^10.45.0-rc.0 + "@carbon/themes": ^10.45.0 "@carbon/type": ^10.37.0 "@ibm/plex": 6.0.0-next.6 css: ^3.0.0 @@ -2121,7 +2121,7 @@ __metadata: languageName: unknown linkType: soft -"@carbon/themes@^10.45.0-rc.0, @carbon/themes@workspace:packages/themes": +"@carbon/themes@^10.45.0, @carbon/themes@workspace:packages/themes": version: 0.0.0-use.local resolution: "@carbon/themes@workspace:packages/themes" dependencies: @@ -10293,7 +10293,7 @@ __metadata: languageName: node linkType: hard -"carbon-components-react@^7.46.0-rc.0, carbon-components-react@workspace:packages/react": +"carbon-components-react@^7.46.0, carbon-components-react@workspace:packages/react": version: 0.0.0-use.local resolution: "carbon-components-react@workspace:packages/react" dependencies: @@ -10309,7 +10309,7 @@ __metadata: "@babel/preset-env": ^7.14.7 "@babel/preset-react": ^7.14.5 "@carbon/feature-flags": ^0.6.0 - "@carbon/icons-react": ^10.41.0-rc.0 + "@carbon/icons-react": ^10.41.0 "@carbon/telemetry": 0.0.0-alpha.6 "@carbon/test-utils": ^10.19.0 "@cypress/react": ^5.4.0 @@ -10336,7 +10336,7 @@ __metadata: babel-plugin-react-docgen: ^4.2.1 babel-plugin-transform-inline-environment-variables: ^0.4.3 browserslist-config-carbon: ^10.6.1 - carbon-components: ^10.46.0-rc.0 + carbon-components: ^10.46.0 carbon-icons: ^7.0.5 chalk: ^4.1.1 classnames: 2.3.1 @@ -10420,7 +10420,7 @@ __metadata: languageName: node linkType: hard -"carbon-components@^10.46.0-rc.0, carbon-components@workspace:packages/components": +"carbon-components@^10.46.0, carbon-components@workspace:packages/components": version: 0.0.0-use.local resolution: "carbon-components@workspace:packages/components" dependencies: @@ -10433,9 +10433,9 @@ __metadata: "@babel/preset-react": ^7.14.5 "@babel/runtime": ^7.14.6 "@carbon/cli": ^10.30.0 - "@carbon/elements": ^10.45.0-rc.0 - "@carbon/icons-handlebars": ^10.41.0-rc.0 - "@carbon/icons-react": ^10.41.0-rc.0 + "@carbon/elements": ^10.45.0 + "@carbon/icons-handlebars": ^10.41.0 + "@carbon/icons-react": ^10.41.0 "@carbon/telemetry": 0.0.0-alpha.6 "@carbon/test-utils": ^10.19.0 "@frctl/fractal": ^1.1.0 From 1af03df10490fe3820f6c7632fc9a938f1ac5f74 Mon Sep 17 00:00:00 2001 From: Kevin Perrine <kperrine@gmail.com> Date: Thu, 14 Oct 2021 18:26:30 -0400 Subject: [PATCH 19/35] fix(repo): add check around math.div usage (#9850) Co-authored-by: Abbey Hart <abbeyhrt@gmail.com> --- .../src/globals/scss/_typography.import.scss | 13 +++- packages/grid/scss/_mixins.import.scss | 61 ++++++++++++------- packages/grid/scss/modules/_css-grid.scss | 7 ++- packages/grid/scss/modules/_mixins.scss | 17 +++++- packages/layout/scss/_convert.import.scss | 13 +++- packages/layout/scss/_key-height.import.scss | 7 ++- packages/layout/scss/modules/_convert.scss | 13 +++- packages/styles/scss/utilities/_convert.scss | 17 ++++-- packages/type/scss/_styles.import.scss | 7 ++- 9 files changed, 116 insertions(+), 39 deletions(-) diff --git a/packages/components/src/globals/scss/_typography.import.scss b/packages/components/src/globals/scss/_typography.import.scss index be16159322c2..31529608aa37 100644 --- a/packages/components/src/globals/scss/_typography.import.scss +++ b/packages/components/src/globals/scss/_typography.import.scss @@ -19,6 +19,7 @@ // compatibility file to ensure we continue to support node-sass and dart-sass // in v10. +@use 'sass:meta'; @use 'sass:math'; @import 'vars'; /* stylelint-disable-line no-invalid-position-at-import-rule */ @@ -42,7 +43,11 @@ $base-font-size: 16px !default; @warn "Expected argument $px to be of type `px`, instead received: `#{unit($px)}`"; } - @return math.div($px, $base-font-size) * 1rem; + @if meta.function-exists('div', 'math') { + @return math.div($px, $base-font-size) * 1rem; + } @else { + @return ($px / $base-font-size) * 1rem; + } } /// Convert px to em @@ -58,7 +63,11 @@ $base-font-size: 16px !default; @warn "Expected argument $px to be of type `px`, instead received: `#{unit($px)}`"; } - @return math.div($px, $base-font-size) * 1em; + @if meta.function-exists('div', 'math') { + @return math.div($px, $base-font-size) * 1em; + } @else { + @return ($px / $base-font-size) * 1em; + } } // 🔬 Experimental diff --git a/packages/grid/scss/_mixins.import.scss b/packages/grid/scss/_mixins.import.scss index 798b69268159..e799c31da54f 100644 --- a/packages/grid/scss/_mixins.import.scss +++ b/packages/grid/scss/_mixins.import.scss @@ -23,6 +23,7 @@ // and often derived from, bootstrap: // https://github.com/twbs/bootstrap/blob/v4-dev/scss/mixins/_grid.scss +@use 'sass:meta'; @use 'sass:math'; @import '@carbon/layout/scss/breakpoint'; /* stylelint-disable-line no-invalid-position-at-import-rule */ @import 'prefix'; /* stylelint-disable-line no-invalid-position-at-import-rule */ @@ -46,21 +47,21 @@ // always setting `width: 100%;`. This works because we use `flex` values // later on to override this initial width. width: 100%; - padding-right: math.div($gutter, 2); - padding-left: math.div($gutter, 2); + padding-right: $gutter * 0.5; + padding-left: $gutter * 0.5; // For our condensed use-case, our gutters collapse to 2px solid, 1px on each // side. .#{$prefix}--row--condensed &, .#{$prefix}--grid--condensed & { - padding-right: math.div($condensed-gutter, 2); - padding-left: math.div($condensed-gutter, 2); + padding-right: $condensed-gutter * 0.5; + padding-left: $condensed-gutter * 0.5; } // For our narrow use-case, our container hangs 16px into the gutter .#{$prefix}--row--narrow &, .#{$prefix}--grid--narrow & { - padding-right: math.div($gutter, 2); + padding-right: $gutter * 0.5; padding-left: 0; } } @@ -80,8 +81,13 @@ // Add a `max-width` to ensure content within each column does not blow out // the width of the column. Applies to IE10+ and Firefox. Chrome and Safari // do not appear to require this. - max-width: percentage(math.div($span, $columns)); - flex: 0 0 percentage(math.div($span, $columns)); + @if meta.function-exists('div', 'math') { + max-width: percentage(math.div($span, $columns)); + flex: 0 0 percentage(math.div($span, $columns)); + } @else { + max-width: percentage(($span / $columns)); + flex: 0 0 percentage(($span / $columns)); + } } } @@ -91,7 +97,12 @@ /// @access private /// @group @carbon/grid @mixin carbon--make-col-offset($span, $columns) { - $offset: math.div($span, $columns); + $offset: 0; + @if meta.function-exists('div', 'math') { + $offset: math.div($span, $columns); + } @else { + $offset: ($span / $columns); + } @if $offset == 0 { margin-left: 0; } @else { @@ -173,8 +184,8 @@ @mixin carbon--make-row($gutter: $carbon--grid-gutter) { display: flex; flex-wrap: wrap; - margin-right: -1 * math.div($gutter, 2); - margin-left: -1 * math.div($gutter, 2); + margin-right: -1 * $gutter * 0.5; + margin-left: -1 * $gutter * 0.5; } // ----------------------------------------------------------------------------- @@ -225,20 +236,20 @@ /// @group @carbon/grid @mixin carbon--hang($gutter: $carbon--grid-gutter) { .#{$prefix}--hang--start { - padding-left: math.div($gutter, 2); + padding-left: $gutter * 0.5; } .#{$prefix}--hang--end { - padding-right: math.div($gutter, 2); + padding-right: $gutter * 0.5; } // Deprecated ☠️ .#{$prefix}--hang--left { - padding-left: math.div($gutter, 2); + padding-left: $gutter * 0.5; } .#{$prefix}--hang--right { - padding-right: math.div($gutter, 2); + padding-right: $gutter * 0.5; } } @@ -299,7 +310,11 @@ $carbon--aspect-ratios: ( $height: nth($aspect-ratio, 2); .#{$prefix}--aspect-ratio--#{$width}x#{$height}::before { - padding-top: percentage(math.div($height, $width)); + @if meta.function-exists('div', 'math') { + padding-top: percentage(math.div($height, $width)); + } @else { + padding-top: percentage(($height / $width)); + } } } @@ -336,14 +351,14 @@ $carbon--aspect-ratios: ( $prev-margin: map-get($prev-breakpoint, margin); @if $prev-margin != $margin { @include carbon--breakpoint($name) { - padding-right: #{math.div($carbon--grid-gutter, 2) + $margin}; - padding-left: #{math.div($carbon--grid-gutter, 2) + $margin}; + padding-right: #{($carbon--grid-gutter * 0.5) + $margin}; + padding-left: #{($carbon--grid-gutter * 0.5) + $margin}; } } } @else { @include carbon--breakpoint($name) { - padding-right: #{math.div($carbon--grid-gutter, 2) + $margin}; - padding-left: #{math.div($carbon--grid-gutter, 2) + $margin}; + padding-right: #{($carbon--grid-gutter * 0.5) + $margin}; + padding-left: #{($carbon--grid-gutter * 0.5) + $margin}; } } } @@ -400,13 +415,13 @@ $carbon--aspect-ratios: ( .#{$prefix}--row-padding [class*='#{$prefix}--col'], .#{$prefix}--col-padding { - padding-top: math.div($grid-gutter, 2); - padding-bottom: math.div($grid-gutter, 2); + padding-top: $grid-gutter * 0.5; + padding-bottom: $grid-gutter * 0.5; } .#{$prefix}--grid--condensed [class*='#{$prefix}--col'] { - padding-top: math.div($condensed-gutter, 2); - padding-bottom: math.div($condensed-gutter, 2); + padding-top: $condensed-gutter * 0.5; + padding-bottom: $condensed-gutter * 0.5; } @include carbon--make-grid-columns($breakpoints, $grid-gutter); diff --git a/packages/grid/scss/modules/_css-grid.scss b/packages/grid/scss/modules/_css-grid.scss index 0362b2a8876c..e5e09efe10e2 100644 --- a/packages/grid/scss/modules/_css-grid.scss +++ b/packages/grid/scss/modules/_css-grid.scss @@ -5,6 +5,7 @@ // LICENSE file in the root directory of this source tree. // +@use 'sass:meta'; @use "sass:math"; @use 'sass:map'; @@ -405,7 +406,11 @@ $carbon--aspect-ratios: ( $height: nth($aspect-ratio, 2); .#{$prefix}--aspect-ratio--#{$width}x#{$height}::before { - padding-top: percentage(math.div($height, $width)); + @if meta.function-exists('div', 'math') { + padding-top: percentage(math.div($height, $width)); + } @else { + padding-top: percentage(($height / $width)); + } } } } diff --git a/packages/grid/scss/modules/_mixins.scss b/packages/grid/scss/modules/_mixins.scss index 4561626a0cd3..08706d68a3ad 100644 --- a/packages/grid/scss/modules/_mixins.scss +++ b/packages/grid/scss/modules/_mixins.scss @@ -5,6 +5,7 @@ // LICENSE file in the root directory of this source tree. // +@use 'sass:meta'; @use "sass:math"; @use 'config' as *; @@ -63,8 +64,13 @@ // Add a `max-width` to ensure content within each column does not blow out // the width of the column. Applies to IE10+ and Firefox. Chrome and Safari // do not appear to require this. - max-width: percentage(math.div($span, $columns)); - flex: 0 0 percentage(math.div($span, $columns)); + @if meta.function-exists('div', 'math') { + max-width: percentage(math.div($span, $columns)); + flex: 0 0 percentage(math.div($span, $columns)); + } @else { + max-width: percentage(($span / $columns)); + flex: 0 0 percentage(($span / $columns)); + } } } @@ -74,7 +80,12 @@ /// @access private /// @group @carbon/grid @mixin -make-col-offset($span, $columns) { - $offset: math.div($span, $columns); + $offset: 0; + @if meta.function-exists('div', 'math') { + $offset: math.div($span, $columns); + } @else { + $offset: ($span / $columns); + } @if $offset == 0 { margin-left: 0; } @else { diff --git a/packages/layout/scss/_convert.import.scss b/packages/layout/scss/_convert.import.scss index 19517d19fbe0..f8cab364b5f3 100644 --- a/packages/layout/scss/_convert.import.scss +++ b/packages/layout/scss/_convert.import.scss @@ -19,6 +19,7 @@ // compatibility file to ensure we continue to support node-sass and dart-sass // in v10. +@use 'sass:meta'; @use 'sass:math'; /// Default font size @@ -38,7 +39,11 @@ $carbon--base-font-size: 16px !default; @warn "Expected argument $px to be of type `px`, instead received: `#{unit($px)}`"; } - @return math.div($px, $carbon--base-font-size) * 1rem; + @if meta.function-exists('div', 'math') { + @return math.div($px, $carbon--base-font-size) * 1rem; + } @else { + @return ($px / $carbon--base-font-size) * 1rem; + } } /// Convert a given px unit to a em unit @@ -52,5 +57,9 @@ $carbon--base-font-size: 16px !default; @warn "Expected argument $px to be of type `px`, instead received: `#{unit($px)}`"; } - @return math.div($px, $carbon--base-font-size) * 1em; + @if meta.function-exists('div', 'math') { + @return math.div($px, $carbon--base-font-size) * 1em; + } @else { + @return ($px / $carbon--base-font-size) * 1em; + } } diff --git a/packages/layout/scss/_key-height.import.scss b/packages/layout/scss/_key-height.import.scss index 0ebab92a256d..15e9f7090f33 100644 --- a/packages/layout/scss/_key-height.import.scss +++ b/packages/layout/scss/_key-height.import.scss @@ -19,6 +19,7 @@ // compatibility file to ensure we continue to support node-sass and dart-sass // in v10. +@use 'sass:meta'; @use "sass:math"; @import 'breakpoint'; /* stylelint-disable-line no-invalid-position-at-import-rule */ @import 'utilities'; /* stylelint-disable-line no-invalid-position-at-import-rule */ @@ -39,7 +40,11 @@ $margin: map-get($values, margin); $columns: map-get($values, columns); - @return math.div($width - (2 * $margin), $columns); + @if meta.function-exists('div', 'math') { + @return math.div($width - (2 * $margin), $columns); + } @else { + @return (($width - (2 * $margin)) / $columns); + } } @else { @warn 'Breakpoint: `#{$breakpoint}` is not a valid breakpoint.'; } diff --git a/packages/layout/scss/modules/_convert.scss b/packages/layout/scss/modules/_convert.scss index c159d9e03984..3b28c4f09127 100644 --- a/packages/layout/scss/modules/_convert.scss +++ b/packages/layout/scss/modules/_convert.scss @@ -5,6 +5,7 @@ // LICENSE file in the root directory of this source tree. // +@use 'sass:meta'; @use 'sass:math'; /// Default font size @@ -24,7 +25,11 @@ $base-font-size: 16px !default; @warn "Expected argument $px to be of type `px`, instead received: `#{unit($px)}`"; } - @return math.div($px, $base-font-size) * 1rem; + @if meta.function-exists('div', 'math') { + @return math.div($px, $base-font-size) * 1rem; + } @else { + @return ($px / $base-font-size) * 1rem; + } } /// Convert a given px unit to a em unit @@ -38,5 +43,9 @@ $base-font-size: 16px !default; @warn "Expected argument $px to be of type `px`, instead received: `#{unit($px)}`"; } - @return math.div($px, $base-font-size) * 1em; + @if meta.function-exists('div', 'math') { + @return math.div($px, $base-font-size) * 1em; + } @else { + @return ($px / $base-font-size) * 1em; + } } diff --git a/packages/styles/scss/utilities/_convert.scss b/packages/styles/scss/utilities/_convert.scss index e20bf087305f..58fb831d1777 100644 --- a/packages/styles/scss/utilities/_convert.scss +++ b/packages/styles/scss/utilities/_convert.scss @@ -5,11 +5,12 @@ // LICENSE file in the root directory of this source tree. // +@use 'sass:meta'; +@use "sass:math"; + /// Default font size /// @type Number /// @access public -@use "sass:math"; - $base-font-size: 16px !default; /// Convert a given px unit to a rem unit @@ -23,7 +24,11 @@ $base-font-size: 16px !default; @warn "Expected argument $px to be of type `px`, instead received: `#{unit($px)}`"; } - @return math.div($px, $base-font-size) * 1rem; + @if meta.function-exists('div', 'math') { + @return math.div($px, $base-font-size) * 1rem; + } @else { + @return ($px / $base-font-size) * 1rem; + } } /// Convert a given px unit to a em unit @@ -37,5 +42,9 @@ $base-font-size: 16px !default; @warn "Expected argument $px to be of type `px`, instead received: `#{unit($px)}`"; } - @return math.div($px, $base-font-size) * 1em; + @if meta.function-exists('div', 'math') { + @return math.div($px, $base-font-size) * 1em; + } @else { + @return ($px / $base-font-size) * 1em; + } } diff --git a/packages/type/scss/_styles.import.scss b/packages/type/scss/_styles.import.scss index 360053250589..51b105afd082 100644 --- a/packages/type/scss/_styles.import.scss +++ b/packages/type/scss/_styles.import.scss @@ -19,6 +19,7 @@ // compatibility file to ensure we continue to support node-sass and dart-sass // in v10. +@use "sass:meta"; @use "sass:math"; @import '@carbon/layout/scss/breakpoint'; /* stylelint-disable-line no-invalid-position-at-import-rule */ @import 'font-family'; /* stylelint-disable-line no-invalid-position-at-import-rule */ @@ -582,7 +583,11 @@ $tokens: ( /// @access public /// @group @carbon/type @function strip-unit($value) { - @return math.div($value, $value * 0 + 1); + @if meta.function-exists('div', 'math') { + @return math.div($value, $value * 0 + 1); + } @else { + @return $value / ($value * 0 + 1); + } } /// This helper includes fluid type styles for the given token value. Fluid type From 021df4c09cd475aa4d6e808eac4a8368a595f2a5 Mon Sep 17 00:00:00 2001 From: "Andrea N. Cardona" <andreancardona@gmail.com> Date: Sun, 17 Oct 2021 19:46:36 -0500 Subject: [PATCH 20/35] fix(progress-indicator): fix active state (#9740) * feat(ContentSwitcher): preliminary unstable refactor * fix(progress-indicator): fix active state * whoops * Delete UnstableContentSwitcher.js * Delete index.js * Delete styles.scss * fix(progress-indicator): fix active state * fix(progress-indicator): fix active state -test * fix(progress-indicator): token fix * fix(reset): commit Co-authored-by: Andrea Cardona <andrea.cardonaibm.com@andreas-macbook-pro.home> --- .../components/progress-indicator/_progress-indicator.scss | 7 ++++--- .../components/progress-indicator/_progress-indicator.scss | 6 ++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/components/src/components/progress-indicator/_progress-indicator.scss b/packages/components/src/components/progress-indicator/_progress-indicator.scss index c991dd835802..8564c19342db 100644 --- a/packages/components/src/components/progress-indicator/_progress-indicator.scss +++ b/packages/components/src/components/progress-indicator/_progress-indicator.scss @@ -102,9 +102,10 @@ margin-right: 0.75rem; } - .#{$prefix}--tooltip__label.#{$prefix}--progress-label:active { - box-shadow: 0 rem(3px) 0 0 $interactive-01; - color: $interactive-01; + .#{$prefix}--progress-step-button:not(.#{$prefix}--progress-step-button--unclickable) + .#{$prefix}--progress-label:active { + box-shadow: 0 rem(3px) 0 0 $interactive; + color: $interactive; } //OVERFLOW STYLING diff --git a/packages/styles/scss/components/progress-indicator/_progress-indicator.scss b/packages/styles/scss/components/progress-indicator/_progress-indicator.scss index 0c406b22f91e..4923b8e452af 100644 --- a/packages/styles/scss/components/progress-indicator/_progress-indicator.scss +++ b/packages/styles/scss/components/progress-indicator/_progress-indicator.scss @@ -225,6 +225,12 @@ $progress-indicator-bar-width: 1px inset transparent !default; cursor: pointer; } + .#{$prefix}--progress-step-button:not(.#{$prefix}--progress-step-button--unclickable) + .#{$prefix}--progress-label:active { + box-shadow: 0 rem(3px) 0 0 $interactive; + color: $interactive; + } + //DISABLED STYLING .#{$prefix}--progress-step--disabled { cursor: not-allowed; From b677f5425222c345f439007348a6583591854682 Mon Sep 17 00:00:00 2001 From: Alessandra Davila <aledavila@ibm.com> Date: Mon, 18 Oct 2021 09:30:59 -0500 Subject: [PATCH 21/35] feat(carbon-react): add layer stories (#9861) --- .../CodeSnippet/CodeSnippet.stories.js | 148 ++++++++++++++++++ .../components/ComboBox/ComboBox.stories.js | 37 +++++ .../ContentSwitcher.stories.js | 27 ++++ .../DatePicker/DatePicker.stories.js | 112 +++++++++++++ .../components/Dropdown/Dropdown.stories.js | 67 ++++++++ .../MultiSelect/MultiSelect.stories.js | 77 +++++++++ .../NumberInput/NumberInput.stories.js | 15 ++ .../Overflow/OverflowMenu.stories.js | 33 ++++ .../src/components/Search/Search.stories.js | 74 +++++++++ .../src/components/Slider/Slider.stories.js | 87 ++++++++++ .../src/components/Tabs/Tabs.stories.js | 75 +++++++++ 11 files changed, 752 insertions(+) diff --git a/packages/carbon-react/src/components/CodeSnippet/CodeSnippet.stories.js b/packages/carbon-react/src/components/CodeSnippet/CodeSnippet.stories.js index 864b1f06ac02..8b6a05b3f7ae 100644 --- a/packages/carbon-react/src/components/CodeSnippet/CodeSnippet.stories.js +++ b/packages/carbon-react/src/components/CodeSnippet/CodeSnippet.stories.js @@ -7,6 +7,7 @@ import React from 'react'; import { CodeSnippet, CodeSnippetSkeleton } from 'carbon-components-react'; +import { Layer } from '../Layer'; export default { title: 'Components/CodeSnippet', @@ -60,6 +61,153 @@ export const singleline = () => ( </CodeSnippet> ); +export const inlineWithLayer = () => { + return ( + <> + <CodeSnippet type="inline" feedback="Copied to clipboard"> + {'node -v'} + </CodeSnippet> + <Layer> + <CodeSnippet type="inline" feedback="Copied to clipboard"> + {'node -v'} + </CodeSnippet> + <Layer> + <CodeSnippet type="inline" feedback="Copied to clipboard"> + {'node -v'} + </CodeSnippet> + </Layer> + </Layer> + </> + ); +}; + +export const multilineWithLayer = () => { + return ( + <> + <CodeSnippet type="multi" feedback="Copied to clipboard"> + {` "scripts": { + "build": "lerna run build --stream --prefix --npm-client yarn", + "ci-check": "carbon-cli ci-check", + "clean": "lerna run clean && lerna clean --yes && rimraf node_modules", + "doctoc": "doctoc --title '## Table of Contents'", + "format": "prettier --write '**/*.{js,md,scss,ts}' '!**/{build,es,lib,storybook,ts,umd}/**'", + "format:diff": "prettier --list-different '**/*.{js,md,scss,ts}' '!**/{build,es,lib,storybook,ts,umd}/**' '!packages/components/**'", + "lint": "eslint actions config codemods packages", + "lint:styles": "stylelint '**/*.{css,scss}' --report-needless-disables --report-invalid-scope-disables", + "sync": "carbon-cli sync", + "test": "cross-env BABEL_ENV=test jest", + "test:e2e": "cross-env BABEL_ENV=test jest --testPathPattern=e2e --testPathIgnorePatterns='examples,/packages/components/,/packages/react/'" + }, + "resolutions": { + "react": "~16.9.0", + "react-dom": "~16.9.0", + "react-is": "~16.9.0", + "react-test-renderer": "~16.9.0" + }, + "devDependencies": { + "@babel/core": "^7.10.0", + "@babel/plugin-proposal-class-properties": "^7.7.4", + "@babel/plugin-proposal-export-default-from": "^7.7.4", + "@babel/plugin-proposal-export-namespace-from": "^7.7.4", + "@babel/plugin-transform-runtime": "^7.10.0", + "@babel/preset-env": "^7.10.0", + "@babel/preset-react": "^7.10.0", + "@babel/runtime": "^7.10.0", + "@commitlint/cli": "^8.3.5",`} + </CodeSnippet> + <Layer> + <CodeSnippet type="multi" feedback="Copied to clipboard"> + {` "scripts": { + "build": "lerna run build --stream --prefix --npm-client yarn", + "ci-check": "carbon-cli ci-check", + "clean": "lerna run clean && lerna clean --yes && rimraf node_modules", + "doctoc": "doctoc --title '## Table of Contents'", + "format": "prettier --write '**/*.{js,md,scss,ts}' '!**/{build,es,lib,storybook,ts,umd}/**'", + "format:diff": "prettier --list-different '**/*.{js,md,scss,ts}' '!**/{build,es,lib,storybook,ts,umd}/**' '!packages/components/**'", + "lint": "eslint actions config codemods packages", + "lint:styles": "stylelint '**/*.{css,scss}' --report-needless-disables --report-invalid-scope-disables", + "sync": "carbon-cli sync", + "test": "cross-env BABEL_ENV=test jest", + "test:e2e": "cross-env BABEL_ENV=test jest --testPathPattern=e2e --testPathIgnorePatterns='examples,/packages/components/,/packages/react/'" + }, + "resolutions": { + "react": "~16.9.0", + "react-dom": "~16.9.0", + "react-is": "~16.9.0", + "react-test-renderer": "~16.9.0" + }, + "devDependencies": { + "@babel/core": "^7.10.0", + "@babel/plugin-proposal-class-properties": "^7.7.4", + "@babel/plugin-proposal-export-default-from": "^7.7.4", + "@babel/plugin-proposal-export-namespace-from": "^7.7.4", + "@babel/plugin-transform-runtime": "^7.10.0", + "@babel/preset-env": "^7.10.0", + "@babel/preset-react": "^7.10.0", + "@babel/runtime": "^7.10.0", + "@commitlint/cli": "^8.3.5",`} + </CodeSnippet> + <Layer> + <CodeSnippet type="multi" feedback="Copied to clipboard"> + {` "scripts": { + "build": "lerna run build --stream --prefix --npm-client yarn", + "ci-check": "carbon-cli ci-check", + "clean": "lerna run clean && lerna clean --yes && rimraf node_modules", + "doctoc": "doctoc --title '## Table of Contents'", + "format": "prettier --write '**/*.{js,md,scss,ts}' '!**/{build,es,lib,storybook,ts,umd}/**'", + "format:diff": "prettier --list-different '**/*.{js,md,scss,ts}' '!**/{build,es,lib,storybook,ts,umd}/**' '!packages/components/**'", + "lint": "eslint actions config codemods packages", + "lint:styles": "stylelint '**/*.{css,scss}' --report-needless-disables --report-invalid-scope-disables", + "sync": "carbon-cli sync", + "test": "cross-env BABEL_ENV=test jest", + "test:e2e": "cross-env BABEL_ENV=test jest --testPathPattern=e2e --testPathIgnorePatterns='examples,/packages/components/,/packages/react/'" + }, + "resolutions": { + "react": "~16.9.0", + "react-dom": "~16.9.0", + "react-is": "~16.9.0", + "react-test-renderer": "~16.9.0" + }, + "devDependencies": { + "@babel/core": "^7.10.0", + "@babel/plugin-proposal-class-properties": "^7.7.4", + "@babel/plugin-proposal-export-default-from": "^7.7.4", + "@babel/plugin-proposal-export-namespace-from": "^7.7.4", + "@babel/plugin-transform-runtime": "^7.10.0", + "@babel/preset-env": "^7.10.0", + "@babel/preset-react": "^7.10.0", + "@babel/runtime": "^7.10.0", + "@commitlint/cli": "^8.3.5",`} + </CodeSnippet> + </Layer> + </Layer> + </> + ); +}; + +export const singlelineWithLayer = () => { + return ( + <> + <CodeSnippet type="single" feedback="Copied to clipboard"> + yarn add carbon-components@latest carbon-components-react@latest + @carbon/icons-react@latest carbon-icons@latest + </CodeSnippet> + <Layer> + <CodeSnippet type="single" feedback="Copied to clipboard"> + yarn add carbon-components@latest carbon-components-react@latest + @carbon/icons-react@latest carbon-icons@latest + </CodeSnippet> + <Layer> + <CodeSnippet type="single" feedback="Copied to clipboard"> + yarn add carbon-components@latest carbon-components-react@latest + @carbon/icons-react@latest carbon-icons@latest + </CodeSnippet> + </Layer> + </Layer> + </> + ); +}; + export const skeleton = () => ( <div> <CodeSnippetSkeleton type="single" style={{ marginBottom: 8 }} /> diff --git a/packages/carbon-react/src/components/ComboBox/ComboBox.stories.js b/packages/carbon-react/src/components/ComboBox/ComboBox.stories.js index 0b997e2db9d7..5203768c6986 100644 --- a/packages/carbon-react/src/components/ComboBox/ComboBox.stories.js +++ b/packages/carbon-react/src/components/ComboBox/ComboBox.stories.js @@ -7,6 +7,7 @@ import React from 'react'; import { ComboBox } from 'carbon-components-react'; +import { Layer } from '../Layer'; const items = [ { @@ -54,3 +55,39 @@ export const Combobox = () => ( /> </div> ); + +export const withLayer = () => ( + <div style={{ width: 300 }}> + <ComboBox + onChange={() => {}} + id="carbon-combobox" + items={items} + itemToString={(item) => (item ? item.text : '')} + placeholder="Filter..." + titleText="First Layer" + helperText="Combobox helper text" + /> + <Layer> + <ComboBox + onChange={() => {}} + id="carbon-combobox" + items={items} + itemToString={(item) => (item ? item.text : '')} + placeholder="Filter..." + titleText="Second Layer" + helperText="Combobox helper text" + /> + <Layer> + <ComboBox + onChange={() => {}} + id="carbon-combobox" + items={items} + itemToString={(item) => (item ? item.text : '')} + placeholder="Filter..." + titleText="Third Layer" + helperText="Combobox helper text" + /> + </Layer> + </Layer> + </div> +); diff --git a/packages/carbon-react/src/components/ContentSwitcher/ContentSwitcher.stories.js b/packages/carbon-react/src/components/ContentSwitcher/ContentSwitcher.stories.js index efdeef12bb1b..82daf616a49a 100644 --- a/packages/carbon-react/src/components/ContentSwitcher/ContentSwitcher.stories.js +++ b/packages/carbon-react/src/components/ContentSwitcher/ContentSwitcher.stories.js @@ -7,6 +7,7 @@ import React from 'react'; import { ContentSwitcher, Switch } from 'carbon-components-react'; +import { Layer } from '../Layer'; export default { title: 'Components/ContentSwitcher', @@ -27,3 +28,29 @@ export const Default = () => ( <Switch name="three" text="Third section" /> </ContentSwitcher> ); + +export const withLayer = () => { + return ( + <> + <ContentSwitcher onChange={() => {}}> + <Switch name="one" text="First section" /> + <Switch name="two" text="Second section" /> + <Switch name="three" text="Third section" /> + </ContentSwitcher> + <Layer> + <ContentSwitcher onChange={() => {}}> + <Switch name="one" text="First section" /> + <Switch name="two" text="Second section" /> + <Switch name="three" text="Third section" /> + </ContentSwitcher> + <Layer> + <ContentSwitcher onChange={() => {}}> + <Switch name="one" text="First section" /> + <Switch name="two" text="Second section" /> + <Switch name="three" text="Third section" /> + </ContentSwitcher> + </Layer> + </Layer> + </> + ); +}; diff --git a/packages/carbon-react/src/components/DatePicker/DatePicker.stories.js b/packages/carbon-react/src/components/DatePicker/DatePicker.stories.js index c82738966093..bfb80349c536 100644 --- a/packages/carbon-react/src/components/DatePicker/DatePicker.stories.js +++ b/packages/carbon-react/src/components/DatePicker/DatePicker.stories.js @@ -12,6 +12,7 @@ import { DatePickerInput, DatePickerSkeleton, } from 'carbon-components-react'; +import { Layer } from '../Layer'; // const patterns = { // 'Short (d{1,2}/d{4})': '\\d{1,2}/\\d{4}', @@ -108,6 +109,117 @@ export const RangeWithCalendar = () => { ); }; +export const SimpleWithLayer = () => { + return ( + <> + <DatePicker datePickerType="simple"> + <DatePickerInput + placeholder="mm/dd/yyyy" + labelText="Date Picker label" + id="date-picker-simple" + /> + </DatePicker> + <Layer> + <DatePicker datePickerType="simple"> + <DatePickerInput + placeholder="mm/dd/yyyy" + labelText="Date Picker label" + id="date-picker-simple" + /> + </DatePicker> + <Layer> + <DatePicker datePickerType="simple"> + <DatePickerInput + placeholder="mm/dd/yyyy" + labelText="Date Picker label" + id="date-picker-simple" + /> + </DatePicker> + </Layer> + </Layer> + </> + ); +}; + +export const SingleWithCalendarWithLayer = () => { + return ( + <> + <DatePicker datePickerType="single"> + <DatePickerInput + placeholder="mm/dd/yyyy" + labelText="Date Picker label" + id="date-picker-single" + /> + </DatePicker> + <Layer> + <DatePicker datePickerType="single"> + <DatePickerInput + placeholder="mm/dd/yyyy" + labelText="Date Picker label" + id="date-picker-single" + /> + </DatePicker> + <Layer> + <DatePicker datePickerType="single"> + <DatePickerInput + placeholder="mm/dd/yyyy" + labelText="Date Picker label" + id="date-picker-single" + /> + </DatePicker> + </Layer> + </Layer> + </> + ); +}; + +export const RangeWithCalendarWithLayer = () => { + return ( + <> + <DatePicker datePickerType="range"> + <DatePickerInput + id="date-picker-input-id-start" + placeholder="mm/dd/yyyy" + labelText="Start date" + /> + <DatePickerInput + id="date-picker-input-id-finish" + placeholder="mm/dd/yyyy" + labelText="End date" + /> + </DatePicker> + <Layer> + <DatePicker datePickerType="range"> + <DatePickerInput + id="date-picker-input-id-start" + placeholder="mm/dd/yyyy" + labelText="Start date" + /> + <DatePickerInput + id="date-picker-input-id-finish" + placeholder="mm/dd/yyyy" + labelText="End date" + /> + </DatePicker> + <Layer> + <DatePicker datePickerType="range"> + <DatePickerInput + id="date-picker-input-id-start" + placeholder="mm/dd/yyyy" + labelText="Start date" + /> + <DatePickerInput + id="date-picker-input-id-finish" + placeholder="mm/dd/yyyy" + labelText="End date" + /> + </DatePicker> + </Layer> + </Layer> + </> + ); +}; + /* eslint-disable react/prop-types */ export const DatePickerPlayground = () => ( <DatePicker {...props.datePicker()}> diff --git a/packages/carbon-react/src/components/Dropdown/Dropdown.stories.js b/packages/carbon-react/src/components/Dropdown/Dropdown.stories.js index 06fb5251c320..92ae3ab55f0d 100644 --- a/packages/carbon-react/src/components/Dropdown/Dropdown.stories.js +++ b/packages/carbon-react/src/components/Dropdown/Dropdown.stories.js @@ -7,6 +7,7 @@ import React from 'react'; import { Dropdown, DropdownSkeleton } from 'carbon-components-react'; +import { Layer } from '../Layer'; const items = [ { @@ -73,6 +74,72 @@ export const Inline = () => ( </div> ); +export const withLayer = () => ( + <div style={{ width: 400 }}> + <Dropdown + id="default" + titleText="First Layer" + helperText="This is some helper text" + label="Dropdown menu options" + items={items} + itemToString={(item) => (item ? item.text : '')} + /> + <Layer> + <Dropdown + id="default" + titleText="Second Layer" + helperText="This is some helper text" + label="Dropdown menu options" + items={items} + itemToString={(item) => (item ? item.text : '')} + /> + <Layer> + <Dropdown + id="default" + titleText="Third Layer" + helperText="This is some helper text" + label="Dropdown menu options" + items={items} + itemToString={(item) => (item ? item.text : '')} + /> + </Layer> + </Layer> + </div> +); + +export const InlineWithLayer = () => ( + <div style={{ width: 600 }}> + <Dropdown + id="inline" + titleText="First Layer" + label="Dropdown menu options" + type="inline" + items={items} + itemToString={(item) => (item ? item.text : '')} + /> + <Layer> + <Dropdown + id="inline" + titleText="Second Layer" + label="Dropdown menu options" + type="inline" + items={items} + itemToString={(item) => (item ? item.text : '')} + /> + <Layer> + <Dropdown + id="inline" + titleText="Third Layer" + label="Dropdown menu options" + type="inline" + items={items} + itemToString={(item) => (item ? item.text : '')} + /> + </Layer> + </Layer> + </div> +); + export const Skeleton = () => ( <div style={{ width: 300 }}> <DropdownSkeleton /> diff --git a/packages/carbon-react/src/components/MultiSelect/MultiSelect.stories.js b/packages/carbon-react/src/components/MultiSelect/MultiSelect.stories.js index 70b0afc23cb2..ee8df2d982fd 100644 --- a/packages/carbon-react/src/components/MultiSelect/MultiSelect.stories.js +++ b/packages/carbon-react/src/components/MultiSelect/MultiSelect.stories.js @@ -7,6 +7,7 @@ import React from 'react'; import { MultiSelect } from 'carbon-components-react'; +import { Layer } from '../Layer'; const items = [ { @@ -94,3 +95,79 @@ export const _Filterable = () => { </div> ); }; + +export const withLayer = () => { + return ( + <div style={{ width: 300 }}> + <MultiSelect + label="First Layer" + id="carbon-multiselect-example" + titleText="Multiselect title" + helperText="This is helper text" + items={items} + itemToString={(item) => (item ? item.text : '')} + selectionFeedback="top-after-reopen" + /> + <Layer> + <MultiSelect + label="Second Layer" + id="carbon-multiselect-example" + titleText="Multiselect title" + helperText="This is helper text" + items={items} + itemToString={(item) => (item ? item.text : '')} + selectionFeedback="top-after-reopen" + /> + <Layer> + <MultiSelect + label="Third Layer" + id="carbon-multiselect-example" + titleText="Multiselect title" + helperText="This is helper text" + items={items} + itemToString={(item) => (item ? item.text : '')} + selectionFeedback="top-after-reopen" + /> + </Layer> + </Layer> + </div> + ); +}; + +export const _FilterableWithLayer = () => { + return ( + <div style={{ width: 300 }}> + <MultiSelect.Filterable + id="carbon-multiselect-example-3" + titleText="First Layer" + helperText="This is helper text" + items={items} + itemToString={(item) => (item ? item.text : '')} + placeholder="Filter" + selectionFeedback="top-after-reopen" + /> + <Layer> + <MultiSelect.Filterable + id="carbon-multiselect-example-3" + titleText="Second Layer" + helperText="This is helper text" + items={items} + itemToString={(item) => (item ? item.text : '')} + placeholder="Filter" + selectionFeedback="top-after-reopen" + /> + <Layer> + <MultiSelect.Filterable + id="carbon-multiselect-example-3" + titleText="Third Layer" + helperText="This is helper text" + items={items} + itemToString={(item) => (item ? item.text : '')} + placeholder="Filter" + selectionFeedback="top-after-reopen" + /> + </Layer> + </Layer> + </div> + ); +}; diff --git a/packages/carbon-react/src/components/NumberInput/NumberInput.stories.js b/packages/carbon-react/src/components/NumberInput/NumberInput.stories.js index b403c8622861..8109f350e78a 100644 --- a/packages/carbon-react/src/components/NumberInput/NumberInput.stories.js +++ b/packages/carbon-react/src/components/NumberInput/NumberInput.stories.js @@ -7,6 +7,7 @@ import React from 'react'; import { NumberInput, NumberInputSkeleton } from 'carbon-components-react'; +import { Layer } from '../Layer'; export default { title: 'Components/NumberInput', @@ -33,6 +34,20 @@ export const Default = () => { return <NumberInput {...numberInputProps} />; }; +export const withLayer = () => { + return ( + <> + <NumberInput {...numberInputProps} /> + <Layer> + <NumberInput {...numberInputProps} /> + <Layer> + <NumberInput {...numberInputProps} /> + </Layer> + </Layer> + </> + ); +}; + export const Skeleton = () => ( <div> <NumberInputSkeleton /> diff --git a/packages/carbon-react/src/components/Overflow/OverflowMenu.stories.js b/packages/carbon-react/src/components/Overflow/OverflowMenu.stories.js index 53d22796348d..b0b46cbf9538 100644 --- a/packages/carbon-react/src/components/Overflow/OverflowMenu.stories.js +++ b/packages/carbon-react/src/components/Overflow/OverflowMenu.stories.js @@ -7,6 +7,7 @@ import { OverflowMenu, OverflowMenuItem } from 'carbon-components-react'; import React from 'react'; +import { Layer } from '../Layer'; export default { title: 'Components/OverflowMenu', @@ -23,3 +24,35 @@ export const Default = () => { </OverflowMenu> ); }; + +export const withLayer = () => { + return ( + <> + <OverflowMenu> + <OverflowMenuItem itemText="Stop app" /> + <OverflowMenuItem itemText="Restart app" /> + <OverflowMenuItem itemText="Rename app" /> + <OverflowMenuItem itemText="Edit routes and access" requireTitle /> + <OverflowMenuItem hasDivider isDelete itemText="Delete app" /> + </OverflowMenu> + <Layer> + <OverflowMenu> + <OverflowMenuItem itemText="Stop app" /> + <OverflowMenuItem itemText="Restart app" /> + <OverflowMenuItem itemText="Rename app" /> + <OverflowMenuItem itemText="Edit routes and access" requireTitle /> + <OverflowMenuItem hasDivider isDelete itemText="Delete app" /> + </OverflowMenu> + <Layer> + <OverflowMenu> + <OverflowMenuItem itemText="Stop app" /> + <OverflowMenuItem itemText="Restart app" /> + <OverflowMenuItem itemText="Rename app" /> + <OverflowMenuItem itemText="Edit routes and access" requireTitle /> + <OverflowMenuItem hasDivider isDelete itemText="Delete app" /> + </OverflowMenu> + </Layer> + </Layer> + </> + ); +}; diff --git a/packages/carbon-react/src/components/Search/Search.stories.js b/packages/carbon-react/src/components/Search/Search.stories.js index aca667e6aa2e..a99ab03d57d0 100644 --- a/packages/carbon-react/src/components/Search/Search.stories.js +++ b/packages/carbon-react/src/components/Search/Search.stories.js @@ -7,6 +7,7 @@ import { Search, ExpandableSearch } from 'carbon-components-react'; import React from 'react'; +import { Layer } from '../Layer'; export default { title: 'Components/Search' }; @@ -32,3 +33,76 @@ export const Expandable = () => ( onKeyDown={() => {}} /> ); + +export const withLayer = () => { + return ( + <> + <Search + size="lg" + defaultValue="First Layer" + labelText="Search" + closeButtonLabelText="Clear search input" + id="search-1" + onChange={() => {}} + onKeyDown={() => {}} + /> + <Layer> + <Search + size="lg" + defaultValue="Second Layer" + labelText="Search" + closeButtonLabelText="Clear search input" + id="search-1" + onChange={() => {}} + onKeyDown={() => {}} + /> + <Layer> + <Search + size="lg" + defaultValue="Third Layer" + labelText="Search" + closeButtonLabelText="Clear search input" + id="search-1" + onChange={() => {}} + onKeyDown={() => {}} + /> + </Layer> + </Layer> + </> + ); +}; + +export const ExpandableWithLayer = () => { + return ( + <> + <ExpandableSearch + size="lg" + labelText="First Layer" + closeButtonLabelText="Clear search input" + id="search-expandable-1" + onChange={() => {}} + onKeyDown={() => {}} + /> + <Layer> + <ExpandableSearch + size="lg" + labelText="Second Layer" + closeButtonLabelText="Clear search input" + id="search-expandable-1" + onChange={() => {}} + onKeyDown={() => {}} + /> + <Layer> + <ExpandableSearch + size="lg" + labelText="Third Layer" + closeButtonLabelText="Clear search input" + id="search-expandable-1" + onChange={() => {}} + onKeyDown={() => {}} + /> + </Layer> + </Layer> + </> + ); +}; diff --git a/packages/carbon-react/src/components/Slider/Slider.stories.js b/packages/carbon-react/src/components/Slider/Slider.stories.js index b968c3d39bc5..802a63d55843 100644 --- a/packages/carbon-react/src/components/Slider/Slider.stories.js +++ b/packages/carbon-react/src/components/Slider/Slider.stories.js @@ -11,6 +11,7 @@ import React, { useState } from 'react'; // import { withKnobs, boolean, number, text } from '@storybook/addon-knobs'; import { Slider, SliderSkeleton } from '.'; // import { sliderValuePropSync } from '../../../../react/src/internal/FeatureFlags'; +import { Layer } from '../Layer'; import mdx from './Slider.mdx'; export default { @@ -63,4 +64,90 @@ export const ControlledSlider = () => { ); }; +export const withLayer = () => { + return ( + <> + <Slider + labelText="First Layer" + value={50} + min={0} + max={100} + step={1} + stepMultiplier={10} + novalidate + /> + <Layer> + <Slider + labelText="Second Layer" + value={50} + min={0} + max={100} + step={1} + stepMultiplier={10} + novalidate + /> + <Layer> + <Slider + labelText="Third Layer" + value={50} + min={0} + max={100} + step={1} + stepMultiplier={10} + novalidate + /> + </Layer> + </Layer> + </> + ); +}; + +export const ControlledSliderWithLayer = () => { + const [val, setVal] = useState(87); + return ( + <> + <button + type="button" + onClick={() => setVal(Math.round(Math.random() * 100))}> + randomize value + </button> + <Slider + max={100} + min={0} + value={val} + onChange={({ value }) => setVal(value)} + /> + <h1>{val}</h1> + <Layer> + <button + type="button" + onClick={() => setVal(Math.round(Math.random() * 100))}> + randomize value + </button> + <Slider + max={100} + min={0} + value={val} + onChange={({ value }) => setVal(value)} + /> + <h1>{val}</h1> + <Layer> + <button + type="button" + onClick={() => setVal(Math.round(Math.random() * 100))}> + randomize value + </button> + <Slider + max={100} + min={0} + value={val} + onChange={({ value }) => setVal(value)} + /> + <h1>{val}</h1> + </Layer> + </Layer> + </> + ); +}; + export const Skeleton = () => <SliderSkeleton />; diff --git a/packages/carbon-react/src/components/Tabs/Tabs.stories.js b/packages/carbon-react/src/components/Tabs/Tabs.stories.js index 08482fdb9108..1c04f224b089 100644 --- a/packages/carbon-react/src/components/Tabs/Tabs.stories.js +++ b/packages/carbon-react/src/components/Tabs/Tabs.stories.js @@ -7,6 +7,7 @@ import React from 'react'; import { Button, Tab, Tabs, TabsSkeleton } from '../Tabs'; +import { Layer } from '../Layer'; export default { title: 'Components/Tabs', @@ -42,3 +43,77 @@ export const Default = () => ( </Tab> </Tabs> ); + +export const withLayer = () => { + return ( + <> + <Tabs> + <Tab id="tab-1" label="Tab label 1"> + <p>First Layer. Content for first tab goes here.</p> + </Tab> + <Tab id="tab-2" label="Tab label 2"> + <p>Content for second tab goes here.</p> + <Button>With a button</Button> + </Tab> + <Tab id="tab-3" label="Tab label 3" disabled> + <p>Content for third tab goes here.</p> + </Tab> + <Tab + id="tab-4" + label="Tab label 4 shows truncation" + title="Tab label 4 shows truncation"> + <p>Content for fourth tab goes here.</p> + </Tab> + <Tab label={<div>Custom Label</div>}> + <p>Content for fifth tab goes here.</p> + </Tab> + </Tabs> + <Layer> + <Tabs> + <Tab id="tab-1" label="Tab label 1"> + <p>Second Layer. Content for first tab goes here.</p> + </Tab> + <Tab id="tab-2" label="Tab label 2"> + <p>Content for second tab goes here.</p> + <Button>With a button</Button> + </Tab> + <Tab id="tab-3" label="Tab label 3" disabled> + <p>Content for third tab goes here.</p> + </Tab> + <Tab + id="tab-4" + label="Tab label 4 shows truncation" + title="Tab label 4 shows truncation"> + <p>Content for fourth tab goes here.</p> + </Tab> + <Tab label={<div>Custom Label</div>}> + <p>Content for fifth tab goes here.</p> + </Tab> + </Tabs> + <Layer> + <Tabs> + <Tab id="tab-1" label="Tab label 1"> + <p>Third Layer. Content for first tab goes here.</p> + </Tab> + <Tab id="tab-2" label="Tab label 2"> + <p>Content for second tab goes here.</p> + <Button>With a button</Button> + </Tab> + <Tab id="tab-3" label="Tab label 3" disabled> + <p>Content for third tab goes here.</p> + </Tab> + <Tab + id="tab-4" + label="Tab label 4 shows truncation" + title="Tab label 4 shows truncation"> + <p>Content for fourth tab goes here.</p> + </Tab> + <Tab label={<div>Custom Label</div>}> + <p>Content for fifth tab goes here.</p> + </Tab> + </Tabs> + </Layer> + </Layer> + </> + ); +}; From 6941df6b9d6007131e47c53d52fef427d4f98bfc Mon Sep 17 00:00:00 2001 From: Darsh Shah <imdarshshah@gmail.com> Date: Mon, 18 Oct 2021 21:38:47 +0530 Subject: [PATCH 22/35] chore: remove husky scripts from package.json (#9881) Co-authored-by: Abbey Hart <abbeyhrt@gmail.com> --- package.json | 6 ------ 1 file changed, 6 deletions(-) diff --git a/package.json b/package.json index ee927a03ef52..2b3c358a6563 100644 --- a/package.json +++ b/package.json @@ -71,12 +71,6 @@ "rimraf": "^3.0.0", "stylelint": "^13.13.1" }, - "husky": { - "hooks": { - "commit-msg": "commitlint -e $HUSKY_GIT_PARAMS", - "pre-commit": "lint-staged" - } - }, "commitlint": { "extends": [ "@commitlint/config-conventional" From 3d06011c150ebe33a1914d828ea567eee09f37e0 Mon Sep 17 00:00:00 2001 From: Josefina Mancilla <32556167+jnm2377@users.noreply.github.com> Date: Mon, 18 Oct 2021 12:16:09 -0500 Subject: [PATCH 23/35] fix(screenshot): make textarea (#9887) --- .github/ISSUE_TEMPLATE/DESIGN_DEFECT.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/DESIGN_DEFECT.yaml b/.github/ISSUE_TEMPLATE/DESIGN_DEFECT.yaml index 804f5e773cef..a4065d5d4723 100644 --- a/.github/ISSUE_TEMPLATE/DESIGN_DEFECT.yaml +++ b/.github/ISSUE_TEMPLATE/DESIGN_DEFECT.yaml @@ -62,7 +62,7 @@ body: placeholder: What did you see? What did you expect to see? validations: required: true - - type: input + - type: textarea id: example-url attributes: label: Screenshots From 4165cc4b1c9146ecdd173d2dfbe421f62aeb4a04 Mon Sep 17 00:00:00 2001 From: Taylor Jones <tay1orjones@users.noreply.github.com> Date: Mon, 18 Oct 2021 14:50:46 -0500 Subject: [PATCH 24/35] fix(tooltip): prevent escape keydown from bubbling (#9875) * fix(tooltip): prevent escape keydown from bubbling * Update packages/react/src/components/Tooltip/Tooltip.js Co-authored-by: Scott Strubberg <sstrubberg@protonmail.com> * chore: remove story used for testing Co-authored-by: Scott Strubberg <sstrubberg@protonmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../src/components/Tooltip/Tooltip-test.js | 29 ++++++++++++++++--- .../react/src/components/Tooltip/Tooltip.js | 8 +++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/packages/react/src/components/Tooltip/Tooltip-test.js b/packages/react/src/components/Tooltip/Tooltip-test.js index 08d2fab9615b..72ddbc00e9a9 100644 --- a/packages/react/src/components/Tooltip/Tooltip-test.js +++ b/packages/react/src/components/Tooltip/Tooltip-test.js @@ -6,22 +6,26 @@ */ import React, { Component } from 'react'; -import debounce from 'lodash.debounce'; +import debounce from 'lodash.debounce'; // eslint-disable-line no-unused-vars import FloatingMenu from '../../internal/FloatingMenu'; import Tooltip from '../Tooltip'; import { mount } from 'enzyme'; +import { screen, render } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import { Information16 as Information, Add16 as Add, OverflowMenuVertical16, } from '@carbon/icons-react'; import { settings } from 'carbon-components'; +import '@testing-library/jest-dom'; const { prefix } = settings; -jest.mock('lodash.debounce'); - -debounce.mockImplementation((fn) => fn); +jest.mock('lodash.debounce', () => (fn) => { + fn.cancel = jest.fn(); + return fn; +}); describe('Tooltip', () => { // An icon component class @@ -191,4 +195,21 @@ describe('Tooltip', () => { expect(rootWrapper.find('Tooltip').instance().state.open).toEqual(false); }); }); + + it('escape key keyDown should not bubble outside the tooltip', () => { + const onKeyDown = jest.fn(); + render( + <> + {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */} + <div onKeyDown={onKeyDown}> + <Tooltip triggerText="Tooltip" /> + </div> + </> + ); + + userEvent.click(screen.getAllByRole('button')[0]); + userEvent.keyboard('{esc}'); + + expect(onKeyDown).not.toHaveBeenCalled(); + }); }); diff --git a/packages/react/src/components/Tooltip/Tooltip.js b/packages/react/src/components/Tooltip/Tooltip.js index 0ec8ba2924d5..27dc2d65613f 100644 --- a/packages/react/src/components/Tooltip/Tooltip.js +++ b/packages/react/src/components/Tooltip/Tooltip.js @@ -703,8 +703,16 @@ class Tooltip extends Component { this._tooltipEl = node; }} updateOrientation={this.updateOrientation}> + {/* This rule is disabled because the onKeyDown event handler is only + * being used to capture and prevent the event from bubbling: */} + {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */} <div className={tooltipClasses} + onKeyDown={(event) => { + if (keyDownMatch(event, [keys.Escape])) { + event.stopPropagation(); + } + }} {...other} id={this._tooltipId} data-floating-menu-direction={storedDirection} From b5487bc40aaeefefcd0a88ef8bcbe71d44a35b0e Mon Sep 17 00:00:00 2001 From: Josh Black <josh@josh.black> Date: Tue, 19 Oct 2021 09:46:26 -0500 Subject: [PATCH 25/35] feat(styles): add default-type export to _type.scss entrypoint (#9891) --- packages/styles/scss/__tests__/type-test.js | 4 ++++ packages/styles/scss/_type.scss | 1 + 2 files changed, 5 insertions(+) diff --git a/packages/styles/scss/__tests__/type-test.js b/packages/styles/scss/__tests__/type-test.js index 7aad4e33663f..033f99697816 100644 --- a/packages/styles/scss/__tests__/type-test.js +++ b/packages/styles/scss/__tests__/type-test.js @@ -25,6 +25,8 @@ describe('@carbon/styles/scss/type', () => { mixins: ( reset: meta.mixin-exists('reset', 'type'), type-style: meta.mixin-exists('type-style', 'type'), + font-family: meta.mixin-exists('font-family', 'type'), + default-type: meta.mixin-exists('default-type', 'type'), ), )); `); @@ -33,6 +35,8 @@ describe('@carbon/styles/scss/type', () => { expect(api.mixins).toEqual({ reset: true, 'type-style': true, + 'font-family': true, + 'default-type': true, }); expect(api.variables).toMatchInlineSnapshot(` Array [ diff --git a/packages/styles/scss/_type.scss b/packages/styles/scss/_type.scss index cd76bbf2811a..4e4245a28e65 100644 --- a/packages/styles/scss/_type.scss +++ b/packages/styles/scss/_type.scss @@ -11,6 +11,7 @@ reset, type-style, font-family, + default-type, // Variables $caption-01, From ac2c448e9c0905c6f4113ffaf37863b43093d2c6 Mon Sep 17 00:00:00 2001 From: Josh Black <josh@josh.black> Date: Tue, 19 Oct 2021 12:24:18 -0500 Subject: [PATCH 26/35] chore(themes): fix v11 token preview g100 color names (#9890) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- packages/themes/examples/preview-v11/src/pages/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/themes/examples/preview-v11/src/pages/index.js b/packages/themes/examples/preview-v11/src/pages/index.js index 1644e8bc5c38..3b0c679e6031 100644 --- a/packages/themes/examples/preview-v11/src/pages/index.js +++ b/packages/themes/examples/preview-v11/src/pages/index.js @@ -277,7 +277,7 @@ export default function IndexPage() { /> <div className="details"> <span> - {getColorByValue(themes.g90[exportName], 'gray')} + {getColorByValue(themes.g100[exportName], 'gray')} </span> <span className="hex-value"> {themes.g100[exportName]} From 727691155c4f9e5dc3c56976f5316dd8ff7d1550 Mon Sep 17 00:00:00 2001 From: Josefina Mancilla <32556167+jnm2377@users.noreply.github.com> Date: Tue, 19 Oct 2021 13:45:55 -0500 Subject: [PATCH 27/35] feat(Tab): make tab functional component (#9722) * feat(Tab): make tab functional component * feat(Tabs): convert to functional * fix: remove console.logs * fix: export components as default * fix: tabs state and refs * fix: use prefix * fix: add feature flag v11 story * fix: temp use v10 classNames * fix: clean up, comment, and fix select * fix: keyboard navigation * fix: remove console log * chore: tabs comment * feat: add tab tests * feat: add tabs tests * fix: add back light * fix: remove v11 styles * Update packages/react/src/components/Tabs/index.js Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com> * fix: next tab test and deprecation * fix: tabs deprecate unused props * fix: deprecations' * fix: tab role presentation test * fix: remove unused arg' Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../src/components/Tabs/Tabs.stories.js | 8 + .../__snapshots__/PublicAPI-test.js.snap | 6 +- packages/react/src/components/Tab/Tab-test.js | 2 +- packages/react/src/components/Tab/Tab.js | 4 +- packages/react/src/components/Tab/index.js | 8 +- .../react/src/components/Tab/next/Tab-test.js | 204 ++++++ packages/react/src/components/Tab/next/Tab.js | 166 +++++ packages/react/src/components/Tabs/index.js | 11 +- .../src/components/Tabs/next/Tabs-test.js | 264 ++++++++ .../react/src/components/Tabs/next/Tabs.js | 613 ++++++++++++++++++ 10 files changed, 1276 insertions(+), 10 deletions(-) create mode 100644 packages/react/src/components/Tab/next/Tab-test.js create mode 100644 packages/react/src/components/Tab/next/Tab.js create mode 100644 packages/react/src/components/Tabs/next/Tabs-test.js create mode 100644 packages/react/src/components/Tabs/next/Tabs.js diff --git a/packages/carbon-react/src/components/Tabs/Tabs.stories.js b/packages/carbon-react/src/components/Tabs/Tabs.stories.js index 1c04f224b089..4e4741d3288f 100644 --- a/packages/carbon-react/src/components/Tabs/Tabs.stories.js +++ b/packages/carbon-react/src/components/Tabs/Tabs.stories.js @@ -7,10 +7,18 @@ import React from 'react'; import { Button, Tab, Tabs, TabsSkeleton } from '../Tabs'; +import { unstable_FeatureFlags as FeatureFlags } from 'carbon-components-react'; import { Layer } from '../Layer'; export default { title: 'Components/Tabs', + decorators: [ + (Story) => ( + <FeatureFlags flags={{ 'enable-v11-release': true }}> + <Story /> + </FeatureFlags> + ), + ], parameters: { component: Tabs, subcomponents: { diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index 6ac36a38f0a8..6223d424aed7 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -5905,7 +5905,6 @@ Map { "label": "provide a label", "onClick": [Function], "onKeyDown": [Function], - "role": "presentation", "selected": false, }, "propTypes": Object { @@ -5946,10 +5945,7 @@ Map { "renderContent": Object { "type": "func", }, - "role": Object { - "isRequired": true, - "type": "string", - }, + "role": [Function], "selected": Object { "isRequired": true, "type": "bool", diff --git a/packages/react/src/components/Tab/Tab-test.js b/packages/react/src/components/Tab/Tab-test.js index f28a9e157f99..f84b5668a6ac 100644 --- a/packages/react/src/components/Tab/Tab-test.js +++ b/packages/react/src/components/Tab/Tab-test.js @@ -45,7 +45,7 @@ describe('Tab', () => { }); it('renders <li> with [role="presentation"]', () => { - expect(wrapper.props().role).toEqual('presentation'); + expect(wrapper.find('li').prop('role')).toEqual('presentation'); }); it('renders <button> with tabindex set to 0', () => { diff --git a/packages/react/src/components/Tab/Tab.js b/packages/react/src/components/Tab/Tab.js index 1a746eb731c1..6329e625edc0 100644 --- a/packages/react/src/components/Tab/Tab.js +++ b/packages/react/src/components/Tab/Tab.js @@ -82,7 +82,7 @@ export default class Tab extends React.Component { /** * Provide an accessibility role for your Tab */ - role: PropTypes.string.isRequired, + role: deprecate(PropTypes.string), /** * Whether your Tab is selected. @@ -97,7 +97,6 @@ export default class Tab extends React.Component { }; static defaultProps = { - role: 'presentation', label: 'provide a label', selected: false, onClick: () => {}, @@ -122,6 +121,7 @@ export default class Tab extends React.Component { renderAnchor, renderButton, renderContent, // eslint-disable-line no-unused-vars + role, // eslint-disable-line no-unused-vars ...other } = this.props; diff --git a/packages/react/src/components/Tab/index.js b/packages/react/src/components/Tab/index.js index e664e8d8850b..d76f1b004194 100644 --- a/packages/react/src/components/Tab/index.js +++ b/packages/react/src/components/Tab/index.js @@ -5,4 +5,10 @@ * LICENSE file in the root directory of this source tree. */ -export default from './Tab'; +import * as FeatureFlags from '@carbon/feature-flags'; +import { default as TabNext } from './next/Tab'; +import { default as TabClassic } from './Tab'; + +const Tab = FeatureFlags.enabled('enable-v11-release') ? TabNext : TabClassic; + +export default Tab; diff --git a/packages/react/src/components/Tab/next/Tab-test.js b/packages/react/src/components/Tab/next/Tab-test.js new file mode 100644 index 000000000000..78a2f5447278 --- /dev/null +++ b/packages/react/src/components/Tab/next/Tab-test.js @@ -0,0 +1,204 @@ +import React from 'react'; +import { default as Tab } from './Tab'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +describe('Tab', () => { + it('adds extra classes that are passed via className', async () => { + render( + <Tab + className="custom-class" + label="Tab 1" + onClick={() => {}} + onKeyDown={() => {}} + selected={false}> + <p>Content for first tab goes here.</p> + </Tab> + ); + + await expect( + screen.getByRole('presentation').classList.contains('custom-class') + ).toBe(true); + }); + + it('sets tabIndex on <button> if one is passed via props', async () => { + render( + <Tab + label="Tab 1" + // eslint-disable-next-line jsx-a11y/tabindex-no-positive + tabIndex={2} + onClick={() => {}} + onKeyDown={() => {}} + selected={false}> + <p>Content for first tab goes here.</p> + </Tab> + ); + + await expect(screen.getByRole('tab').tabIndex).toEqual(2); + }); + + it('renders <li> with [role="presentation"]', async () => { + render( + <Tab + className="custom-class" + label="Tab 1" + onClick={() => {}} + onKeyDown={() => {}} + selected={false}> + <p>Content for first tab goes here.</p> + </Tab> + ); + + await expect(screen.getByRole('presentation')).toBeTruthy(); + }); + + it('renders <button> with tabindex set to 0 by default', async () => { + render( + <Tab + label="Tab 1" + onClick={() => {}} + onKeyDown={() => {}} + selected={false}> + <p>Content for first tab goes here.</p> + </Tab> + ); + + await expect(screen.getByRole('tab').tabIndex).toEqual(0); + }); + + it('renders <button> with tabindex set to -1 if disabled', async () => { + render( + <Tab + label="Tab 1" + onClick={() => {}} + onKeyDown={() => {}} + selected={false} + disabled> + <p>Content for first tab goes here.</p> + </Tab> + ); + + await expect(screen.getByRole('tab').tabIndex).toEqual(-1); + }); + + it('uses label to set children on <button> when passed via props', async () => { + render( + <Tab + label="Tab 1" + onClick={() => {}} + onKeyDown={() => {}} + selected={false}> + <p>Content for first tab goes here.</p> + </Tab> + ); + + await expect(screen.getByRole('tab').textContent).toBe('Tab 1'); + }); + + it('has aria-disabled that matches disabled', async () => { + render( + <Tab + label="Tab 1" + onClick={() => {}} + onKeyDown={() => {}} + selected={false} + disabled> + <p>Content for first tab goes here.</p> + </Tab> + ); + + await expect(screen.getByRole('tab')).toHaveAttribute('aria-disabled'); + }); +}); + +describe('Click events', () => { + it('invokes handleTabClick from handleTabClick prop', async () => { + const handleTabClick = jest.fn(); + render( + <Tab + label="Tab 1" + handleTabClick={handleTabClick} + onClick={() => {}} + onKeyDown={() => {}} + selected={false}> + <p>Content for first tab goes here.</p> + </Tab> + ); + + const button = screen.getByRole('tab'); + userEvent.click(button); + await expect(handleTabClick).toHaveBeenCalled(); + }); + + it('invokes onClick when a function is passed to onClick prop', async () => { + const onClick = jest.fn(); + + render( + <Tab + label="Tab 1" + onClick={onClick} + onKeyDown={() => {}} + selected={false}> + <p>Content for first tab goes here.</p> + </Tab> + ); + + const button = screen.getByRole('tab'); + userEvent.click(button); + await expect(onClick).toHaveBeenCalled(); + }); + + it('does not invoke click handler if tab is disabled', async () => { + const onClick = jest.fn(); + + render( + <Tab + label="Tab 1" + onClick={onClick} + onKeyDown={() => {}} + selected={false} + disabled> + <p>Content for first tab goes here.</p> + </Tab> + ); + + const button = screen.getByRole('tab'); + userEvent.click(button); + await expect(onClick).not.toHaveBeenCalled(); + }); +}); + +describe('Keyboard events', () => { + it('invokes onKeyDown from onKeyDown prop', async () => { + const onKeyDown = jest.fn(); + render( + <Tab label="Tab 1" onClick={() => {}} onKeyDown={onKeyDown} selected> + <p>Content for first tab goes here.</p> + </Tab> + ); + + const button = screen.getByRole('tab'); + userEvent.type(button, '[ArrowLeft]'); + + await expect(onKeyDown).toHaveBeenCalled(); + }); + + it('invokes handleTabKeyDown from handleTabKeyDown prop', async () => { + const handleTabKeyDown = jest.fn(); + render( + <Tab + label="Tab 1" + onClick={() => {}} + onKeyDown={() => {}} + handleTabKeyDown={handleTabKeyDown} + selected> + <p>Content for first tab goes here.</p> + </Tab> + ); + + const button = screen.getByRole('tab'); + userEvent.type(button, '[ArrowRight]'); + + await expect(handleTabKeyDown).toHaveBeenCalled(); + }); +}); diff --git a/packages/react/src/components/Tab/next/Tab.js b/packages/react/src/components/Tab/next/Tab.js new file mode 100644 index 000000000000..40be07b3b1cb --- /dev/null +++ b/packages/react/src/components/Tab/next/Tab.js @@ -0,0 +1,166 @@ +/** + * Copyright IBM Corp. 2016, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import PropTypes from 'prop-types'; +import React from 'react'; +import classNames from 'classnames'; +import { usePrefix } from '../../../internal/usePrefix'; + +const Tab = React.forwardRef(function Tab( + { + className, + disabled, + handleTabClick, + handleTabKeyDown, + id, + index, + label = 'provide a label', + onClick = () => {}, + onKeyDown = () => {}, + renderButton, + renderContent, // eslint-disable-line no-unused-vars + selected = false, + tabIndex = 0, + ...other + }, + ref +) { + const prefix = usePrefix(); + + const classes = classNames( + className, + // TODO: remove scrollable in next major release + // `${prefix}--tabs__nav-item`, + `${prefix}--tabs--scrollable__nav-item`, + { + [`${prefix}--tabs__nav-item--disabled`]: disabled, + [`${prefix}--tabs__nav-item--selected`]: selected, + // TODO: remove scrollable in next major release + [`${prefix}--tabs--scrollable__nav-item--disabled`]: disabled, + [`${prefix}--tabs--scrollable__nav-item--selected`]: selected, + } + ); + + const buttonProps = { + ['aria-selected']: selected, + ['aria-disabled']: disabled, + ['aria-controls']: id && `${id}__panel`, + id, + // TODO: remove scrollable in next major release + // className: `${prefix}--tabs__nav-link`, + className: `${prefix}--tabs--scrollable__nav-link`, + tabIndex: !disabled ? tabIndex : -1, + ref: ref, + }; + + return ( + <li + {...other} + className={classes} + onClick={(evt) => { + if (disabled) { + return; + } + if (handleTabClick) { + handleTabClick(index, evt); + } + onClick(evt); + }} + onKeyDown={(evt) => { + if (disabled) { + return; + } + if (handleTabKeyDown) { + handleTabKeyDown(index, evt); + } + onKeyDown(evt); + }} + role="presentation"> + {renderButton ? ( + renderButton(buttonProps) + ) : ( + <button type="button" role="tab" {...buttonProps}> + {label} + </button> + )} + </li> + ); +}); + +Tab.propTypes = { + /** + * Specify an optional className to be added to your Tab + */ + className: PropTypes.string, + + /** + * Whether your Tab is disabled. + */ + disabled: PropTypes.bool, + + /** + * A handler that is invoked when a user clicks on the control. + * Reserved for usage in Tabs + */ + handleTabClick: PropTypes.func, + + /** + * A handler that is invoked on the key down event for the control. + * Reserved for usage in Tabs + */ + handleTabKeyDown: PropTypes.func, + + /** + * The element ID for the top-level element. + */ + id: PropTypes.string, + + /** + * The index of your Tab in your Tabs. Reserved for usage in Tabs + */ + index: PropTypes.number, + + /** + * Provide the contents of your Tab + */ + label: PropTypes.node, + + /** + * Provide a handler that is invoked when a user clicks on the control + */ + onClick: PropTypes.func, + + /** + * Provide a handler that is invoked on the key down event for the control + */ + onKeyDown: PropTypes.func, + + /* + * An optional parameter to allow overriding the anchor rendering. + * Useful for using Tab along with react-router or other client + * side router libraries. + **/ + renderButton: PropTypes.func, + + /* + * An optional parameter to allow overriding the content rendering. + **/ + renderContent: PropTypes.func, + + /** + * Whether your Tab is selected. + * Reserved for usage in Tabs + */ + selected: PropTypes.bool, + + /** + * Specify the tab index of the `<button>` node + */ + tabIndex: PropTypes.number, +}; + +export default Tab; diff --git a/packages/react/src/components/Tabs/index.js b/packages/react/src/components/Tabs/index.js index 531a69be74b1..989fb9845fb8 100644 --- a/packages/react/src/components/Tabs/index.js +++ b/packages/react/src/components/Tabs/index.js @@ -5,5 +5,14 @@ * LICENSE file in the root directory of this source tree. */ +import * as FeatureFlags from '@carbon/feature-flags'; +import { default as TabsNext } from './next/Tabs'; +import { default as TabsClassic } from './Tabs'; + +const Tabs = FeatureFlags.enabled('enable-v11-release') + ? TabsNext + : TabsClassic; + export * from './Tabs.Skeleton'; -export default from './Tabs'; + +export default Tabs; diff --git a/packages/react/src/components/Tabs/next/Tabs-test.js b/packages/react/src/components/Tabs/next/Tabs-test.js new file mode 100644 index 000000000000..c95e6731711a --- /dev/null +++ b/packages/react/src/components/Tabs/next/Tabs-test.js @@ -0,0 +1,264 @@ +import React from 'react'; +import { default as Tabs } from './Tabs'; +import { default as Tab } from '../../Tab/next/Tab'; +import { render, screen } from '@testing-library/react'; +import { fireEvent } from '@testing-library/dom'; + +describe('Tabs', () => { + it('adds extra classes that are passed via className prop', async () => { + render( + <Tabs className="custom-class" data-testid="tabs-test"> + <Tab label="firstTab">content1</Tab> + <Tab label="lastTab">content2</Tab> + </Tabs> + ); + + const tabs = screen.getByTestId('tabs-test'); + await expect(tabs.classList.contains('custom-class')).toBe(true); + }); + + it('renders <ul> with tablist role by default', async () => { + render( + <Tabs className="custom-class"> + <Tab label="firstTab">content1</Tab> + <Tab label="lastTab">content2</Tab> + </Tabs> + ); + + const tablist = screen.getByRole('tablist'); + await expect(tablist).toBeTruthy(); + }); +}); + +describe('Children tabs', () => { + it('renders children', async () => { + render( + <Tabs className="custom-class"> + <Tab label="firstTab">content1</Tab> + <Tab label="lastTab">content2</Tab> + </Tabs> + ); + + const tabArray = screen.getAllByRole('presentation'); + await expect(tabArray.length).toEqual(2); + }); + + it('first tab is selected by default', async () => { + render( + <Tabs className="custom-class"> + <Tab label="firstTab" data-testid="first-tab"> + content1 + </Tab> + <Tab label="lastTab">content2</Tab> + </Tabs> + ); + + const firstTab = screen.getByTestId('first-tab'); + await expect( + firstTab.classList.contains('bx--tabs__nav-item--selected') + ).toBe(true); + }); + + it('overrides default selected tab when selected prop is provided', async () => { + render( + <Tabs className="custom-class" selected={1}> + <Tab label="firstTab" data-testid="first-tab"> + content1 + </Tab> + <Tab label="lastTab" data-testid="second-tab"> + content2 + </Tab> + </Tabs> + ); + + const firstTab = screen.getByTestId('first-tab'); + const secondTab = screen.getByTestId('second-tab'); + + await expect( + firstTab.classList.contains('bx--tabs__nav-item--selected') + ).toBe(false); + await expect( + secondTab.classList.contains('bx--tabs__nav-item--selected') + ).toBe(true); + }); +}); + +describe('Children tab content', () => { + it('renders correct number of children content as expected', async () => { + render( + <Tabs className="custom-class"> + <Tab label="firstTab">content1</Tab> + <Tab label="lastTab">content2</Tab> + </Tabs> + ); + + const contentArray = screen.getAllByRole('tabpanel', { hidden: true }); + await expect(contentArray.length).toEqual(2); + }); + + it('only shows one content tabpanel at a time', async () => { + render( + <Tabs className="custom-class"> + <Tab label="firstTab">content1</Tab> + <Tab label="secondTab">content2</Tab> + <Tab label="lastTab">content3</Tab> + </Tabs> + ); + + const contentArray = screen.getAllByRole('tabpanel'); + await expect(contentArray.length).toEqual(1); + }); + + it('adds extra classes that are passed via tabContentClassName prop', async () => { + render( + <Tabs tabContentClassName="content-class"> + <Tab label="firstTab">content1</Tab> + <Tab label="lastTab">content2</Tab> + </Tabs> + ); + + const content = screen.getByRole('tabpanel'); + await expect(content.classList.contains('content-class')).toBe(true); + }); + + it('renders unselected tab content with hidden attribute', async () => { + render( + <Tabs className="custom-class"> + <Tab label="firstTab">content1</Tab> + <Tab label="lastTab">content2</Tab> + </Tabs> + ); + + const contentArray = screen.getAllByRole('tabpanel', { hidden: true }); + await expect(contentArray[1]).toHaveAttribute('hidden'); + }); +}); + +describe('Keyboard events', () => { + it('updates selected tab and content, and loops from first tab to last tab when pressing left arrow key', async () => { + render( + <Tabs> + <Tab label="firstTab" data-testid="tab1"> + content1 + </Tab> + <Tab label="lastTab" data-testid="tab2"> + content2 + </Tab> + </Tabs> + ); + + const tab1 = screen.getByTestId('tab1'); + const tab2 = screen.getByTestId('tab2'); + + const tabContent = screen.getAllByRole('tabpanel'); + const tab1Content = tabContent[0]; + fireEvent.keyDown(tab1, { + key: 'ArrowLeft', + code: 'ArrowLeft', + charCode: 37, + }); + await expect(tab2.classList.contains('bx--tabs__nav-item--selected')).toBe( + true + ); + await expect(tab1Content).toHaveAttribute('hidden'); + }); + + it('updates selected tab and content when pressing right arrow key', async () => { + render( + <Tabs> + <Tab label="firstTab" data-testid="tab1"> + content1 + </Tab> + <Tab label="lastTab" data-testid="tab2"> + content2 + </Tab> + </Tabs> + ); + + const tab1 = screen.getByTestId('tab1'); + const tab2 = screen.getByTestId('tab2'); + const tabContent = screen.getAllByRole('tabpanel'); + const tab1Content = tabContent[0]; + + fireEvent.keyDown(tab1, { + key: 'ArrowRight', + code: 'ArrowRight', + charCode: 39, + }); + await expect(tab2.classList.contains('bx--tabs__nav-item--selected')).toBe( + true + ); + await expect(tab1Content).toHaveAttribute('hidden'); + }); + + it('ignores disabled tabs', async () => { + render( + <Tabs> + <Tab label="firstTab" data-testid="tab1"> + content1 + </Tab> + <Tab label="lastTab" data-testid="tab2" disabled> + content2 + </Tab> + <Tab label="thirdTab" data-testid="tab3"> + content3 + </Tab> + </Tabs> + ); + const tab1 = screen.getByTestId('tab1'); + const tab3 = screen.getByTestId('tab3'); + fireEvent.keyDown(tab1, { + key: 'ArrowRight', + code: 'ArrowRight', + charCode: 39, + }); + + await expect(tab3.classList.contains('bx--tabs__nav-item--selected')).toBe( + true + ); + }); +}); + +describe('Click events', () => { + it('updates selected tab and content on click', async () => { + render( + <Tabs> + <Tab label="firstTab" data-testid="tab1"> + content1 + </Tab> + <Tab label="lastTab" data-testid="tab2"> + content2 + </Tab> + </Tabs> + ); + const tab2 = screen.getByTestId('tab2'); + const tabContent = screen.getAllByRole('tabpanel'); + const tab1Content = tabContent[0]; + fireEvent.click(tab2); + await expect(tab2.classList.contains('bx--tabs__nav-item--selected')).toBe( + true + ); + await expect(tab1Content).toHaveAttribute('hidden'); + }); + + it('ignores disabled tab on click', async () => { + render( + <Tabs> + <Tab label="firstTab" data-testid="tab1"> + content1 + </Tab> + <Tab label="lastTab" data-testid="tab2" disabled> + content2 + </Tab> + </Tabs> + ); + const tab2 = screen.getByTestId('tab2'); + const tabContent = screen.getAllByRole('tabpanel', { hidden: true }); + const tab2Content = tabContent[1]; + fireEvent.click(tab2); + await expect(tab2.classList.contains('bx--tabs__nav-item--selected')).toBe( + false + ); + await expect(tab2Content).toHaveAttribute('hidden'); + }); +}); diff --git a/packages/react/src/components/Tabs/next/Tabs.js b/packages/react/src/components/Tabs/next/Tabs.js new file mode 100644 index 000000000000..c94a46d8719d --- /dev/null +++ b/packages/react/src/components/Tabs/next/Tabs.js @@ -0,0 +1,613 @@ +/** + * Copyright IBM Corp. 2016, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import PropTypes from 'prop-types'; +import React, { useState, useRef, useEffect, useCallback } from 'react'; +import classNames from 'classnames'; +import { ChevronLeft16, ChevronRight16 } from '@carbon/icons-react'; +import debounce from 'lodash.debounce'; +import { keys, match, matches } from '../../../internal/keyboard'; +import TabContent from '../../TabContent'; +import deprecate from '../../../prop-types/deprecate'; +import { usePrefix } from '../../../internal/usePrefix'; + +const Tabs = React.forwardRef(function Tabs( + { + children, + className, + leftOverflowButtonProps, + light = false, + onSelectionChange, + rightOverflowButtonProps, + scrollIntoView = true, + selected = 0, + selectionMode = 'automatic', + tabContentClassName, + type = 'default', + ...other + }, + ref +) { + const prefix = usePrefix(); + + //refs + const tablist = useRef(); + const leftOverflowNavButton = useRef(); + const rightOverflowNavButton = useRef(); + const tabs = useRef([]); + + //states + const [horizontalOverflow, setHorizontalOverflow] = useState(false); + const [tablistClientWidth, setTablistClientWidth] = useState(null); + const [tablistScrollWidth, setTablistScrollWidth] = useState(null); + const [tablistScrollLeft, setTablistScrollLeft] = useState(null); + const [isSelected, setIsSelected] = useState(selected); + const [prevSelected, setPrevSelected] = useState(isSelected); + + /** + * prop + state alignment - getDerivedStateFromProps + * only update if selected prop changes + */ + useEffect(() => { + if (selected !== prevSelected) { + setIsSelected(selected); + setPrevSelected(selected); + } + }, [selected]); //eslint-disable-line react-hooks/exhaustive-deps + + // width of the overflow buttons + let OVERFLOW_BUTTON_OFFSET = 40; + + /** + * `scroll` event handler to save tablist clientWidth, scrollWidth, and + * scrollLeft + */ + const handleScroll = () => { + if (!tablist?.current) { + return; + } + const { clientWidth, scrollLeft, scrollWidth } = tablist.current; + + setTablistClientWidth(clientWidth); + setTablistScrollWidth(scrollWidth); + setTablistScrollLeft(scrollLeft); + setHorizontalOverflow(scrollWidth > clientWidth); + }; + + /** + * The debounced version of the `resize` event handler. + * @type {Function} + * @private + */ + const _debouncedHandleWindowResize = useRef(); + + const _handleWindowResize = handleScroll; + + /** + * returns all tabs that are not disabled + * used for keyboard navigation + */ + const getEnabledTabs = () => + React.Children.toArray(children).reduce( + (enabledTabs, tab, index) => + !tab.props.disabled ? enabledTabs.concat(index) : enabledTabs, + [] + ); + + /** + * returns the index of the next tab we are going to when navigating L/R arrow keys (i.e. 0, 1, 2) + * used in handleTabKeyDown to get the next index after keyboard arrow evt, which then updates selected tab + */ + const getNextIndex = (index, direction) => { + const enabledTabs = getEnabledTabs(); + const nextIndex = Math.max( + enabledTabs.indexOf(index) + direction, + // For `tab` not found in `enabledTabs` + -1 + ); + const nextIndexLooped = + nextIndex >= 0 && nextIndex < enabledTabs.length + ? nextIndex + : nextIndex - Math.sign(nextIndex) * enabledTabs.length; + return enabledTabs[nextIndexLooped]; + }; + + /** + * used as second argument for getNextIndex(i,d) + * returns -1, 1 or 0 depending on arrow key + * number is then used in math calculations to find the index of the next tab we are navigating to + */ + const getDirection = (evt) => { + if (match(evt, keys.ArrowLeft)) { + return -1; + } + if (match(evt, keys.ArrowRight)) { + return 1; + } + return 0; + }; + + const getTabAt = useCallback( + (index) => tabs.current[index] || React.Children.toArray(children)[index], + [tabs, children] + ); + + const scrollTabIntoView = (event, { index }) => { + const tab = getTabAt(index); + if ( + matches(event, [keys.ArrowLeft, keys.ArrowRight]) || + event.type === 'click' + ) { + const currentScrollLeft = tablistScrollLeft; + tab?.tabAnchor?.scrollIntoView({ + block: 'nearest', + inline: 'nearest', + }); + tab?.tabAnchor?.focus(); + const newScrollLeft = tablist.current.scrollLeft; + if (newScrollLeft > currentScrollLeft) { + tablist.current.scrollLeft += OVERFLOW_BUTTON_OFFSET; + } + } + }; + + /** + * selecting tab on click and on keyboard nav + * index = tab to be selected, returned in handleTabKeyDown + * onSelectionChange = optional prop for event handler + */ + const selectTabAt = (event, { index, onSelectionChange }) => { + scrollTabIntoView(event, { index }); + if (isSelected !== index) { + setIsSelected(index); + setPrevSelected(index); + if (typeof onSelectionChange === 'function') { + onSelectionChange(index); + } + } + }; + + /** + * keyboard event handler + */ + const handleTabKeyDown = (onSelectionChange) => { + return (index, evt) => { + if (matches(evt, [keys.Enter, keys.Space])) { + selectTabAt(evt, { index, onSelectionChange }); + } + + const nextIndex = (() => { + if (matches(evt, [keys.ArrowLeft, keys.ArrowRight])) { + return getNextIndex(index, getDirection(evt)); + } + if (match(evt, keys.Home)) { + return 0; + } + if (match(evt, keys.End)) { + return getEnabledTabs().pop(); + } + })(); + const tab = getTabAt(nextIndex); + + // updating selected tab + if ( + matches(evt, [keys.ArrowLeft, keys.ArrowRight, keys.Home, keys.End]) + ) { + evt.preventDefault(); + if (selectionMode !== 'manual') { + selectTabAt(evt, { index: nextIndex, onSelectionChange }); + } else { + scrollTabIntoView(evt, { index: nextIndex }); + } + tab?.focus(); + } + }; + }; + + const getTabs = () => React.Children.map(children, (tab) => tab); + + /** + * click handler + * passed down to Tab children as a prop in `tabsWithProps` + * following functions (handle*) are Props on Tab.js, see Tab.js for parameters + */ + const handleTabClick = (onSelectionChange) => (index, evt) => { + evt.preventDefault(); + selectTabAt(evt, { index, onSelectionChange }); + }; + + /** + * creates an array of all the child tab items + */ + const setTabAt = (index, tabRef) => { + tabs.current[index] = tabRef; + }; + + let overflowNavInterval = null; + + /** + * group - overflow scroll + * scrolling via overflow btn click + * click handler for scrollable tabs L/R arrow buttons + */ + const handleOverflowNavClick = (_, { direction, multiplier = 10 }) => { + // account for overflow button appearing and causing tablist width change + const { clientWidth, scrollLeft, scrollWidth } = tablist?.current; + if (direction === 1 && !scrollLeft) { + tablist.current.scrollLeft += OVERFLOW_BUTTON_OFFSET; + } + + tablist.current.scrollLeft += direction * multiplier; + + const leftEdgeReached = + direction === -1 && scrollLeft < OVERFLOW_BUTTON_OFFSET; + + const rightEdgeReached = + direction === 1 && + scrollLeft + clientWidth >= scrollWidth - OVERFLOW_BUTTON_OFFSET; + + if (leftEdgeReached || rightEdgeReached) { + if (leftEdgeReached) { + rightOverflowNavButton?.current?.focus(); + } + if (rightEdgeReached) { + leftOverflowNavButton?.current?.focus(); + } + } + }; + + /** + * group - overflow scroll + * scrolling w/ mouse event + * mousedown handler for scrollable tabs + */ + const handleOverflowNavMouseDown = (event, { direction }) => { + // disregard mouse buttons aside from LMB + if (event.buttons !== 1) { + return; + } + + overflowNavInterval = setInterval(() => { + const { clientWidth, scrollLeft, scrollWidth } = tablist?.current; + + // clear interval if scroll reaches left or right edge + const leftEdgeReached = + direction === -1 && scrollLeft < OVERFLOW_BUTTON_OFFSET; + + const rightEdgeReached = + direction === 1 && + scrollLeft + clientWidth >= scrollWidth - OVERFLOW_BUTTON_OFFSET; + + if (leftEdgeReached || rightEdgeReached) { + clearInterval(overflowNavInterval); + } + + // account for overflow button appearing and causing tablist width change + handleOverflowNavClick(event, { direction }); + }); + }; + + /** + * group - overflow scroll + * scrolling w/ mouse event + * mouseup handler for scrollable tabs + */ + const handleOverflowNavMouseUp = () => { + clearInterval(overflowNavInterval); + }; + + /** + * only run once - component did mount equivalent + */ + useEffect(() => { + _debouncedHandleWindowResize.current = debounce(_handleWindowResize, 200); + + _handleWindowResize(); + window.addEventListener('resize', _debouncedHandleWindowResize.current); + + // scroll selected tab into view on mount + const { clientWidth, scrollLeft, scrollWidth } = tablist?.current || {}; + + setTablistClientWidth(clientWidth); + setTablistScrollWidth(scrollWidth); + setTablistScrollLeft(scrollLeft); + + const tab = getTabAt(isSelected); + const horizontalOverflow = scrollWidth > clientWidth; + + if (horizontalOverflow) { + const leftOverflowNavButtonHidden = + tab?.tabAnchor?.getBoundingClientRect().right < + tab?.tabAnchor?.offsetParent.getBoundingClientRect().right; + + const rightOverflowNavButtonHidden = + scrollLeft + clientWidth === scrollWidth; + scrollIntoView && + tab?.tabAnchor?.scrollIntoView({ + block: 'nearest', + inline: 'nearest', + }); + + // account for overflow buttons in scroll position on mount + if (!leftOverflowNavButtonHidden && !rightOverflowNavButtonHidden) { + tablist.current.scrollLeft += OVERFLOW_BUTTON_OFFSET * 2; + } + } + + //component will unmount equivalent + return () => { + if (_debouncedHandleWindowResize.current) { + _debouncedHandleWindowResize.current.cancel(); + } + window.removeEventListener( + 'resize', + _debouncedHandleWindowResize.current + ); + }; + }, []); // eslint-disable-line react-hooks/exhaustive-deps + + /** + * component did update equivalent + */ + useEffect(() => { + // compare current tablist properties to current state + const { + clientWidth: currentTablistClientWidth, + scrollLeft: currentTablistScrollLeft, + scrollWidth: currentTablistScrollWidth, + } = tablist.current; + + if ( + currentTablistClientWidth !== tablistClientWidth || + currentTablistScrollLeft !== tablistScrollLeft || + currentTablistScrollWidth !== tablistScrollWidth + ) { + setTablistClientWidth(currentTablistClientWidth); + setTablistScrollWidth(currentTablistScrollWidth); + setTablistScrollLeft(currentTablistScrollLeft); + setHorizontalOverflow( + currentTablistScrollWidth > currentTablistClientWidth + ); + } + + if (scrollIntoView && prevSelected !== isSelected) { + getTabAt(isSelected)?.tabAnchor?.scrollIntoView({ + block: 'nearest', + inline: 'nearest', + }); + } + }, [ + isSelected, + prevSelected, + scrollIntoView, + tablistClientWidth, + tablistScrollLeft, + tablistScrollWidth, + getTabAt, + ]); + + /** + * The tab panel acts like a tab panel when the screen is wider, but acts + * like a select list when the screen is narrow. In the wide case we want + * to allow the user to use the tab key to set the focus in the tab panel + * and then use the left and right arrow keys to navigate the tabs. In the + * narrow case we want to use the tab key to select different options in + * the list. + * + * We set the tab index based on the different states so the browser will treat + * the whole tab panel as a single focus component when it looks like a tab + * panel and separate components when it looks like a select list. + */ + const tabsWithProps = getTabs().map((tab, index) => { + const tabIndex = index === isSelected ? 0 : -1; + const newTab = React.cloneElement(tab, { + index, + selected: index === isSelected, + handleTabClick: handleTabClick(onSelectionChange), + tabIndex, + ref: (e) => { + setTabAt(index, e); + }, + handleTabKeyDown: handleTabKeyDown(onSelectionChange), + }); + + return newTab; + }); + + const tabContentWithProps = React.Children.map(tabsWithProps, (tab) => { + const { + id: tabId, + children, + selected, + renderContent: Content = TabContent, + } = tab.props; + + return ( + <Content + id={tabId && `${tabId}__panel`} + className={tabContentClassName} + hidden={!selected} + selected={selected} + aria-labelledby={tabId}> + {children} + </Content> + ); + }); + + const leftOverflowNavButtonHidden = !horizontalOverflow || !tablistScrollLeft; + + const rightOverflowNavButtonHidden = + !horizontalOverflow || + tablistScrollLeft + tablistClientWidth === tablistScrollWidth; + + const classes = { + // TODO: remove scrollable from classnames in next major release and uncomment classnames that don't contain scrollable + tabs: classNames( + className, + // `${prefix}--tabs`, + `${prefix}--tabs--scrollable`, + { + // [`${prefix}--tabs--container`]: type === 'container', + [`${prefix}--tabs--scrollable--container`]: type === 'container', + // [`${prefix}--tabs--light`]: light, + [`${prefix}--tabs--scrollable--light`]: light, + } + ), + // TODO: remove scrollable from classnames in next major release and uncomment classnames that don't contain scrollable + tablist: classNames( + // `${prefix}--tabs__nav`, + `${prefix}--tabs--scrollable__nav` + ), + leftOverflowButtonClasses: classNames({ + [`${prefix}--tab--overflow-nav-button`]: horizontalOverflow, + [`${prefix}--tab--overflow-nav-button--hidden`]: leftOverflowNavButtonHidden, + }), + rightOverflowButtonClasses: classNames({ + [`${prefix}--tab--overflow-nav-button`]: horizontalOverflow, + [`${prefix}--tab--overflow-nav-button--hidden`]: rightOverflowNavButtonHidden, + }), + }; + + return ( + <> + <div + className={classes.tabs} + onScroll={handleScroll} + ref={ref} + {...other}> + <button + aria-hidden="true" + aria-label="Scroll left" + className={classes.leftOverflowButtonClasses} + onClick={(_) => handleOverflowNavClick(_, { direction: -1 })} + onMouseDown={(event) => + handleOverflowNavMouseDown(event, { direction: -1 }) + } + onMouseUp={handleOverflowNavMouseUp} + ref={leftOverflowNavButton} + tabIndex="-1" + type="button" + {...leftOverflowButtonProps}> + <ChevronLeft16 /> + </button> + {!leftOverflowNavButtonHidden && ( + <div className={`${prefix}--tabs__overflow-indicator--left`} /> + )} + <ul + role="tablist" + tabIndex={-1} + className={classes.tablist} + ref={tablist}> + {tabsWithProps} + </ul> + {!rightOverflowNavButtonHidden && ( + <div className={`${prefix}--tabs__overflow-indicator--right`} /> + )} + <button + aria-hidden="true" + aria-label="Scroll right" + className={classes.rightOverflowButtonClasses} + onClick={(_) => handleOverflowNavClick(_, { direction: 1 })} + onMouseDown={(event) => + handleOverflowNavMouseDown(event, { direction: 1 }) + } + onMouseUp={handleOverflowNavMouseUp} + ref={rightOverflowNavButton} + tabIndex="-1" + type="button" + {...rightOverflowButtonProps}> + <ChevronRight16 /> + </button> + </div> + {tabContentWithProps} + </> + ); +}); + +Tabs.propTypes = { + /** + * Pass in a collection of <Tab> children to be rendered depending on the + * currently selected tab + */ + children: PropTypes.node, + + /** + * Provide a className that is applied to the root <div> component for the + * <Tabs> + */ + className: PropTypes.string, + + /** + * Specify whether the Tab content is hidden + */ + hidden: PropTypes.bool, + + /** + * Provide the props that describe the left overflow button + */ + leftOverflowButtonProps: PropTypes.object, + + /** + * Specify whether or not to use the light component variant + */ + light: deprecate( + PropTypes.bool, + 'The light prop has been deprecated in v11 in favor of our new layering model that uses the Layer component' + ), + + /** + * Optionally provide an `onClick` handler that is invoked when a <Tab> is + * clicked + */ + onClick: PropTypes.func, + + /** + * Optionally provide an `onKeyDown` handler that is invoked when keyed + * navigation is triggered + */ + onKeyDown: PropTypes.func, + + /** + * Provide an optional handler that is called whenever the selection + * changes. This method is called with the index of the tab that was + * selected + */ + onSelectionChange: PropTypes.func, + + /** + * Provide the props that describe the right overflow button + */ + rightOverflowButtonProps: PropTypes.object, + + /** + * Choose whether or not to automatically scroll to newly selected tabs + * on component rerender + */ + scrollIntoView: PropTypes.bool, + + /** + * Optionally provide an index for the currently selected <Tab> + */ + selected: PropTypes.number, + + /** + * Choose whether or not to automatically change selection on focus + */ + selectionMode: PropTypes.oneOf(['automatic', 'manual']), + + /** + * Provide a className that is applied to the <TabContent> components + */ + tabContentClassName: PropTypes.string, + + /** + * Provide the type of Tab + */ + type: PropTypes.oneOf(['default', 'container']), +}; + +export default Tabs; From 72731190d6bf854b09e3cdb5785799821908970f Mon Sep 17 00:00:00 2001 From: Taylor Jones <tay1orjones@users.noreply.github.com> Date: Tue, 19 Oct 2021 14:19:30 -0500 Subject: [PATCH 28/35] Remove external/outside margin from components (#9830) * fix(form): remove fieldset margin * fix(form): remove fileuploader margin * fix(form): remove label margin * fix(notifications): remove external margin * fix(structured-list): remove external margin * chore: put component margin removal behind flag * chore: add v11 flag env variable to sass compilation config Co-authored-by: Josh Black <josh@josh.black> --- .../file-uploader/_file-uploader.scss | 5 ++++- .../components/src/components/form/_form.scss | 21 +++++++++++++------ .../notification/_inline-notification.scss | 7 +++++-- .../notification/_toast-notification.scss | 15 ++++++++----- .../structured-list/_structured-list.scss | 5 ++++- packages/react/.storybook/main.js | 4 +++- .../src/components/FormGroup/FormGroup.js | 3 ++- .../file-uploader/_file-uploader.scss | 5 ++++- .../styles/scss/components/form/_form.scss | 21 +++++++++++++------ .../_actionable-notification.scss | 7 +++++-- .../notification/_inline-notification.scss | 7 +++++-- .../notification/_toast-notification.scss | 15 ++++++++----- .../structured-list/_structured-list.scss | 5 ++++- 13 files changed, 86 insertions(+), 34 deletions(-) diff --git a/packages/components/src/components/file-uploader/_file-uploader.scss b/packages/components/src/components/file-uploader/_file-uploader.scss index 1d997c4d0600..bb4b63e24c7e 100644 --- a/packages/components/src/components/file-uploader/_file-uploader.scss +++ b/packages/components/src/components/file-uploader/_file-uploader.scss @@ -57,7 +57,10 @@ display: inline-block; width: 100%; max-width: rem(320px); - margin-bottom: $carbon--spacing-03; + @if not feature-flag-enabled('enable-v11-release') { + margin-bottom: $carbon--spacing-03; + } + color: $link-01; cursor: pointer; outline: 2px solid transparent; diff --git a/packages/components/src/components/form/_form.scss b/packages/components/src/components/form/_form.scss index 17715c9e33f8..f00ae8ef4124 100644 --- a/packages/components/src/components/form/_form.scss +++ b/packages/components/src/components/form/_form.scss @@ -18,11 +18,15 @@ .#{$prefix}--fieldset { @include reset; - margin-bottom: $carbon--spacing-07; + @if not feature-flag-enabled('enable-v11-release') { + margin-bottom: $carbon--spacing-07; + } } - .#{$prefix}--fieldset--no-margin { - margin-bottom: 0; + @if not feature-flag-enabled('enable-v11-release') { + .#{$prefix}--fieldset--no-margin { + margin-bottom: 0; + } } .#{$prefix}--form-item { @@ -42,7 +46,10 @@ @include type-style('label-01'); display: inline-block; - margin-bottom: $carbon--spacing-03; + @if not feature-flag-enabled('enable-v11-release') { + margin-bottom: $carbon--spacing-03; + } + color: $text-02; font-weight: $input-label-weight; line-height: 1rem; @@ -125,8 +132,10 @@ display: block; } - .#{$prefix}--form--fluid .#{$prefix}--fieldset { - margin: 0; + @if not feature-flag-enabled('enable-v11-release') { + .#{$prefix}--form--fluid .#{$prefix}--fieldset { + margin: 0; + } } .#{$prefix}--form--fluid input[data-invalid] { diff --git a/packages/components/src/components/notification/_inline-notification.scss b/packages/components/src/components/notification/_inline-notification.scss index 17cbde33b4c4..f58bf988467d 100644 --- a/packages/components/src/components/notification/_inline-notification.scss +++ b/packages/components/src/components/notification/_inline-notification.scss @@ -33,8 +33,11 @@ height: auto; min-height: rem(48px); flex-wrap: wrap; - margin-top: $carbon--spacing-05; - margin-bottom: $carbon--spacing-05; + @if not feature-flag-enabled('enable-v11-release') { + margin-top: $carbon--spacing-05; + margin-bottom: $carbon--spacing-05; + } + color: $inverse-01; @include carbon--breakpoint(md) { diff --git a/packages/components/src/components/notification/_toast-notification.scss b/packages/components/src/components/notification/_toast-notification.scss index 1fb6fdaa305d..2c4cf3d76b02 100644 --- a/packages/components/src/components/notification/_toast-notification.scss +++ b/packages/components/src/components/notification/_toast-notification.scss @@ -29,14 +29,19 @@ width: rem(288px); height: auto; padding-left: $carbon--spacing-05; - margin-top: $carbon--spacing-03; - margin-right: $carbon--spacing-05; - margin-bottom: $carbon--spacing-03; + @if not feature-flag-enabled('enable-v11-release') { + margin-top: $carbon--spacing-03; + margin-right: $carbon--spacing-05; + margin-bottom: $carbon--spacing-03; + } + box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.2); color: $inverse-01; - &:first-child { - margin-top: $carbon--spacing-05; + @if not feature-flag-enabled('enable-v11-release') { + &:first-child { + margin-top: $carbon--spacing-05; + } } @include carbon--breakpoint(max) { diff --git a/packages/components/src/components/structured-list/_structured-list.scss b/packages/components/src/components/structured-list/_structured-list.scss index f07bf8b9ed23..a19bbcbf7dae 100644 --- a/packages/components/src/components/structured-list/_structured-list.scss +++ b/packages/components/src/components/structured-list/_structured-list.scss @@ -32,7 +32,10 @@ display: table; width: 100%; - margin-bottom: 5rem; + @if not feature-flag-enabled('enable-v11-release') { + margin-bottom: 5rem; + } + background-color: transparent; border-collapse: collapse; border-spacing: 0; diff --git a/packages/react/.storybook/main.js b/packages/react/.storybook/main.js index 4d9fa461553e..41be2da8f11c 100644 --- a/packages/react/.storybook/main.js +++ b/packages/react/.storybook/main.js @@ -13,7 +13,7 @@ const customProperties = require('postcss-custom-properties'); const rtlcss = require('rtlcss'); const { - CARBON_ENABLE_V11_RELEASE, + CARBON_ENABLE_V11_RELEASE = 'false', CARBON_REACT_STORYBOOK_USE_CUSTOM_PROPERTIES = 'false', CARBON_REACT_STORYBOOK_USE_RTL, CARBON_REACT_STORYBOOK_USE_SASS_LOADER, @@ -69,6 +69,7 @@ module.exports = { $feature-flags: ( ui-shell: true, enable-css-custom-properties: ${CARBON_REACT_STORYBOOK_USE_CUSTOM_PROPERTIES}, + enable-v11-release: ${CARBON_ENABLE_V11_RELEASE}, ); ${content} `; @@ -88,6 +89,7 @@ module.exports = { $feature-flags: ( ui-shell: true, enable-css-custom-properties: ${CARBON_REACT_STORYBOOK_USE_CUSTOM_PROPERTIES}, + enable-v11-release: ${CARBON_ENABLE_V11_RELEASE}, ); `, implementation: require('sass'), diff --git a/packages/react/src/components/FormGroup/FormGroup.js b/packages/react/src/components/FormGroup/FormGroup.js index f2cd065863d5..d476c4bd4d50 100644 --- a/packages/react/src/components/FormGroup/FormGroup.js +++ b/packages/react/src/components/FormGroup/FormGroup.js @@ -19,7 +19,7 @@ const FormGroup = ({ className, message, messageText, - hasMargin, + hasMargin, // TODO - remove in v11 ...other }) => { const prefix = usePrefix(); @@ -27,6 +27,7 @@ const FormGroup = ({ const classNamesLegend = classnames(`${prefix}--label`, [ enabled ? null : className, ]); + // TODO - remove `fieldset--no-margin` in v11 const classNamesFieldset = classnames(`${prefix}--fieldset`, className, { [`${prefix}--fieldset--no-margin`]: !hasMargin, }); diff --git a/packages/styles/scss/components/file-uploader/_file-uploader.scss b/packages/styles/scss/components/file-uploader/_file-uploader.scss index 1f7a90661459..d093294b83df 100644 --- a/packages/styles/scss/components/file-uploader/_file-uploader.scss +++ b/packages/styles/scss/components/file-uploader/_file-uploader.scss @@ -62,7 +62,10 @@ display: inline-block; width: 100%; max-width: rem(320px); - margin-bottom: $spacing-03; + @if not enabled('enable-v11-release') { + margin-bottom: $spacing-03; + } + color: $link-primary; cursor: pointer; outline: 2px solid transparent; diff --git a/packages/styles/scss/components/form/_form.scss b/packages/styles/scss/components/form/_form.scss index 1db3071bcad7..bee4c969ac82 100644 --- a/packages/styles/scss/components/form/_form.scss +++ b/packages/styles/scss/components/form/_form.scss @@ -22,11 +22,15 @@ $input-label-weight: 400 !default; .#{$prefix}--fieldset { @include reset; - margin-bottom: $spacing-07; + @if not enabled('enable-v11-release') { + margin-bottom: $spacing-07; + } } - .#{$prefix}--fieldset--no-margin { - margin-bottom: 0; + @if not enabled('enable-v11-release') { + .#{$prefix}--fieldset--no-margin { + margin-bottom: 0; + } } .#{$prefix}--form-item { @@ -46,7 +50,10 @@ $input-label-weight: 400 !default; @include type-style('label-01'); display: inline-block; - margin-bottom: $spacing-03; + @if not enabled('enable-v11-release') { + margin-bottom: $spacing-03; + } + color: $text-secondary; font-weight: $input-label-weight; line-height: 1rem; @@ -129,8 +136,10 @@ $input-label-weight: 400 !default; display: block; } - .#{$prefix}--form--fluid .#{$prefix}--fieldset { - margin: 0; + @if not enabled('enable-v11-release') { + .#{$prefix}--form--fluid .#{$prefix}--fieldset { + margin: 0; + } } .#{$prefix}--form--fluid input[data-invalid] { diff --git a/packages/styles/scss/components/notification/_actionable-notification.scss b/packages/styles/scss/components/notification/_actionable-notification.scss index 7984f0bdb9c1..deb8d6e6cb42 100644 --- a/packages/styles/scss/components/notification/_actionable-notification.scss +++ b/packages/styles/scss/components/notification/_actionable-notification.scss @@ -36,8 +36,11 @@ height: auto; min-height: rem(48px); flex-wrap: wrap; - margin-top: $spacing-05; - margin-bottom: $spacing-05; + @if not enabled('enable-v11-release') { + margin-top: $spacing-05; + margin-bottom: $spacing-05; + } + color: $text-inverse; @include breakpoint(md) { diff --git a/packages/styles/scss/components/notification/_inline-notification.scss b/packages/styles/scss/components/notification/_inline-notification.scss index 5f281a2cf556..fe15efe2a1d0 100644 --- a/packages/styles/scss/components/notification/_inline-notification.scss +++ b/packages/styles/scss/components/notification/_inline-notification.scss @@ -34,8 +34,11 @@ height: auto; min-height: rem(48px); flex-wrap: wrap; - margin-top: $spacing-05; - margin-bottom: $spacing-05; + @if not enabled('enable-v11-release') { + margin-top: $spacing-05; + margin-bottom: $spacing-05; + } + color: $text-inverse; @include breakpoint(md) { diff --git a/packages/styles/scss/components/notification/_toast-notification.scss b/packages/styles/scss/components/notification/_toast-notification.scss index 80765bcc3a93..c4e6471ef7e7 100644 --- a/packages/styles/scss/components/notification/_toast-notification.scss +++ b/packages/styles/scss/components/notification/_toast-notification.scss @@ -32,14 +32,19 @@ width: rem(288px); height: auto; padding-left: $spacing-05; - margin-top: $spacing-03; - margin-right: $spacing-05; - margin-bottom: $spacing-03; + @if not enabled('enable-v11-release') { + margin-top: $spacing-03; + margin-right: $spacing-05; + margin-bottom: $spacing-03; + } + box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.2); color: $text-inverse; - &:first-child { - margin-top: $spacing-05; + @if not enabled('enable-v11-release') { + &:first-child { + margin-top: $spacing-05; + } } @include breakpoint(max) { diff --git a/packages/styles/scss/components/structured-list/_structured-list.scss b/packages/styles/scss/components/structured-list/_structured-list.scss index 08a64f15cc9d..ed2c72bb94bc 100644 --- a/packages/styles/scss/components/structured-list/_structured-list.scss +++ b/packages/styles/scss/components/structured-list/_structured-list.scss @@ -36,7 +36,10 @@ display: table; width: 100%; - margin-bottom: 5rem; + @if not enabled('enable-v11-release') { + margin-bottom: 5rem; + } + background-color: transparent; border-collapse: collapse; border-spacing: 0; From 3f7fbdf5b1dfd45e9c2061bc65890534f4c25ddf Mon Sep 17 00:00:00 2001 From: Kin Ueng <github@kinueng.com> Date: Wed, 20 Oct 2021 12:09:38 -0500 Subject: [PATCH 29/35] fix(button): hcm for ghost icon color contrast (#9904) * fix(button): hcm for ghost icon color contrast - #9903 * fix(button): hcm iconOnly fill fix, mirror to styles package Co-authored-by: Taylor Jones <taylor.jones826@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- packages/components/src/components/button/_button.scss | 9 +++++++++ packages/styles/scss/components/button/_button.scss | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/packages/components/src/components/button/_button.scss b/packages/components/src/components/button/_button.scss index 307d9914392d..621372083de3 100644 --- a/packages/components/src/components/button/_button.scss +++ b/packages/components/src/components/button/_button.scss @@ -523,6 +523,15 @@ .#{$prefix}--btn:focus { @include high-contrast-mode('focus'); } + + // Windows HCM fix + // stylelint-disable-next-line no-duplicate-selectors + .#{$prefix}--btn--ghost.#{$prefix}--btn--icon-only + .#{$prefix}--btn__icon + path:not([data-icon-path]):not([fill='none']), + .#{$prefix}--btn--ghost.#{$prefix}--btn--icon-only .#{$prefix}--btn__icon { + @include high-contrast-mode('icon-fill'); + } } @include exports('button') { diff --git a/packages/styles/scss/components/button/_button.scss b/packages/styles/scss/components/button/_button.scss index 6b32ccdae45b..d89b56c32fc1 100644 --- a/packages/styles/scss/components/button/_button.scss +++ b/packages/styles/scss/components/button/_button.scss @@ -525,4 +525,13 @@ .#{$prefix}--btn:focus { @include high-contrast-mode('focus'); } + + // Windows HCM fix + // stylelint-disable-next-line no-duplicate-selectors + .#{$prefix}--btn--ghost.#{$prefix}--btn--icon-only + .#{$prefix}--btn__icon + path:not([data-icon-path]):not([fill='none']), + .#{$prefix}--btn--ghost.#{$prefix}--btn--icon-only .#{$prefix}--btn__icon { + @include high-contrast-mode('icon-fill'); + } } From 84de2dc35cb337b9e7fd60e7fe0535449ae730ce Mon Sep 17 00:00:00 2001 From: Taylor Jones <tay1orjones@users.noreply.github.com> Date: Wed, 20 Oct 2021 15:41:41 -0500 Subject: [PATCH 30/35] feat(multiselect): allow disabled listbox items (#9859) * feat(multiselect): allow disabled listbox items * fix(listbox): use disabled-02 instead of disabled-03 for items Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../MultiSelect/MultiSelect.stories.js | 3 +- .../src/components/list-box/_list-box.scss | 28 +++++++++++++++++++ .../MultiSelect/MultiSelect-story.js | 3 +- .../src/components/MultiSelect/MultiSelect.js | 1 + .../scss/components/list-box/_list-box.scss | 28 +++++++++++++++++++ 5 files changed, 61 insertions(+), 2 deletions(-) diff --git a/packages/carbon-react/src/components/MultiSelect/MultiSelect.stories.js b/packages/carbon-react/src/components/MultiSelect/MultiSelect.stories.js index ee8df2d982fd..d30f81f1ca0b 100644 --- a/packages/carbon-react/src/components/MultiSelect/MultiSelect.stories.js +++ b/packages/carbon-react/src/components/MultiSelect/MultiSelect.stories.js @@ -20,7 +20,8 @@ const items = [ }, { id: 'downshift-1-item-2', - text: 'Option 3', + text: 'Option 3 - a disabled item', + disabled: true, }, { id: 'downshift-1-item-3', diff --git a/packages/components/src/components/list-box/_list-box.scss b/packages/components/src/components/list-box/_list-box.scss index 32cb93a25edb..61b22c191879 100644 --- a/packages/components/src/components/list-box/_list-box.scss +++ b/packages/components/src/components/list-box/_list-box.scss @@ -658,6 +658,34 @@ $list-box-menu-width: rem(300px); color: $disabled-02; } + .#{$prefix}--list-box__menu-item[disabled], + .#{$prefix}--list-box__menu-item[disabled] *, + .#{$prefix}--list-box__menu-item[disabled]:hover { + color: $disabled-02; + cursor: not-allowed; + outline: none; + } + + .#{$prefix}--list-box__menu-item[disabled]:hover { + background-color: revert; + } + + .#{$prefix}--list-box__menu-item[disabled] + .#{$prefix}--checkbox-label::before { + border-color: $disabled-02; + } + + .#{$prefix}--list-box__menu-item[disabled] + .#{$prefix}--list-box__menu-item__option { + border-top-color: $ui-03; + } + + .#{$prefix}--list-box__menu-item[disabled]:hover + + .#{$prefix}--list-box__menu-item + .#{$prefix}--list-box__menu-item__option { + border-top-color: $ui-03; + } + .#{$prefix}--list-box.#{$prefix}--list-box--inline .#{$prefix}--list-box__menu-item__option { margin: 0 $carbon--spacing-03; diff --git a/packages/react/src/components/MultiSelect/MultiSelect-story.js b/packages/react/src/components/MultiSelect/MultiSelect-story.js index 7b6189191402..5872c25c574d 100644 --- a/packages/react/src/components/MultiSelect/MultiSelect-story.js +++ b/packages/react/src/components/MultiSelect/MultiSelect-story.js @@ -32,7 +32,8 @@ const items = [ }, { id: 'downshift-1-item-2', - text: 'Option 3', + text: 'Option 3 - a disabled item', + disabled: true, }, { id: 'downshift-1-item-3', diff --git a/packages/react/src/components/MultiSelect/MultiSelect.js b/packages/react/src/components/MultiSelect/MultiSelect.js index 1f38ef456a2c..4524192e85e4 100644 --- a/packages/react/src/components/MultiSelect/MultiSelect.js +++ b/packages/react/src/components/MultiSelect/MultiSelect.js @@ -282,6 +282,7 @@ const MultiSelect = React.forwardRef(function MultiSelect( // we don't want Downshift to set aria-selected for us // we also don't want to set 'false' for reader verbosity's sake ['aria-selected']: isChecked ? true : null, + disabled: item?.disabled, }); const itemText = itemToString(item); const isChecked = diff --git a/packages/styles/scss/components/list-box/_list-box.scss b/packages/styles/scss/components/list-box/_list-box.scss index 797fa331cdec..c3e863d32326 100644 --- a/packages/styles/scss/components/list-box/_list-box.scss +++ b/packages/styles/scss/components/list-box/_list-box.scss @@ -668,6 +668,34 @@ $list-box-menu-width: rem(300px); color: $text-disabled; } + .#{$prefix}--list-box__menu-item[disabled], + .#{$prefix}--list-box__menu-item[disabled] *, + .#{$prefix}--list-box__menu-item[disabled]:hover { + color: $text-disabled; + cursor: not-allowed; + outline: none; + } + + .#{$prefix}--list-box__menu-item[disabled]:hover { + background-color: revert; + } + + .#{$prefix}--list-box__menu-item[disabled] + .#{$prefix}--checkbox-label::before { + border-color: $text-disabled; + } + + .#{$prefix}--list-box__menu-item[disabled] + .#{$prefix}--list-box__menu-item__option { + border-top-color: $border-subtle; + } + + .#{$prefix}--list-box__menu-item[disabled]:hover + + .#{$prefix}--list-box__menu-item + .#{$prefix}--list-box__menu-item__option { + border-top-color: $border-subtle; + } + .#{$prefix}--list-box.#{$prefix}--list-box--inline .#{$prefix}--list-box__menu-item__option { margin: 0 $spacing-03; From 559412c9ade325337d1bfb9f0e995abdab853ddf Mon Sep 17 00:00:00 2001 From: "@RianTavaresOn" <rian.tavares@live.com> Date: Thu, 21 Oct 2021 12:15:30 -0300 Subject: [PATCH 31/35] feat(HeaderMenu): include isCurrentPage props to HeaderMenu component (#9785) * feat(HeaderMenu): include isCurrentPage props to HeaderMenu component set HeaderMenu as active when selected, contribute to the UX and accessibility * chore: update storybook to show example of isCurrentPage on sub-link Co-authored-by: Rian Tavares <rian.tavares@ibm.com> Co-authored-by: Taylor Jones <taylor.jones826@gmail.com> --- .all-contributorsrc | 10 ++++++++++ README.md | 1 + .../src/components/ui-shell/_header.scss | 19 +++++++++++++++++++ .../src/components/UIShell/HeaderMenu.js | 8 +++++++- .../src/components/UIShell/UIShell-story.js | 10 +++++----- .../components/ui-shell/header/_header.scss | 19 +++++++++++++++++++ 6 files changed, 61 insertions(+), 6 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 438d1bb8bd25..92e7b8f4fbf8 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -802,6 +802,16 @@ "code" ] }, + { + "login": "RianTavares", + "name": "@RianTavaresOn", + "avatar_url": "https://avatars.githubusercontent.com/u/8935295?v=4", + "profile": "https://riantavares.github.io/", + "contributions": [ + "code", + "design" + ] + }, { "login": "ColbyJohnIBM", "name": "ColbyJohnIBM", diff --git a/README.md b/README.md index 935208018c02..a3911db05b94 100644 --- a/README.md +++ b/README.md @@ -187,6 +187,7 @@ check out our [Contributing Guide](/.github/CONTRIBUTING.md) and our <td align="center"><a href="https://github.com/adamalston"><img src="https://avatars.githubusercontent.com/u/18297826?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Adam Alston</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=adamalston" title="Documentation">📖</a></td> <td align="center"><a href="https://github.com/Kiittyka"><img src="https://avatars.githubusercontent.com/u/41021851?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Krithika S Udupa</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=Kiittyka" title="Documentation">📖</a></td> <td align="center"><a href="https://github.com/egriff38"><img src="https://avatars.githubusercontent.com/u/6627718?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Eshin Griffith</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=egriff38" title="Code">💻</a></td> + <td align="center"><a href="https://riantavares.github.io/"><img src="https://avatars.githubusercontent.com/u/8935295?v=4?s=100" width="100px;" alt=""/><br /><sub><b>@RianTavaresOn</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=RianTavares" title="Code">💻</a> <a href="#design-RianTavares" title="Design">🎨</a></td> <td align="center"><a href="https://github.com/ColbyJohnIBM"><img src="https://avatars.githubusercontent.com/u/19613692?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ColbyJohnIBM</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=ColbyJohnIBM" title="Code">💻</a></td> </tr> </table> diff --git a/packages/components/src/components/ui-shell/_header.scss b/packages/components/src/components/ui-shell/_header.scss index 22e5f21f5b34..77118b94f71b 100644 --- a/packages/components/src/components/ui-shell/_header.scss +++ b/packages/components/src/components/ui-shell/_header.scss @@ -245,6 +245,25 @@ position: relative; } + .#{$prefix}--header__submenu--current::after { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + width: 100%; + border-bottom: 3px solid $border-interactive; + content: ''; + } + + .#{$prefix}--header__submenu--current:focus { + border: 2px solid $focus; + } + + .#{$prefix}--header__submenu--current:focus::after { + border: 0; + } + .#{$prefix}--header__menu-title[aria-haspopup='true'] { position: relative; } diff --git a/packages/react/src/components/UIShell/HeaderMenu.js b/packages/react/src/components/UIShell/HeaderMenu.js index ac49ec9d930f..0f7792aec7c7 100644 --- a/packages/react/src/components/UIShell/HeaderMenu.js +++ b/packages/react/src/components/UIShell/HeaderMenu.js @@ -160,6 +160,7 @@ class HeaderMenu extends React.Component { render() { const prefix = this.context; const { + isCurrentPage, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, className: customClassName, @@ -174,7 +175,12 @@ class HeaderMenu extends React.Component { 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, }; - const className = cx(`${prefix}--header__submenu`, customClassName); + const className = cx({ + [`${prefix}--header__submenu`]: true, + [customClassName]: true, + [`${prefix}--header__submenu--current`]: isCurrentPage, + }); + // Notes on eslint comments and based on the examples in: // https://www.w3.org/TR/wai-aria-practices/examples/menubar/menubar-1/menubar-1.html# // - The focus is handled by the <a> menuitem, onMouseOver is for mouse diff --git a/packages/react/src/components/UIShell/UIShell-story.js b/packages/react/src/components/UIShell/UIShell-story.js index f202fbce11f6..abf309dcb68c 100644 --- a/packages/react/src/components/UIShell/UIShell-story.js +++ b/packages/react/src/components/UIShell/UIShell-story.js @@ -203,14 +203,14 @@ export const HeaderBaseWNavigation = withReadme(readme, () => ( [Platform] </HeaderName> <HeaderNavigation aria-label="IBM [Platform]"> - <HeaderMenuItem isCurrentPage href="#"> - Link 1 - </HeaderMenuItem> + <HeaderMenuItem href="#">Link 1</HeaderMenuItem> <HeaderMenuItem href="#">Link 2</HeaderMenuItem> <HeaderMenuItem href="#">Link 3</HeaderMenuItem> - <HeaderMenu aria-label="Link 4" menuLinkName="Link 4"> + <HeaderMenu aria-label="Link 4" menuLinkName="Link 4" isCurrentPage> <HeaderMenuItem href="#">Sub-link 1</HeaderMenuItem> - <HeaderMenuItem href="#">Sub-link 2</HeaderMenuItem> + <HeaderMenuItem href="#" isCurrentPage> + Sub-link 2 + </HeaderMenuItem> <HeaderMenuItem href="#">Sub-link 3</HeaderMenuItem> </HeaderMenu> </HeaderNavigation> diff --git a/packages/styles/scss/components/ui-shell/header/_header.scss b/packages/styles/scss/components/ui-shell/header/_header.scss index 3809b2602699..b88dcda6f355 100644 --- a/packages/styles/scss/components/ui-shell/header/_header.scss +++ b/packages/styles/scss/components/ui-shell/header/_header.scss @@ -269,6 +269,25 @@ position: relative; } + .#{$prefix}--header__submenu--current::after { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + width: 100%; + border-bottom: 3px solid $border-interactive; + content: ''; + } + + .#{$prefix}--header__submenu--current:focus { + border: 2px solid $focus; + } + + .#{$prefix}--header__submenu--current:focus::after { + border: 0; + } + .#{$prefix}--header__menu-title[aria-haspopup='true'] { position: relative; } From a9c13fffe27b61c5662b785af0010489caa18ae1 Mon Sep 17 00:00:00 2001 From: Scott Strubberg <sstrubberg@protonmail.com> Date: Thu, 21 Oct 2021 12:21:41 -0500 Subject: [PATCH 32/35] feat(modal): deprecate iconDescription (#9828) * feat(modal): deprecate iconDescription new tests * feat(modal): update test co-authored: @aledavila * feat(modal): updated snappy * Update packages/react/src/components/Modal/Modal-test.js Co-authored-by: DAK <40970507+dakahn@users.noreply.github.com> * feat(modal): added test * feat(modal): updated snappy * feat(Modal): aria lable on the close icon * feat(Modal): updated wrapper test Co-authored-by: DAK <40970507+dakahn@users.noreply.github.com> --- .../__snapshots__/PublicAPI-test.js.snap | 5 +---- .../react/src/components/Modal/Modal-story.js | 1 - .../react/src/components/Modal/Modal-test.js | 17 ++++++----------- packages/react/src/components/Modal/Modal.js | 14 +++++++++----- .../__snapshots__/ModalWrapper-test.js.snap | 17 ++++++++++------- 5 files changed, 26 insertions(+), 28 deletions(-) diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index 6223d424aed7..bcf4df344ccc 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -3811,7 +3811,6 @@ Map { "Modal" => Object { "defaultProps": Object { "hasScrollingContent": false, - "iconDescription": "Close", "modalHeading": "", "modalLabel": "", "onKeyDown": [Function], @@ -3841,9 +3840,7 @@ Map { "hasScrollingContent": Object { "type": "bool", }, - "iconDescription": Object { - "type": "string", - }, + "iconDescription": [Function], "id": Object { "type": "string", }, diff --git a/packages/react/src/components/Modal/Modal-story.js b/packages/react/src/components/Modal/Modal-story.js index 61351855588c..86556df7f226 100644 --- a/packages/react/src/components/Modal/Modal-story.js +++ b/packages/react/src/components/Modal/Modal-story.js @@ -68,7 +68,6 @@ const props = { '[data-modal-primary-focus]' ), size: select('Size (size)', sizes, 'md'), - iconDescription: text('Close icon description (iconDescription)', 'Close'), onBlur: action('onBlur'), onClick: action('onClick'), onFocus: action('onFocus'), diff --git a/packages/react/src/components/Modal/Modal-test.js b/packages/react/src/components/Modal/Modal-test.js index e860715e1db9..872974008ce9 100644 --- a/packages/react/src/components/Modal/Modal-test.js +++ b/packages/react/src/components/Modal/Modal-test.js @@ -47,19 +47,14 @@ describe('Modal', () => { expect(getModal(modal).props().id).toEqual('modal-1'); }); - it('has the expected default iconDescription', () => { - expect(mounted.props().iconDescription).toEqual('Close'); + it('should not place the svg icon in the accessibility tree', () => { + const ariaHidden = mounted.find(Close20).props()['aria-hidden']; + expect(ariaHidden).toEqual('true'); }); - it('adds new iconDescription when passed via props', () => { - mounted.setProps({ iconDescription: 'new description' }); - expect(mounted.props().iconDescription).toEqual('new description'); - }); - - it('should have iconDescription match Icon component description prop', () => { - const description = mounted.find(Close20).props()['aria-label']; - const matches = mounted.props().iconDescription === description; - expect(matches).toEqual(true); + it("icon isn't a focusable tab stop", () => { + const icon = mounted.find(Close20).props().tabIndex; + expect(icon).toEqual('-1'); }); it('enables primary button by default', () => { diff --git a/packages/react/src/components/Modal/Modal.js b/packages/react/src/components/Modal/Modal.js index 012baa8e1216..66c61af0a479 100644 --- a/packages/react/src/components/Modal/Modal.js +++ b/packages/react/src/components/Modal/Modal.js @@ -80,7 +80,10 @@ export default class Modal extends Component { /** * Provide a description for "close" icon that can be read by screen readers */ - iconDescription: PropTypes.string, + iconDescription: deprecate( + PropTypes.string, + 'The iconDescription prop is no longer needed and can be safely removed. This prop will be removed in the next major release of Carbon.' + ), /** * Specify the DOM element ID of the top-level node. @@ -220,7 +223,6 @@ export default class Modal extends Component { primaryButtonDisabled: false, onKeyDown: () => {}, passiveModal: false, - iconDescription: 'Close', modalHeading: '', modalLabel: '', preventCloseOnClickOutside: false, @@ -417,11 +419,13 @@ export default class Modal extends Component { className={this.modalCloseButtonClass} type="button" onClick={onRequestClose} - title={iconDescription} - aria-label={iconDescription} + title={ariaLabel ? ariaLabel : iconDescription} + aria-label={ariaLabel ? ariaLabel : iconDescription} ref={this.button}> <Close20 - aria-label={iconDescription} + aria-hidden="true" + aria-label="close" + tabIndex="-1" className={`${this.modalCloseButtonClass}__icon`} /> </button> diff --git a/packages/react/src/components/ModalWrapper/__snapshots__/ModalWrapper-test.js.snap b/packages/react/src/components/ModalWrapper/__snapshots__/ModalWrapper-test.js.snap index deffd66f96e6..c01fc67ed101 100644 --- a/packages/react/src/components/ModalWrapper/__snapshots__/ModalWrapper-test.js.snap +++ b/packages/react/src/components/ModalWrapper/__snapshots__/ModalWrapper-test.js.snap @@ -56,7 +56,6 @@ exports[`ModalWrapper should render 1`] = ` <Modal aria-label="test modal" hasScrollingContent={false} - iconDescription="Close" id="modal" modalHeading="Transactional Modal" modalLabel="Test Modal Label" @@ -110,34 +109,38 @@ exports[`ModalWrapper should render 1`] = ` Transactional Modal </h3> <button - aria-label="Close" className="bx--modal-close" onClick={[Function]} - title="Close" type="button" > <ForwardRef(Close20) - aria-label="Close" + aria-hidden="true" + aria-label="close" className="bx--modal-close__icon" + tabIndex="-1" > <Icon - aria-label="Close" + aria-hidden="true" + aria-label="close" className="bx--modal-close__icon" fill="currentColor" height={20} preserveAspectRatio="xMidYMid meet" + tabIndex="-1" viewBox="0 0 32 32" width={20} xmlns="http://www.w3.org/2000/svg" > <svg - aria-label="Close" + aria-hidden="true" + aria-label="close" className="bx--modal-close__icon" fill="currentColor" - focusable="false" + focusable="true" height={20} preserveAspectRatio="xMidYMid meet" role="img" + tabIndex="-1" viewBox="0 0 32 32" width={20} xmlns="http://www.w3.org/2000/svg" From 4a95fb77ba8a8a585aa627261462cc00d185e331 Mon Sep 17 00:00:00 2001 From: Alessandra Davila <aledavila@ibm.com> Date: Thu, 21 Oct 2021 13:17:47 -0500 Subject: [PATCH 33/35] fix(button): remove tooltip on click on button in and tooltip icon (#9882) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- packages/react/src/components/Button/Button.js | 1 + packages/react/src/components/TooltipIcon/TooltipIcon.js | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/react/src/components/Button/Button.js b/packages/react/src/components/Button/Button.js index be79fd9d398b..368a182bf6d4 100644 --- a/packages/react/src/components/Button/Button.js +++ b/packages/react/src/components/Button/Button.js @@ -106,6 +106,7 @@ const Button = React.forwardRef(function Button( const handleClick = (evt) => { // Prevent clicks on the tooltip from triggering the button click event + setAllowTooltipVisibility(false); if (evt.target === tooltipRef.current) { evt.preventDefault(); return; diff --git a/packages/react/src/components/TooltipIcon/TooltipIcon.js b/packages/react/src/components/TooltipIcon/TooltipIcon.js index 2a63b180dd51..cfc27662a3b7 100644 --- a/packages/react/src/components/TooltipIcon/TooltipIcon.js +++ b/packages/react/src/components/TooltipIcon/TooltipIcon.js @@ -98,6 +98,7 @@ const TooltipIcon = ({ }; const handleClick = (evt) => { + setAllowTooltipVisibility(false); // Prevent clicks on the tooltip from triggering the button click event if (evt.target === tooltipRef.current) { evt.preventDefault(); From 22cdc872c7824af511e09b38ea029715b1a49dd3 Mon Sep 17 00:00:00 2001 From: Abbey Hart <abbeyhrt@gmail.com> Date: Thu, 21 Oct 2021 14:11:12 -0500 Subject: [PATCH 34/35] feat(react,carbon-react): add layer stories (#9838) * feat(react,carbon-react): add layer stories and deprecate light prop * chore(react): update deprecation message for lsitbox light prop * chore(react): remove deprecation warning for light prop * chore(react): remove accidental change to content switcher Co-authored-by: Alessandra Davila <aledavila@ibm.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../src/components/Select/Select.stories.js | 58 +++++++ .../components/TextArea/TextArea.stories.js | 36 ++++ .../components/TextInput/TextInput.stories.js | 31 +++- .../src/components/Tile/Tile.stories.js | 156 ++++++++++++++++++ .../TimePicker/TimePicker.stories.js | 42 +++++ .../ContentSwitcher/ContentSwitcher.js | 2 +- .../react/src/components/ListBox/ListBox.js | 3 +- .../src/components/RadioTile/RadioTile.js | 3 +- .../react/src/components/Select/Select.js | 3 +- .../react/src/components/TextArea/TextArea.js | 3 +- .../TextInput/ControlledPasswordInput.js | 3 +- .../src/components/TextInput/PasswordInput.js | 3 +- .../src/components/TextInput/TextInput.js | 3 +- packages/react/src/components/Tile/Tile.js | 2 + .../src/components/TimePicker/TimePicker.js | 3 +- 15 files changed, 341 insertions(+), 10 deletions(-) diff --git a/packages/carbon-react/src/components/Select/Select.stories.js b/packages/carbon-react/src/components/Select/Select.stories.js index 057fb8ff05a7..779e3497c1ae 100644 --- a/packages/carbon-react/src/components/Select/Select.stories.js +++ b/packages/carbon-react/src/components/Select/Select.stories.js @@ -12,6 +12,7 @@ import { SelectItemGroup, SelectSkeleton, } from 'carbon-components-react'; +import { Layer } from '../Layer'; export default { title: 'Components/Select', @@ -91,3 +92,60 @@ export const _Skeleton = () => ( <SelectSkeleton /> </div> ); + +export const withLayer = () => { + return ( + <> + <Select + id="select-1" + defaultValue="placeholder-item" + labelText="" + helperText="First layer"> + <SelectItem + disabled + hidden + value="placeholder-item" + text="Choose an option" + /> + <SelectItem value="option-1" text="Option 1" /> + <SelectItem value="option-2" text="Option 2" /> + </Select> + <Layer> + <Select + id="select-1" + defaultValue="placeholder-item" + labelText="" + helperText=" Second layer"> + <SelectItem + disabled + hidden + value="placeholder-item" + text="Choose an option" + /> + <SelectItem value="option-1" text="Option 1" /> + <SelectItem value="option-2" text="Option 2" /> + <SelectItem value="option-3" text="Option 3" /> + <SelectItem value="option-4" text="Option 4" /> + </Select> + <Layer> + <Select + id="select-1" + defaultValue="placeholder-item" + labelText="" + helperText="Third layer"> + <SelectItem + disabled + hidden + value="placeholder-item" + text="Choose an option" + /> + <SelectItem value="option-1" text="Option 1" /> + <SelectItem value="option-2" text="Option 2" /> + <SelectItem value="option-3" text="Option 3" /> + <SelectItem value="option-4" text="Option 4" /> + </Select> + </Layer> + </Layer> + </> + ); +}; diff --git a/packages/carbon-react/src/components/TextArea/TextArea.stories.js b/packages/carbon-react/src/components/TextArea/TextArea.stories.js index 001a32aba115..3992c2be6984 100644 --- a/packages/carbon-react/src/components/TextArea/TextArea.stories.js +++ b/packages/carbon-react/src/components/TextArea/TextArea.stories.js @@ -7,6 +7,7 @@ import React from 'react'; import { TextArea, TextAreaSkeleton } from 'carbon-components-react'; +import { Layer } from '../Layer'; export default { title: 'Components/TextArea', @@ -29,4 +30,39 @@ export const Default = () => ( /> ); +export const withLayer = () => { + return ( + <> + <TextArea + labelText="First layer" + helperText="Optional helper text" + placeholder="Placeholder text" + cols={50} + rows={4} + id="text-area-1" + /> + <Layer> + <TextArea + labelText="Second layer" + helperText="Optional helper text" + placeholder="Placeholder text" + cols={50} + rows={4} + id="text-area-1" + /> + <Layer> + <TextArea + labelText="Third layer" + helperText="Optional helper text" + placeholder="Placeholder text" + cols={50} + rows={4} + id="text-area-1" + /> + </Layer> + </Layer> + </> + ); +}; + export const Skeleton = () => <TextAreaSkeleton />; diff --git a/packages/carbon-react/src/components/TextInput/TextInput.stories.js b/packages/carbon-react/src/components/TextInput/TextInput.stories.js index 99dfbe0852a1..efb9622a7cf6 100644 --- a/packages/carbon-react/src/components/TextInput/TextInput.stories.js +++ b/packages/carbon-react/src/components/TextInput/TextInput.stories.js @@ -7,7 +7,7 @@ import React from 'react'; import { TextInput, TextInputSkeleton, FluidForm } from '.'; - +import { Layer } from '../Layer'; import mdx from './TextInput.mdx'; export default { @@ -54,4 +54,33 @@ export const TogglePasswordVisibility = () => { ); }; +export const withLayer = () => { + return ( + <> + <TextInput + type="text" + labelText="First layer" + defaultValue="This is not a default value" + helperText="Optional help text" + /> + <Layer> + <TextInput + type="text" + labelText="Second layer" + defaultValue="This is not a default value" + helperText="Optional help text" + /> + <Layer> + <TextInput + type="text" + labelText="Third layer" + defaultValue="This is not a default value" + helperText="Optional help text" + /> + </Layer> + </Layer> + </> + ); +}; + export const Skeleton = () => <TextInputSkeleton />; diff --git a/packages/carbon-react/src/components/Tile/Tile.stories.js b/packages/carbon-react/src/components/Tile/Tile.stories.js index 1f567fab6569..44f9fc01a8ad 100644 --- a/packages/carbon-react/src/components/Tile/Tile.stories.js +++ b/packages/carbon-react/src/components/Tile/Tile.stories.js @@ -18,6 +18,7 @@ import { TileAboveTheFoldContent, TileBelowTheFoldContent, } from 'carbon-components-react'; +import { Layer } from '../Layer'; import './tile-story.scss'; export default { @@ -47,10 +48,53 @@ export const Default = () => { ); }; +export const DefaultWithLayer = () => { + return ( + <> + <Tile> + First layer + <br /> + <br /> + <Link href="https://www.carbondesignsystem.com">Link</Link> + </Tile> + <Layer> + <Tile> + Second layer + <br /> + <br /> + <Link href="https://www.carbondesignsystem.com">Link</Link> + </Tile> + <Layer> + <Tile> + Third layer + <br /> + <br /> + <Link href="https://www.carbondesignsystem.com">Link</Link> + </Tile> + </Layer> + </Layer> + </> + ); +}; + export const Clickable = () => { return <ClickableTile>Clickable Tile</ClickableTile>; }; +export const ClickableWithLayer = () => { + return ( + <> + <ClickableTile>First layer</ClickableTile> + <Layer> + <ClickableTile>Second layer</ClickableTile> + <Layer> + <ClickableTile>Third layer</ClickableTile> + </Layer> + </Layer> + </> + ); +}; + export const MultiSelect = () => { return ( <div role="group" aria-label="selectable tiles"> @@ -67,6 +111,24 @@ export const MultiSelect = () => { ); }; +export const SelectableWithLayer = () => { + <> + <SelectableTile id="tile-3" name="tiles"> + First layer + </SelectableTile> + <Layer> + <SelectableTile id="tile-3" name="tiles"> + Second layer + </SelectableTile> + <Layer> + <SelectableTile id="tile-3" name="tiles"> + Third layer + </SelectableTile> + </Layer> + </Layer> + </>; +}; + export const Radio = () => { return ( <TileGroup @@ -86,6 +148,50 @@ export const Radio = () => { ); }; +export const RadioWithLayer = () => { + return ( + <> + <TileGroup + defaultSelected="default-selected" + legend="First layer" + name="radio tile group"> + <RadioTile value="standard" style={{ marginBottom: '.5rem' }}> + Option 1 + </RadioTile> + <RadioTile value="default-selected" id="tile-2"> + Option 2 + </RadioTile> + </TileGroup> + <Layer> + <TileGroup + defaultSelected="default-selected" + legend="Second Layer" + name="radio tile group"> + <RadioTile value="standard" style={{ marginBottom: '.5rem' }}> + Option 1 + </RadioTile> + <RadioTile value="default-selected" id="tile-2"> + Option 2 + </RadioTile> + </TileGroup> + <Layer> + <TileGroup + defaultSelected="default-selected" + legend="Third Layer" + name="radio tile group"> + <RadioTile value="standard" style={{ marginBottom: '.5rem' }}> + Option 1 + </RadioTile> + <RadioTile value="default-selected" id="tile-2"> + Option 2 + </RadioTile> + </TileGroup> + </Layer> + </Layer> + </> + ); +}; + export const Expandable = () => ( <ExpandableTile tileCollapsedIconText="Interact to Expand tile" @@ -101,3 +207,53 @@ export const Expandable = () => ( </TileBelowTheFoldContent> </ExpandableTile> ); + +export const ExpandableWithLayer = () => { + return ( + <> + <ExpandableTile + tileCollapsedIconText="Interact to Expand tile" + tileExpandedIconText="Interact to Collapse tile"> + <TileAboveTheFoldContent> + <div style={{ height: '200px' }}>First layer</div> + </TileAboveTheFoldContent> + <TileBelowTheFoldContent> + <div style={{ height: '400px' }}> + Below the fold content here + <TextInput id="test2" invalidText="A valid value is required" /> + </div> + </TileBelowTheFoldContent> + </ExpandableTile> + <Layer> + <ExpandableTile + tileCollapsedIconText="Interact to Expand tile" + tileExpandedIconText="Interact to Collapse tile"> + <TileAboveTheFoldContent> + <div style={{ height: '200px' }}>Second layer</div> + </TileAboveTheFoldContent> + <TileBelowTheFoldContent> + <div style={{ height: '400px' }}> + Below the fold content here + <TextInput id="test2" invalidText="A valid value is required" /> + </div> + </TileBelowTheFoldContent> + </ExpandableTile> + <Layer> + <ExpandableTile + tileCollapsedIconText="Interact to Expand tile" + tileExpandedIconText="Interact to Collapse tile"> + <TileAboveTheFoldContent> + <div style={{ height: '200px' }}>Third layer</div> + </TileAboveTheFoldContent> + <TileBelowTheFoldContent> + <div style={{ height: '400px' }}> + Below the fold content here + <TextInput id="test2" invalidText="A valid value is required" /> + </div> + </TileBelowTheFoldContent> + </ExpandableTile> + </Layer> + </Layer> + </> + ); +}; diff --git a/packages/carbon-react/src/components/TimePicker/TimePicker.stories.js b/packages/carbon-react/src/components/TimePicker/TimePicker.stories.js index 34ba3e473bb2..96ef1e5ebdc1 100644 --- a/packages/carbon-react/src/components/TimePicker/TimePicker.stories.js +++ b/packages/carbon-react/src/components/TimePicker/TimePicker.stories.js @@ -11,6 +11,7 @@ import { TimePickerSelect, SelectItem, } from 'carbon-components-react'; +import { Layer } from '../Layer'; // const props = { // timepicker: () => ({ @@ -77,3 +78,44 @@ export const Default = () => { </TimePicker> ); }; + +export const withLayer = () => { + return ( + <> + <TimePicker id="time-picker" labelText="First layer"> + <TimePickerSelect id="time-picker-select-1"> + <SelectItem value="AM" text="AM" /> + <SelectItem value="PM" text="PM" /> + </TimePickerSelect> + <TimePickerSelect id="time-picker-select-2"> + <SelectItem value="Time zone 1" text="Time zone 1" /> + <SelectItem value="Time zone 2" text="Time zone 2" /> + </TimePickerSelect> + </TimePicker> + <Layer> + <TimePicker id="time-picker" labelText="Second layer"> + <TimePickerSelect id="time-picker-select-1"> + <SelectItem value="AM" text="AM" /> + <SelectItem value="PM" text="PM" /> + </TimePickerSelect> + <TimePickerSelect id="time-picker-select-2"> + <SelectItem value="Time zone 1" text="Time zone 1" /> + <SelectItem value="Time zone 2" text="Time zone 2" /> + </TimePickerSelect> + </TimePicker> + <Layer> + <TimePicker id="time-picker" labelText="Third layer"> + <TimePickerSelect id="time-picker-select-1"> + <SelectItem value="AM" text="AM" /> + <SelectItem value="PM" text="PM" /> + </TimePickerSelect> + <TimePickerSelect id="time-picker-select-2"> + <SelectItem value="Time zone 1" text="Time zone 1" /> + <SelectItem value="Time zone 2" text="Time zone 2" /> + </TimePickerSelect> + </TimePicker> + </Layer> + </Layer> + </> + ); +}; diff --git a/packages/react/src/components/ContentSwitcher/ContentSwitcher.js b/packages/react/src/components/ContentSwitcher/ContentSwitcher.js index cd044d232ea2..85aa2b0a70cc 100644 --- a/packages/react/src/components/ContentSwitcher/ContentSwitcher.js +++ b/packages/react/src/components/ContentSwitcher/ContentSwitcher.js @@ -8,9 +8,9 @@ import PropTypes from 'prop-types'; import React from 'react'; import classNames from 'classnames'; +import deprecate from '../../prop-types/deprecate'; import { composeEventHandlers } from '../../tools/events'; import { getNextIndex, matches, keys } from '../../internal/keyboard'; -import deprecate from '../../prop-types/deprecate'; import { PrefixContext } from '../../internal/usePrefix'; export default class ContentSwitcher extends React.Component { diff --git a/packages/react/src/components/ListBox/ListBox.js b/packages/react/src/components/ListBox/ListBox.js index 0fe99aa963eb..29f3345b3885 100644 --- a/packages/react/src/components/ListBox/ListBox.js +++ b/packages/react/src/components/ListBox/ListBox.js @@ -112,7 +112,8 @@ ListBox.propTypes = { isOpen: PropTypes.bool, /** - * Specify if the control should use the light variant + * `true` to use the light version. For use on $ui-01 backgrounds only. + * Don't use this to make tile background color same as container background color. */ light: PropTypes.bool, diff --git a/packages/react/src/components/RadioTile/RadioTile.js b/packages/react/src/components/RadioTile/RadioTile.js index 3826de9dec2b..4dbd06a81392 100644 --- a/packages/react/src/components/RadioTile/RadioTile.js +++ b/packages/react/src/components/RadioTile/RadioTile.js @@ -120,7 +120,8 @@ RadioTile.propTypes = { id: PropTypes.string, /** - * `true` to use the light version. + * `true` to use the light version. For use on $ui-01 backgrounds only. + * Don't use this to make tile background color same as container background color. */ light: PropTypes.bool, diff --git a/packages/react/src/components/Select/Select.js b/packages/react/src/components/Select/Select.js index bf31c3ace004..c85cd368dfee 100644 --- a/packages/react/src/components/Select/Select.js +++ b/packages/react/src/components/Select/Select.js @@ -218,7 +218,8 @@ Select.propTypes = { labelText: PropTypes.node, /** - * Specify whether you want the light version of this control + * `true` to use the light version. For use on $ui-01 backgrounds only. + * Don't use this to make tile background color same as container background color. */ light: PropTypes.bool, diff --git a/packages/react/src/components/TextArea/TextArea.js b/packages/react/src/components/TextArea/TextArea.js index 7382c174bbad..ea3b76c23348 100644 --- a/packages/react/src/components/TextArea/TextArea.js +++ b/packages/react/src/components/TextArea/TextArea.js @@ -171,7 +171,8 @@ TextArea.propTypes = { labelText: PropTypes.node.isRequired, /** - * Specify whether you want the light version of this control + * `true` to use the light version. For use on $ui-01 backgrounds only. + * Don't use this to make tile background color same as container background color. */ light: PropTypes.bool, diff --git a/packages/react/src/components/TextInput/ControlledPasswordInput.js b/packages/react/src/components/TextInput/ControlledPasswordInput.js index c62434e654dd..17a11ac87028 100644 --- a/packages/react/src/components/TextInput/ControlledPasswordInput.js +++ b/packages/react/src/components/TextInput/ControlledPasswordInput.js @@ -208,7 +208,8 @@ ControlledPasswordInput.propTypes = { labelText: PropTypes.node.isRequired, /** - * Specify light version or default version of this control + * `true` to use the light version. For use on $ui-01 backgrounds only. + * Don't use this to make tile background color same as container background color. */ light: PropTypes.bool, diff --git a/packages/react/src/components/TextInput/PasswordInput.js b/packages/react/src/components/TextInput/PasswordInput.js index c593fb0c6f26..6a9e0134ba02 100644 --- a/packages/react/src/components/TextInput/PasswordInput.js +++ b/packages/react/src/components/TextInput/PasswordInput.js @@ -264,7 +264,8 @@ PasswordInput.propTypes = { labelText: PropTypes.node.isRequired, /** - * Specify light version or default version of this control + * `true` to use the light version. For use on $ui-01 backgrounds only. + * Don't use this to make tile background color same as container background color. */ light: PropTypes.bool, diff --git a/packages/react/src/components/TextInput/TextInput.js b/packages/react/src/components/TextInput/TextInput.js index 8ce8d7b0f3e9..fc943e010f58 100644 --- a/packages/react/src/components/TextInput/TextInput.js +++ b/packages/react/src/components/TextInput/TextInput.js @@ -235,7 +235,8 @@ TextInput.propTypes = { labelText: PropTypes.node.isRequired, /** - * `true` to use the light version. + * `true` to use the light version. For use on $ui-01 backgrounds only. + * Don't use this to make tile background color same as container background color. */ light: PropTypes.bool, diff --git a/packages/react/src/components/Tile/Tile.js b/packages/react/src/components/Tile/Tile.js index d10221dbb688..ee3d2d4ab023 100644 --- a/packages/react/src/components/Tile/Tile.js +++ b/packages/react/src/components/Tile/Tile.js @@ -316,6 +316,7 @@ export function SelectableTile(props) { </> ); } + SelectableTile.defaultProps = { value: 'value', title: 'title', @@ -326,6 +327,7 @@ SelectableTile.defaultProps = { onChange: () => {}, onKeyDown: () => {}, }; + SelectableTile.propTypes = { /** * The child nodes. diff --git a/packages/react/src/components/TimePicker/TimePicker.js b/packages/react/src/components/TimePicker/TimePicker.js index 46d7e8e980ce..774e9c90f8b1 100644 --- a/packages/react/src/components/TimePicker/TimePicker.js +++ b/packages/react/src/components/TimePicker/TimePicker.js @@ -59,7 +59,8 @@ export default class TimePicker extends Component { labelText: PropTypes.node, /** - * `true` to use the light version. + * `true` to use the light version. For use on $ui-01 backgrounds only. + * Don't use this to make tile background color same as container background color. */ light: PropTypes.bool, From f012e36f1c2439d8717305969269f1d70b7dfde6 Mon Sep 17 00:00:00 2001 From: Taylor Jones <tay1orjones@users.noreply.github.com> Date: Thu, 21 Oct 2021 14:37:42 -0500 Subject: [PATCH 35/35] chore(fileuploaderbutton): remove unused `listFiles` prop (#9915) * chore(fileuploaderbutton): remove unused prop * chore: update public api snap Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../react/__tests__/__snapshots__/PublicAPI-test.js.snap | 3 --- .../react/src/components/FileUploader/FileUploaderButton.js | 6 ------ 2 files changed, 9 deletions(-) diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index bcf4df344ccc..6baee82c07d6 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -2907,9 +2907,6 @@ Map { "labelText": Object { "type": "node", }, - "listFiles": Object { - "type": "bool", - }, "multiple": Object { "type": "bool", }, diff --git a/packages/react/src/components/FileUploader/FileUploaderButton.js b/packages/react/src/components/FileUploader/FileUploaderButton.js index e5e4804a76a8..7cccdb3e44f4 100644 --- a/packages/react/src/components/FileUploader/FileUploaderButton.js +++ b/packages/react/src/components/FileUploader/FileUploaderButton.js @@ -141,12 +141,6 @@ FileUploaderButton.propTypes = { */ labelText: PropTypes.node, - /** - * Specify whether you want the component to list the files that have been - * submitted to be uploaded - */ - listFiles: PropTypes.bool, - /** * Specify if the component should accept multiple files to upload */