From cf5dc882f29bcaf9f00a4af5765bf052d19d0a36 Mon Sep 17 00:00:00 2001 From: Alison Joseph Date: Wed, 20 Nov 2024 09:25:33 -0600 Subject: [PATCH] feat(checkbox): replace slug prop with decorator (#18040) * feat(checkbox): replace slug prop with decorator * chore: update tests * chore: add test * chore: typo * Update packages/react/src/components/Checkbox/Checkbox.tsx Co-authored-by: Ariella Gilmore * Update packages/react/src/components/CheckboxGroup/CheckboxGroup.tsx Co-authored-by: Ariella Gilmore * chore: cleanup styles * feat: update checkbox decorator styles * chore: typo * chore: cleanup styles * chore: format * chore: revert storybook test changes * chore: typo --------- Co-authored-by: Ariella Gilmore Co-authored-by: Guilherme Datilio Ribeiro --- .../__snapshots__/PublicAPI-test.js.snap | 14 ++--- .../components/Checkbox/Checkbox.stories.js | 10 ++-- .../src/components/Checkbox/Checkbox.tsx | 54 +++++++++++++++---- .../Checkbox/__tests__/Checkbox-test.js | 34 +++++++++++- .../CheckboxGroup/CheckboxGroup-test.js | 19 ++++++- .../CheckboxGroup/CheckboxGroup.tsx | 52 ++++++++++++++---- .../scss/components/checkbox/_checkbox.scss | 31 ++++++++++- 7 files changed, 179 insertions(+), 35 deletions(-) diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index 58a02b6cce38..8ca88ff17d11 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -613,6 +613,9 @@ Map { "className": Object { "type": "string", }, + "decorator": Object { + "type": "node", + }, "defaultChecked": Object { "type": "bool", }, @@ -648,9 +651,7 @@ Map { "readOnly": Object { "type": "bool", }, - "slug": Object { - "type": "node", - }, + "slug": [Function], "title": Object { "type": "string", }, @@ -671,6 +672,9 @@ Map { "className": Object { "type": "string", }, + "decorator": Object { + "type": "node", + }, "helperText": Object { "type": "node", }, @@ -699,9 +703,7 @@ Map { "readOnly": Object { "type": "bool", }, - "slug": Object { - "type": "node", - }, + "slug": [Function], "warn": Object { "type": "bool", }, diff --git a/packages/react/src/components/Checkbox/Checkbox.stories.js b/packages/react/src/components/Checkbox/Checkbox.stories.js index ba8aff5eccee..1c6da060394c 100644 --- a/packages/react/src/components/Checkbox/Checkbox.stories.js +++ b/packages/react/src/components/Checkbox/Checkbox.stories.js @@ -124,7 +124,7 @@ const AILabelFunc = (kind) => ( export const withAILabel = () => (
- + @@ -134,12 +134,12 @@ export const withAILabel = () => ( @@ -148,12 +148,12 @@ export const withAILabel = () => ( diff --git a/packages/react/src/components/Checkbox/Checkbox.tsx b/packages/react/src/components/Checkbox/Checkbox.tsx index 277198c75c99..1ed09ec09e91 100644 --- a/packages/react/src/components/Checkbox/Checkbox.tsx +++ b/packages/react/src/components/Checkbox/Checkbox.tsx @@ -6,9 +6,10 @@ */ import PropTypes from 'prop-types'; -import React, { ReactNode } from 'react'; +import React, { ReactElement, ReactNode } from 'react'; import classNames from 'classnames'; import { Text } from '../Text'; +import deprecate from '../../prop-types/deprecate'; import { usePrefix } from '../../internal/usePrefix'; import { WarningFilled, WarningAltFilled } from '@carbon/icons-react'; import { useId } from '../../internal/useId'; @@ -32,6 +33,11 @@ export interface CheckboxProps */ labelText: NonNullable; + /** + * **Experimental**: Provide a `decorator` component to be rendered inside the `Checkbox` component + */ + decorator?: ReactNode; + /** * Specify whether the underlying input should be checked by default */ @@ -68,6 +74,7 @@ export interface CheckboxProps invalidText?: ReactNode; /** + * @deprecated please use decorator instead. * **Experimental**: Provide a `Slug` component to be rendered inside the `Checkbox` component */ slug?: ReactNode; @@ -102,6 +109,7 @@ const Checkbox = React.forwardRef( ( { className, + decorator, helperText, id, labelText, @@ -146,18 +154,30 @@ const Checkbox = React.forwardRef( [`${prefix}--checkbox-wrapper--invalid`]: !readOnly && invalid, [`${prefix}--checkbox-wrapper--warning`]: showWarning, [`${prefix}--checkbox-wrapper--slug`]: slug, + [`${prefix}--checkbox-wrapper--decorator`]: decorator, } ); const innerLabelClasses = classNames(`${prefix}--checkbox-label-text`, { [`${prefix}--visually-hidden`]: hideLabel, }); - let normalizedSlug; - if (slug && React.isValidElement(slug)) { - const size = slug.props?.['kind'] === 'inline' ? 'md' : 'mini'; - normalizedSlug = React.cloneElement(slug as React.ReactElement, { - size, - }); + let normalizedDecorator = React.isValidElement(slug ?? decorator) + ? (slug ?? decorator) + : null; + if ( + normalizedDecorator && + normalizedDecorator['type']?.displayName === 'AILabel' + ) { + const size = + (normalizedDecorator as ReactElement).props?.['kind'] === 'inline' + ? 'md' + : 'mini'; + normalizedDecorator = React.cloneElement( + normalizedDecorator as React.ReactElement, + { + size, + } + ); } return ( @@ -203,7 +223,15 @@ const Checkbox = React.forwardRef( title={title}> {labelText} - {normalizedSlug} + {slug ? ( + normalizedDecorator + ) : decorator ? ( +
+ {normalizedDecorator} +
+ ) : ( + '' + )}
@@ -239,6 +267,11 @@ Checkbox.propTypes = { */ className: PropTypes.string, + /** + * **Experimental**: Provide a decorator component to be rendered inside the `Checkbox` component + */ + decorator: PropTypes.node, + /** * Specify whether the underlying input should be checked by default */ @@ -300,7 +333,10 @@ Checkbox.propTypes = { /** * **Experimental**: Provide a `Slug` component to be rendered inside the `Checkbox` component */ - slug: PropTypes.node, + slug: deprecate( + PropTypes.node, + 'The `slug` prop has been deprecated and will be removed in the next major version. Use the decorator prop instead.' + ), /** * Specify a title for the