From 56066ae6246cef5af05b8d4a621e76dce07b25ee Mon Sep 17 00:00:00 2001 From: Andrew Holloway Date: Tue, 4 Jun 2024 19:44:48 -0500 Subject: [PATCH] feat!: move from isWarning and isError to status prop (#1973) - update all (sub-)components to use status instead of two sep. props - refactor stories to use the new prop - ensure snapshots do not change (not updating class names at the moment) - add in migration codemod for changes since last alpha release --- .../migrations/alpha14-to-alpha15.test.ts | 156 ++++++++++++++++++ .../migrate/migrations/alpha14-to-alpha15.ts | 98 +++++++++++ .../FieldNote/FieldNote-v2.stories.tsx | 5 +- src/components/FieldNote/FieldNote-v2.tsx | 31 ++-- src/components/Input/Input-v2.tsx | 17 +- .../InputField/InputField-v2.stories.tsx | 4 +- src/components/InputField/InputField-v2.tsx | 35 ++-- src/components/Select/Select-v2.stories.tsx | 4 +- src/components/Select/Select-v2.tsx | 71 +++----- .../TextareaField-v2.stories.tsx | 27 ++- .../TextareaField/TextareaField-v2.tsx | 47 +++--- .../TextareaField-v2.test.tsx.snap | 107 ++++++++---- 12 files changed, 439 insertions(+), 163 deletions(-) create mode 100644 src/bin/migrate/migrations/alpha14-to-alpha15.test.ts create mode 100644 src/bin/migrate/migrations/alpha14-to-alpha15.ts diff --git a/src/bin/migrate/migrations/alpha14-to-alpha15.test.ts b/src/bin/migrate/migrations/alpha14-to-alpha15.test.ts new file mode 100644 index 000000000..64c89de30 --- /dev/null +++ b/src/bin/migrate/migrations/alpha14-to-alpha15.test.ts @@ -0,0 +1,156 @@ +import { dedent } from 'ts-dedent'; + +import { updateStatusProp } from './alpha14-to-alpha15'; +import { createTestSourceFile } from '../helpers'; + +describe('alpha14-to-alpha15', () => { + it('updates an appropriate isWarning prop', () => { + const sourceFileText = dedent` + import {FieldNote} from '@chanzuckerberg/eds'; + + export default function Component() { + return ( + + ) + } + `; + + const sourceFile = createTestSourceFile(sourceFileText); + + updateStatusProp({ + file: sourceFile, + }); + + expect(sourceFile.getText()).toEqual(dedent` + import {FieldNote} from '@chanzuckerberg/eds'; + + export default function Component() { + return ( + + ) + } + `); + }); + + it('updates an appropriate isError prop', () => { + const sourceFileText = dedent` + import {FieldNote} from '@chanzuckerberg/eds'; + + export default function Component() { + return ( + + ) + } + `; + + const sourceFile = createTestSourceFile(sourceFileText); + + updateStatusProp({ + file: sourceFile, + }); + + expect(sourceFile.getText()).toEqual(dedent` + import {FieldNote} from '@chanzuckerberg/eds'; + + export default function Component() { + return ( + + ) + } + `); + }); + + it('does not update an isError prop on non-EDS component', () => { + const sourceFileText = dedent` + import {FieldNote} from 'somewhere'; + + export default function Component() { + return ( + + ) + } + `; + + const sourceFile = createTestSourceFile(sourceFileText); + + updateStatusProp({ + file: sourceFile, + }); + + expect(sourceFile.getText()).toEqual(dedent` + import {FieldNote} from 'somewhere'; + + export default function Component() { + return ( + + ) + } + `); + }); + + it('updates appropriately when both isError and isWarning prop exists', () => { + const sourceFileText = dedent` + import {FieldNote} from '@chanzuckerberg/eds'; + + export default function Component() { + return ( + + ) + } + `; + + const sourceFile = createTestSourceFile(sourceFileText); + + updateStatusProp({ + file: sourceFile, + }); + + expect(sourceFile.getText()).toEqual(dedent` + import {FieldNote} from '@chanzuckerberg/eds'; + + export default function Component() { + return ( + + ) + } + `); + }); + + it('converts on all component types', () => { + const sourceFileText = dedent` + import {FieldNote, InputField, Select, TextareaField} from '@chanzuckerberg/eds'; + + export default function Component() { + return ( +
+ + + + +
+ ); + } + `; + + const sourceFile = createTestSourceFile(sourceFileText); + + updateStatusProp({ + file: sourceFile, + }); + + expect(sourceFile.getText()).toEqual(dedent` + import {FieldNote, InputField, Select, TextareaField} from '@chanzuckerberg/eds'; + + export default function Component() { + return ( +
+ + + + +
+ ); + } + `); + }); +}); diff --git a/src/bin/migrate/migrations/alpha14-to-alpha15.ts b/src/bin/migrate/migrations/alpha14-to-alpha15.ts new file mode 100644 index 000000000..d4020c7fc --- /dev/null +++ b/src/bin/migrate/migrations/alpha14-to-alpha15.ts @@ -0,0 +1,98 @@ +import { + type JsxAttribute, + SyntaxKind, + type Project, + type SourceFile, +} from 'ts-morph'; +import { isDesignSystemImport } from '../helpers'; + +export default function migration(project: Project) { + const files = project.getSourceFiles(); + const sourceFiles = files.filter((file) => !file.isDeclarationFile()); + + sourceFiles.forEach((sourceFile) => { + updateStatusProp({ file: sourceFile }); // https://github.com/chanzuckerberg/edu-design-system/pull/1973 + }); +} + +type TransformOptions = { + file: SourceFile; +}; + +const statusComponents = [ + 'FieldNote', + 'InputField', + 'Select', + 'TextareaField', +].map((name) => name.toLowerCase()); + +export function updateStatusProp({ file }: TransformOptions) { + // Filter down to the design-system-only imports + const importDeclarations = file + .getImportDeclarations() + .filter( + (importDeclaration) => + !importDeclaration.isTypeOnly() && + isDesignSystemImport(importDeclaration), + ); + + const jsxElements = file.getDescendantsOfKind(SyntaxKind.JsxOpeningElement); + const jsxSelfClosingElements = file.getDescendantsOfKind( + SyntaxKind.JsxSelfClosingElement, + ); + + // Get the component usages in the given file (which should only work on EDS imports) + [...jsxElements, ...jsxSelfClosingElements].forEach((element) => { + const tagName = element.getTagNameNode().getText(); + const edsTags: string[] = []; + importDeclarations.forEach((importDeclaration) => { + importDeclaration.getNamedImports().forEach((namedImport) => { + edsTags.push(namedImport.getName()); + }); + }); + + if ( + statusComponents.includes(tagName.toLowerCase()) && + edsTags.includes(tagName) + ) { + // detect if isWarning exists (at all or with value true) + if ( + isBooleanTrue( + element.getAttribute('isWarning')?.asKind(SyntaxKind.JsxAttribute), + ) + ) { + element.getAttribute('isWarning')?.remove(); + element.addAttribute({ + name: 'status', + initializer: `"warning"`, + }); + } + + // detect if isError exists (at all or with value true) + if ( + isBooleanTrue( + element.getAttribute('isError')?.asKind(SyntaxKind.JsxAttribute), + ) + ) { + element.getAttribute('isError')?.remove(); + element.addAttribute({ + name: 'status', + initializer: `"critical"`, + }); + } + } + }); +} + +/** + * Determine whether the attribute evaluates to being set to true + * + * @param attribute the attribute retrieved from the element node + * @returns whether the elements attribute evaluates to true in JSX (exists or exists AND is true) + */ +function isBooleanTrue(attribute: JsxAttribute | undefined): boolean { + return ( + (attribute && typeof attribute?.getInitializer() === 'undefined') || + attribute?.getInitializer()?.getText() === '{true}' + ); +} diff --git a/src/components/FieldNote/FieldNote-v2.stories.tsx b/src/components/FieldNote/FieldNote-v2.stories.tsx index 97f0c0cf8..ed8a1a1de 100644 --- a/src/components/FieldNote/FieldNote-v2.stories.tsx +++ b/src/components/FieldNote/FieldNote-v2.stories.tsx @@ -28,15 +28,16 @@ export const WithErrorIcon: StoryObj = { children: 'This is a fieldnote.', id: 'field-1', icon: 'warning-filled', - isError: true, + status: 'critical', }, }; -export const WithIcon: StoryObj = { +export const WithWarningIcon: StoryObj = { args: { children: 'This is a fieldnote.', id: 'field-1', icon: 'warning-filled', + status: 'warning', }, }; diff --git a/src/components/FieldNote/FieldNote-v2.tsx b/src/components/FieldNote/FieldNote-v2.tsx index fff0cfd5d..17f1e5e82 100644 --- a/src/components/FieldNote/FieldNote-v2.tsx +++ b/src/components/FieldNote/FieldNote-v2.tsx @@ -1,6 +1,7 @@ import clsx from 'clsx'; import type { ReactNode } from 'react'; import React from 'react'; +import type { Status } from '../../util/variant-types'; import { IconV2 as Icon, type IconNameV2 as IconName } from '../Icon'; import styles from './FieldNote-v2.module.css'; @@ -30,13 +31,11 @@ export interface Props { */ icon?: Extract; /** - * Whether there is an error state for the field note text (and icon) - */ - isError?: boolean; - /** - * Whether there is a warning state for the field note text (and icon) + * Status for the field state + * + * **Default is `"default"`**. */ - isWarning?: boolean; + status?: 'default' | Extract; } /** @@ -50,36 +49,36 @@ export const FieldNote = ({ id, disabled, icon, - isError, - isWarning, + status, ...other }: Props) => { const componentClassName = clsx( styles['field-note'], disabled && styles['field-note--disabled'], - isError && styles['field-note--error'], - isWarning && styles['field-note--warning'], + status === 'critical' && styles['field-note--error'], + status === 'warning' && styles['field-note--warning'], className, ); let iconToUse = icon; - if (isError) { + let title = 'fieldnote status icon'; + if (status === 'critical') { iconToUse = 'dangerous'; - } else if (isWarning) { + title = 'error'; + } else if (status === 'warning') { iconToUse = 'warning-filled'; - } else if (icon) { - iconToUse = icon; + title = 'warning'; } return (
- {(isError || isWarning || iconToUse) && ( + {(status === 'critical' || status === 'warning' || iconToUse) && ( )} {children} diff --git a/src/components/Input/Input-v2.tsx b/src/components/Input/Input-v2.tsx index 98c226204..6e7c0a27d 100644 --- a/src/components/Input/Input-v2.tsx +++ b/src/components/Input/Input-v2.tsx @@ -1,6 +1,7 @@ import clsx from 'clsx'; import type { ChangeEventHandler } from 'react'; import React, { forwardRef } from 'react'; +import type { Status } from '../../util/variant-types'; import styles from './Input-v2.module.css'; export type InputProps = React.InputHTMLAttributes & { @@ -78,24 +79,22 @@ export type InputProps = React.InputHTMLAttributes & { defaultValue?: string | number; // Design API /** - * Error state of the form field + * Status for the field state + * + * **Default is `"default"`**. */ - isError?: boolean; - /** - * Whether there is a warning state for the field note text (and icon) - */ - isWarning?: boolean; + status?: 'default' | Extract; }; /** * Input component for one line of text. */ export const Input = forwardRef( - ({ className, disabled, id, isError, isWarning, ...other }, ref) => { + ({ className, disabled, id, status, ...other }, ref) => { const componentClassName = clsx( styles['input'], - isError && styles['error'], - isWarning && styles['warning'], + status === 'critical' && styles['error'], + status === 'warning' && styles['warning'], className, ); diff --git a/src/components/InputField/InputField-v2.stories.tsx b/src/components/InputField/InputField-v2.stories.tsx index 22a57efab..b95bd6318 100644 --- a/src/components/InputField/InputField-v2.stories.tsx +++ b/src/components/InputField/InputField-v2.stories.tsx @@ -58,7 +58,7 @@ export const NoFieldnote: Story = { export const Error: Story = { args: { label: 'Error input field', - isError: true, + status: 'critical', fieldNote: 'This is a fieldnote with an error.', }, }; @@ -69,7 +69,7 @@ export const Error: Story = { export const Warning: Story = { args: { label: 'Warning input field', - isWarning: true, + status: 'warning', fieldNote: 'This uses the warning treatment and also applies to the field note', }, diff --git a/src/components/InputField/InputField-v2.tsx b/src/components/InputField/InputField-v2.tsx index 06b160f2a..9eb6e9a97 100644 --- a/src/components/InputField/InputField-v2.tsx +++ b/src/components/InputField/InputField-v2.tsx @@ -7,6 +7,7 @@ import type { EitherInclusive, ForwardedRefComponent, } from '../../util/utility-types'; +import type { Status } from '../../util/variant-types'; import FieldLabel from '../FieldLabel'; import { FieldNoteV2 as FieldNote } from '../FieldNote'; import { IconV2 as Icon, type IconNameV2 as IconName } from '../Icon'; @@ -94,18 +95,6 @@ export type InputFieldProps = React.InputHTMLAttributes & { * Text under the text input used to provide a description or error message to describe the input. */ fieldNote?: ReactNode; - /** - * Whether there is an error state for the field note text (and icon) - * - * **Default is `false`**. - */ - isError?: boolean; - /** - * Whether there is a warning state for the field note text (and icon) - * - * **Default is `false`**. - */ - isWarning?: boolean; /** * An icon that prefixes the field input. */ @@ -129,6 +118,12 @@ export type InputFieldProps = React.InputHTMLAttributes & { * **Default is `"false"`**. */ showHint?: boolean; + /** + * Status for the field state + * + * **Default is `"default"`**. + */ + status?: 'default' | Extract; } & EitherInclusive< { /** @@ -168,8 +163,6 @@ export const InputField: InputFieldType = forwardRef( fieldNote, id, inputWithin, - isError, - isWarning, label, leadingIcon, maxLength, @@ -178,6 +171,7 @@ export const InputField: InputFieldType = forwardRef( recommendedMaxLength, required, showHint, + status = 'default', type = 'text', ...other }, @@ -217,7 +211,7 @@ export const InputField: InputFieldType = forwardRef( : false; const shouldRenderError = - isError || textExceedsMaxLength || textExceedsRecommendedLength; + textExceedsMaxLength || textExceedsRecommendedLength; const generatedIdVar = useId(); const idVar = id || generatedIdVar; @@ -279,12 +273,10 @@ export const InputField: InputFieldType = forwardRef(
{ setFieldText(e.target.value); @@ -293,6 +285,7 @@ export const InputField: InputFieldType = forwardRef( readOnly={readOnly} ref={ref} required={required} + status={shouldRenderError ? 'critical' : status} type={type} {...other} /> @@ -313,8 +306,7 @@ export const InputField: InputFieldType = forwardRef( {fieldNote} @@ -327,8 +319,7 @@ export const InputField: InputFieldType = forwardRef( {fieldNote} diff --git a/src/components/Select/Select-v2.stories.tsx b/src/components/Select/Select-v2.stories.tsx index cd7d30316..55be8f1b0 100644 --- a/src/components/Select/Select-v2.stories.tsx +++ b/src/components/Select/Select-v2.stories.tsx @@ -796,7 +796,7 @@ export const Optional: StoryObj = { export const Error: StoryObj = { args: { ...Required.args, - isError: true, + status: 'critical', fieldNote: 'Some text describing error', }, parameters: { @@ -810,7 +810,7 @@ export const Error: StoryObj = { export const Warning: StoryObj = { args: { ...Optional.args, - isWarning: true, + status: 'warning', fieldNote: 'Some text describing warning', }, parameters: { diff --git a/src/components/Select/Select-v2.tsx b/src/components/Select/Select-v2.tsx index d13369222..8459713a3 100644 --- a/src/components/Select/Select-v2.tsx +++ b/src/components/Select/Select-v2.tsx @@ -12,6 +12,7 @@ import { usePopper } from 'react-popper'; import { useId } from '../../util/useId'; import type { ExtractProps } from '../../util/utility-types'; +import type { Status } from '../../util/variant-types'; import FieldLabel from '../FieldLabel'; import { FieldNoteV2 as FieldNote } from '../FieldNote'; import { IconV2 as Icon, type IconNameV2 as IconName } from '../Icon'; @@ -62,18 +63,6 @@ type SelectProps = ExtractProps & * Text under the text input used to provide a description or error message to describe the input. */ fieldNote?: ReactNode; - /** - * Whether there is an error state for the field note text (and icon) - * - * **Default is `false`**. - */ - isError?: boolean; - /** - * Whether there is a warning state for the field note text (and icon) - * - * **Default is `false`**. - */ - isWarning?: boolean; /** * Visible text label for the component. */ @@ -90,6 +79,12 @@ type SelectProps = ExtractProps & * **Default is `"false"`**. */ showHint?: boolean; + /** + * Status for the field state + * + * **Default is `"default"`**. + */ + status?: 'default' | Extract; }; type SelectLabelProps = ExtractProps & { @@ -129,18 +124,6 @@ type SelectButtonWrapperProps = { * Icon override for component. Default is 'chevron-down' */ icon?: Extract; - /** - * Whether there is an error state for the field note text (and icon) - * - * **Default is `false`**. - */ - isError?: boolean; - /** - * Whether there is a warning state for the field note text (and icon) - * - * **Default is `false`**. - */ - isWarning?: boolean; /** * Indicates state of the select, used to style the button. */ @@ -153,12 +136,17 @@ type SelectButtonWrapperProps = { * Whether we should truncate the text displayed in the select field */ shouldTruncate?: boolean; + /** + * Status for the field state + * + * **Default is `"default"`**. + */ + status?: 'default' & Extract; }; type SelectContextType = PopoverContext & { optionsClassName?: string; - isWarning?: boolean; - isError?: boolean; + status?: SelectButtonWrapperProps['status']; }; let showNameWarning = true; @@ -199,8 +187,6 @@ export function Select({ disabled, fieldNote, id, - isError, - isWarning, label, labelLayout = 'vertical', modifiers = defaultPopoverModifiers, @@ -210,6 +196,7 @@ export function Select({ placement = 'bottom-start', required, showHint, + status, strategy, onChange: theirOnChange, ...other @@ -272,8 +259,7 @@ export function Select({ { setPopperElement }, { popperStyles: popperStyles.popper }, { popperAttributes: popperAttributes.popper }, - { isError }, - { isWarning }, + { status }, ); if (typeof children === 'function') { @@ -318,11 +304,7 @@ export function Select({ {fieldNote && (
- + {fieldNote}
@@ -383,7 +365,7 @@ const SelectLabel = ({ */ const SelectButton = function (props: SelectButtonProps) { const { children, className, onClick: theirOnClick, ...other } = props; - const { setReferenceElement, isWarning, isError } = useContext(SelectContext); + const { setReferenceElement, status } = useContext(SelectContext); return ( { theirOnClick && theirOnClick(event); }} + status={status} > {children} @@ -493,25 +474,19 @@ export const SelectButtonWrapper = React.forwardRef< children, className, icon = 'chevron-down', - isError, isOpen, - isWarning, - shouldTruncate = false, onClick: theirOnClick, + shouldTruncate = false, ...other }, ref, ) => { - const { isWarning: contextWarning, isError: contextError } = - useContext(SelectContext); - const showWarning = - typeof isWarning !== 'undefined' ? isWarning : contextWarning; - const showError = typeof isError !== 'undefined' ? isError : contextError; + const { status } = useContext(SelectContext); const componentClassName = clsx( styles['select-button'], - showWarning && styles['select-button--warning'], - showError && styles['select-button--error'], + status === 'warning' && styles['select-button--warning'], + status === 'critical' && styles['select-button--error'], className, ); const iconClassName = clsx( diff --git a/src/components/TextareaField/TextareaField-v2.stories.tsx b/src/components/TextareaField/TextareaField-v2.stories.tsx index 31fc17045..775200b35 100644 --- a/src/components/TextareaField/TextareaField-v2.stories.tsx +++ b/src/components/TextareaField/TextareaField-v2.stories.tsx @@ -82,20 +82,40 @@ export const WhenReadOnly: Story = { }, }; +/** + * The default status isn't really anything, but exists to allow a value to be set if needed. This applies + * the neutral styles. + */ +export const WhenDefaultStatus: Story = { + args: { + status: 'default', + fieldNote: 'Text should be at least 100 characters', + }, +}; + +/** + * When in an error state, this is the status to use. It matches other components which have a critical status. + */ export const WhenError: Story = { args: { - isError: true, + status: 'critical', fieldNote: 'Text should be at least 100 characters', }, }; +/** + * You can also apply a warning status. + */ export const WhenWarning: Story = { args: { - isWarning: true, + status: 'warning', fieldNote: 'Text should be at least 100 characters', }, }; +/** + * Textarea components can be set as required. + */ export const WhenRequired: Story = { args: { required: true, @@ -103,6 +123,9 @@ export const WhenRequired: Story = { }, }; +/** + * ... or optional. + */ export const WhenOptional: Story = { args: { required: false, diff --git a/src/components/TextareaField/TextareaField-v2.tsx b/src/components/TextareaField/TextareaField-v2.tsx index d84d2dd65..8a2092c2e 100644 --- a/src/components/TextareaField/TextareaField-v2.tsx +++ b/src/components/TextareaField/TextareaField-v2.tsx @@ -8,6 +8,7 @@ import type { ForwardedRefComponent, } from '../../util/utility-types'; +import type { Status } from '../../util/variant-types'; import FieldLabel from '../FieldLabel'; import { FieldNoteV2 as FieldNote } from '../FieldNote'; import Text from '../Text'; @@ -37,16 +38,6 @@ type TextareaFieldProps = React.TextareaHTMLAttributes & { */ id?: string; // Design API - /** - * Error state of the form field - */ - isError?: boolean; - /** - * Whether there is a warning state for the field note text (and icon) - * - * **Default is `false`**. - */ - isWarning?: boolean; /** * Behaves similar to `maxLength` but allows the user to continue typing more text. * Should not be larger than `maxLength`, if present. @@ -58,6 +49,12 @@ type TextareaFieldProps = React.TextareaHTMLAttributes & { * **Default is `"false"`**. */ showHint?: boolean; + /** + * Status for the field state + * + * **Default is `"default"`**. + */ + status?: 'default' | Extract; } & EitherInclusive< { /** @@ -95,15 +92,11 @@ type TextAreaProps = React.TextareaHTMLAttributes & { */ disabled?: boolean; /** - * Whether the error state is active - */ - isError?: boolean; - /** - * Whether there is a warning state for the field note text (and icon) + * Status for the field state * - * **Default is `false`**. + * **Default is `"default"`**. */ - isWarning?: boolean; + status?: 'default' | Extract; }; /** @@ -116,17 +109,16 @@ const TextArea = forwardRef( children, disabled, defaultValue = '', - isError = false, - isWarning, readOnly, + status = 'default', ...other }, ref, ) => { const componentClassName = clsx( styles['textarea'], - isError && styles['error'], - isWarning && styles['warning'], + status === 'critical' && styles['error'], + status === 'warning' && styles['warning'], disabled && styles['textarea--disabled'], className, ); @@ -163,8 +155,6 @@ export const TextareaField: TextareaFieldType = forwardRef( disabled, fieldNote, id, - isError, - isWarning, label, maxLength, onChange, @@ -172,6 +162,7 @@ export const TextareaField: TextareaFieldType = forwardRef( recommendedMaxLength, required, showHint, + status = 'default', ...other }, ref, @@ -192,7 +183,9 @@ export const TextareaField: TextareaFieldType = forwardRef( : false; const shouldRenderError = - isError || textExceedsMaxLength || textExceedsRecommendedLength; + status === 'critical' || + textExceedsMaxLength || + textExceedsRecommendedLength; const ariaDescribedByVar = fieldNote ? ariaDescribedBy || generatedAriaDescribedById @@ -266,8 +259,6 @@ export const TextareaField: TextareaFieldType = forwardRef( defaultValue={defaultValue} disabled={disabled} id={idVar} - isError={shouldRenderError} - isWarning={isWarning} maxLength={maxLength} onChange={(e) => { setFieldText(e.target.value); @@ -276,6 +267,7 @@ export const TextareaField: TextareaFieldType = forwardRef( readOnly={readOnly} ref={ref} required={required} + status={shouldRenderError ? 'critical' : status} {...other} > {children} @@ -287,8 +279,7 @@ export const TextareaField: TextareaFieldType = forwardRef( className={styles['textarea-field__field-note']} disabled={disabled} id={ariaDescribedByVar} - isError={shouldRenderError} - isWarning={isWarning} + status={shouldRenderError ? 'critical' : status} > {fieldNote} diff --git a/src/components/TextareaField/__snapshots__/TextareaField-v2.test.tsx.snap b/src/components/TextareaField/__snapshots__/TextareaField-v2.test.tsx.snap index c1e507df3..f7377f6cb 100644 --- a/src/components/TextareaField/__snapshots__/TextareaField-v2.test.tsx.snap +++ b/src/components/TextareaField/__snapshots__/TextareaField-v2.test.tsx.snap @@ -44,6 +44,49 @@ praesentium, commodi eligendi asperiores quis dolorum porro.
`; +exports[` WhenDefaultStatus story renders snapshot 1`] = ` +
+
+
+ +
+ + +
+
+`; + exports[` WhenDisabled story renders snapshot 1`] = `
WhenError story renders snapshot 1`] = ` >