From 643d907e836ce4b700fca580247b25f3d9fb0762 Mon Sep 17 00:00:00 2001 From: TJ Egan Date: Wed, 17 Aug 2022 15:55:33 +0200 Subject: [PATCH 01/12] feat(FluidTextInput): create FluidTextInput component --- .../FluidTextInput/FluidTextInput.js | 91 ++++++++++++++ .../FluidTextInput/FluidTextInput.stories.js | 116 ++++++++++++++++++ .../src/components/FluidTextInput/index.js | 9 ++ packages/react/src/index.js | 1 + 4 files changed, 217 insertions(+) create mode 100644 packages/react/src/components/FluidTextInput/FluidTextInput.js create mode 100644 packages/react/src/components/FluidTextInput/FluidTextInput.stories.js create mode 100644 packages/react/src/components/FluidTextInput/index.js diff --git a/packages/react/src/components/FluidTextInput/FluidTextInput.js b/packages/react/src/components/FluidTextInput/FluidTextInput.js new file mode 100644 index 000000000000..1cd0fb098365 --- /dev/null +++ b/packages/react/src/components/FluidTextInput/FluidTextInput.js @@ -0,0 +1,91 @@ +/** + * 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 FluidForm from '../FluidForm'; +import TextInput from '../TextInput'; + +function FluidTextInput({ className, ...other }) { + return ( + + + + ); +} + +FluidTextInput.propTypes = { + /** + * Specify an optional className to be applied to the outer FluidForm wrapper + */ + className: PropTypes.string, + + /** + * Optionally provide the default value of the `` + */ + defaultValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + + /** + * Specify whether the `` should be disabled + */ + disabled: PropTypes.bool, + + /** + * Specify a custom `id` for the `` + */ + id: PropTypes.string.isRequired, + + /** + * Specify whether the control is currently invalid + */ + invalid: PropTypes.bool, + + /** + * Provide the text that is displayed when the control is in an invalid state + */ + invalidText: PropTypes.node, + + /** + * Provide the text that will be read by a screen reader when visiting this + * control + */ + labelText: PropTypes.node.isRequired, + + /** + * Optionally provide an `onChange` handler that is called whenever `` + * is updated + */ + onChange: PropTypes.func, + + /** + * Optionally provide an `onClick` handler that is called whenever the + * `` is clicked + */ + onClick: PropTypes.func, + + /** + * Specify the placeholder attribute for the `` + */ + placeholder: PropTypes.string, + + /** + * Specify the value of the `` + */ + value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + + /** + * Specify whether the control is currently in warning state + */ + warn: PropTypes.bool, + + /** + * Provide the text that is displayed when the control is in warning state + */ + warnText: PropTypes.node, +}; + +export default FluidTextInput; diff --git a/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js b/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js new file mode 100644 index 000000000000..5a0da4cb0eb8 --- /dev/null +++ b/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js @@ -0,0 +1,116 @@ +/** + * 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 FluidTextInput from '../FluidTextInput'; +import { + ToggletipLabel, + Toggletip, + ToggletipButton, + ToggletipContent, +} from '../Toggletip'; +import { Information } from '@carbon/icons-react'; + +export default { + title: 'Components/FluidTextInput', + component: FluidTextInput, +}; + +export const Default = () => ( + +); + +const ToggleTip = ( + <> + Label + + + + + +

Additional field information here.

+
+
+ +); + +export const DefaultWithTooltip = () => ( + +); + +export const Playground = (args) => ( +
+ +
+); + +Playground.argTypes = { + playgroundWidth: { + control: { type: 'range', min: 300, max: 800, step: 50 }, + defaultValue: 300, + }, + className: { + control: { + type: 'text', + }, + defaultValue: 'test-class', + }, + defaultValue: { + control: { + type: 'text', + }, + }, + placeholder: { + control: { + type: 'text', + }, + defaultValue: 'Placeholder text', + }, + invalid: { + control: { + type: 'boolean', + }, + defaultValue: false, + }, + invalidText: { + control: { + type: 'text', + }, + defaultValue: + 'Error message that is really long can wrap to more lines but should not be excessively long.', + }, + disabled: { + control: { + type: 'boolean', + }, + defaultValue: false, + }, + labelText: { + control: { + type: 'text', + }, + defaultValue: 'Label', + }, + warn: { + control: { + type: 'boolean', + }, + defaultValue: false, + }, + warnText: { + control: { + type: 'text', + }, + defaultValue: + 'Warning message that is really long can wrap to more lines but should not be excessively long.', + }, + value: { + control: { + type: 'text', + }, + }, +}; diff --git a/packages/react/src/components/FluidTextInput/index.js b/packages/react/src/components/FluidTextInput/index.js new file mode 100644 index 000000000000..df90b5ae9178 --- /dev/null +++ b/packages/react/src/components/FluidTextInput/index.js @@ -0,0 +1,9 @@ +/** + * 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. + */ + +export default from './FluidTextInput'; +export { FluidTextInput } from './FluidTextInput'; diff --git a/packages/react/src/index.js b/packages/react/src/index.js index 56affb142734..d5cd712fcda8 100644 --- a/packages/react/src/index.js +++ b/packages/react/src/index.js @@ -66,6 +66,7 @@ export FileUploader, { export { FilterableMultiSelect } from './components/FilterableMultiSelect'; export Form from './components/Form'; export FluidForm from './components/FluidForm'; +export FluidTextInput from './components/FluidTextInput'; export FormGroup from './components/FormGroup'; export FormItem from './components/FormItem'; export FormLabel from './components/FormLabel'; From c09be2d38d0787756407b262e225ce2328c3ac6e Mon Sep 17 00:00:00 2001 From: TJ Egan Date: Wed, 17 Aug 2022 16:03:30 +0200 Subject: [PATCH 02/12] test(snapshot): update snapshots --- .../__snapshots__/PublicAPI-test.js.snap | 65 +++++++++++++++++++ packages/react/src/__tests__/index-test.js | 1 + 2 files changed, 66 insertions(+) diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index df56e8b322ee..fe9ec438dd78 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -3334,6 +3334,71 @@ Map { }, }, }, + "FluidTextInput" => Object { + "propTypes": Object { + "className": Object { + "type": "string", + }, + "defaultValue": Object { + "args": Array [ + Array [ + Object { + "type": "string", + }, + Object { + "type": "number", + }, + ], + ], + "type": "oneOfType", + }, + "disabled": Object { + "type": "bool", + }, + "id": Object { + "isRequired": true, + "type": "string", + }, + "invalid": Object { + "type": "bool", + }, + "invalidText": Object { + "type": "node", + }, + "labelText": Object { + "isRequired": true, + "type": "node", + }, + "onChange": Object { + "type": "func", + }, + "onClick": Object { + "type": "func", + }, + "placeholder": Object { + "type": "string", + }, + "value": Object { + "args": Array [ + Array [ + Object { + "type": "string", + }, + Object { + "type": "number", + }, + ], + ], + "type": "oneOfType", + }, + "warn": Object { + "type": "bool", + }, + "warnText": Object { + "type": "node", + }, + }, + }, "Form" => Object { "propTypes": Object { "children": Object { diff --git a/packages/react/src/__tests__/index-test.js b/packages/react/src/__tests__/index-test.js index c90af09ec018..d1e8e8658fad 100644 --- a/packages/react/src/__tests__/index-test.js +++ b/packages/react/src/__tests__/index-test.js @@ -63,6 +63,7 @@ describe('Carbon Components React', () => { "FilterableMultiSelect", "FlexGrid", "FluidForm", + "FluidTextInput", "Form", "FormGroup", "FormItem", From 2ed05da8583fa5f04e5d593440d8460068fad935 Mon Sep 17 00:00:00 2001 From: Alessandra Davila Date: Wed, 17 Aug 2022 14:00:05 -0500 Subject: [PATCH 03/12] chore(fluid-input-text): update fluid input text styles --- .../components/text-input/_text-input.scss | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/packages/styles/scss/components/text-input/_text-input.scss b/packages/styles/scss/components/text-input/_text-input.scss index 04606f73cef2..5c5899d8830e 100644 --- a/packages/styles/scss/components/text-input/_text-input.scss +++ b/packages/styles/scss/components/text-input/_text-input.scss @@ -281,7 +281,7 @@ } .#{$prefix}--form--fluid .#{$prefix}--text-input--invalid, - .#{$prefix}--form--fluid .#{$prefix}--text-input--warn { + .#{$prefix}--form--fluid .#{$prefix}--text-input--warning { border-bottom: none; } @@ -289,7 +289,7 @@ .#{$prefix}--text-input--invalid + .#{$prefix}--text-input__divider, .#{$prefix}--form--fluid - .#{$prefix}--text-input--warn + .#{$prefix}--text-input--warning + .#{$prefix}--text-input__divider { display: block; border-style: solid; @@ -309,8 +309,15 @@ .#{$prefix}--form--fluid .#{$prefix}--text-input__field-wrapper[data-invalid] - > .#{$prefix}--text-input--invalid { - @include focus-outline('reset'); + > .#{$prefix}--text-input--invalid, + .#{$prefix}--form--fluid + .#{$prefix}--text-input__field-wrapper--warning + > .#{$prefix}--text-input--warning { + outline: none; + } + + .#{$prefix}--form--fluid .#{$prefix}--text-input__field-wrapper--warning { + border-bottom: 1px solid $border-strong; } .#{$prefix}--form--fluid @@ -319,11 +326,20 @@ } .#{$prefix}--form--fluid - .#{$prefix}--text-input__field-wrapper[data-invalid] - > .#{$prefix}--text-input--invalid:focus { + .#{$prefix}--text-input__field-wrapper[data-invalid]:focus-within, + .#{$prefix}--form--fluid + .#{$prefix}--text-input__field-wrapper--warning:focus-within { @include focus-outline('outline'); } + .#{$prefix}--form--fluid + .#{$prefix}--text-input__field-wrapper[data-invalid] + > .#{$prefix}--text-input--invalid:focus, + .#{$prefix}--form--fluid + .#{$prefix}--text-input__field-wrapper--warning + > .#{$prefix}--text-input--warning:focus { + outline: none; + } //----------------------------- // Inline Text Input //----------------------------- From bd27e43f23ca80a68433d1defe884279cc80746d Mon Sep 17 00:00:00 2001 From: TJ Egan Date: Thu, 18 Aug 2022 16:09:55 +0200 Subject: [PATCH 04/12] chore(test): add test stories --- .../FluidTextInput/FluidTextInput.stories.js | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js b/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js index 5a0da4cb0eb8..f04cb448866a 100644 --- a/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js +++ b/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js @@ -24,6 +24,58 @@ export const Default = () => ( ); +export const Test = () => ( + <> +
+ + + + + +
+
+
+
+ + + + + +
+ +); + const ToggleTip = ( <> Label From fbbf969addb35ad50c11b51a83fa57b983028e86 Mon Sep 17 00:00:00 2001 From: TJ Egan Date: Thu, 18 Aug 2022 17:21:06 +0200 Subject: [PATCH 05/12] style(FluidTextInput): adjust tooltip styles, add test story --- .../FluidTextInput/FluidTextInput.stories.js | 20 ++++--------------- .../src/components/FluidTextInput/test.scss | 11 ++++++++++ .../components/text-input/_text-input.scss | 3 +++ 3 files changed, 18 insertions(+), 16 deletions(-) create mode 100644 packages/react/src/components/FluidTextInput/test.scss diff --git a/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js b/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js index f04cb448866a..961f1b0fa904 100644 --- a/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js +++ b/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js @@ -14,6 +14,7 @@ import { ToggletipContent, } from '../Toggletip'; import { Information } from '@carbon/icons-react'; +import './test.scss'; export default { title: 'Components/FluidTextInput', @@ -26,13 +27,7 @@ export const Default = () => ( export const Test = () => ( <> -
+
( labelText="Label" placeholder="Placeholder text" /> -
-
-
+
( const ToggleTip = ( <> Label - + diff --git a/packages/react/src/components/FluidTextInput/test.scss b/packages/react/src/components/FluidTextInput/test.scss new file mode 100644 index 000000000000..39dd297f889b --- /dev/null +++ b/packages/react/src/components/FluidTextInput/test.scss @@ -0,0 +1,11 @@ +.fluid-input-wrapper { + display: flex; + width: 100%; + justify-content: space-between; + margin-bottom: 2rem; +} + +.fluid-input-wrapper > * { + width: 33%; + margin: 0 1rem; +} diff --git a/packages/styles/scss/components/text-input/_text-input.scss b/packages/styles/scss/components/text-input/_text-input.scss index 5c5899d8830e..d66a01f6bd2b 100644 --- a/packages/styles/scss/components/text-input/_text-input.scss +++ b/packages/styles/scss/components/text-input/_text-input.scss @@ -263,6 +263,9 @@ z-index: 1; top: rem(13px); left: $spacing-05; + display: flex; + height: rem(16px); + align-items: center; margin: 0; } From 78f3a6aa7f0258e719066e0e724de8fdc77358bc Mon Sep 17 00:00:00 2001 From: TJ Egan Date: Tue, 23 Aug 2022 17:48:19 +0200 Subject: [PATCH 06/12] test(FluidTextInput): add e2e tests --- .../FluidTextInput/FluidTextInput-test.e2e.js | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 e2e/components/FluidTextInput/FluidTextInput-test.e2e.js diff --git a/e2e/components/FluidTextInput/FluidTextInput-test.e2e.js b/e2e/components/FluidTextInput/FluidTextInput-test.e2e.js new file mode 100644 index 000000000000..2cf30c309135 --- /dev/null +++ b/e2e/components/FluidTextInput/FluidTextInput-test.e2e.js @@ -0,0 +1,37 @@ +/** + * 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. + */ + +'use strict'; + +const { expect, test } = require('@playwright/test'); +const { themes } = require('../../test-utils/env'); +const { snapshotStory, visitStory } = require('../../test-utils/storybook'); + +test.describe('FluidTextInput', () => { + themes.forEach((theme) => { + test.describe(theme, () => { + test('fluid text input @vrt', async ({ page }) => { + await snapshotStory(page, { + component: 'FluidTextInput', + id: 'components-fluidtextinput--default', + theme, + }); + }); + }); + }); + + test('accessibility-checker @avt', async ({ page }) => { + await visitStory(page, { + component: 'FluidTextInput', + id: 'components-fluidtextinput--default', + globals: { + theme: 'white', + }, + }); + await expect(page).toHaveNoACViolations('FluidTextInput'); + }); +}); From 6dde849c715e39d29fcbfd8a6cd086b0df103b1b Mon Sep 17 00:00:00 2001 From: TJ Egan Date: Thu, 25 Aug 2022 11:55:08 +0200 Subject: [PATCH 07/12] refactor(TextInput): move fluid text input styles to own file --- packages/styles/scss/components/_index.scss | 1 + .../fluid-text-input/_fluid-text-input.scss | 107 ++++++++++++++++++ .../components/fluid-text-input/_index.scss | 11 ++ .../components/text-input/_text-input.scss | 7 +- 4 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 packages/styles/scss/components/fluid-text-input/_fluid-text-input.scss create mode 100644 packages/styles/scss/components/fluid-text-input/_index.scss diff --git a/packages/styles/scss/components/_index.scss b/packages/styles/scss/components/_index.scss index 532d1dc0a40b..715314a80f19 100644 --- a/packages/styles/scss/components/_index.scss +++ b/packages/styles/scss/components/_index.scss @@ -22,6 +22,7 @@ @use 'date-picker'; @use 'dropdown'; @use 'file-uploader'; +@use 'fluid-text-input'; @use 'form'; @use 'inline-loading'; @use 'link'; diff --git a/packages/styles/scss/components/fluid-text-input/_fluid-text-input.scss b/packages/styles/scss/components/fluid-text-input/_fluid-text-input.scss new file mode 100644 index 000000000000..957ebc93fee1 --- /dev/null +++ b/packages/styles/scss/components/fluid-text-input/_fluid-text-input.scss @@ -0,0 +1,107 @@ +// +// Copyright IBM Corp. 2018, 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. +// + +//----------------------------- +// Fluid Text Input +//----------------------------- +@use '../../config' as *; +@use '../../motion' as *; +@use '../../spacing' as *; +@use '../../theme' as *; +@use '../../utilities/convert' as *; +@use '../../utilities/focus-outline' as *; +@use '../text-input'; + +@mixin fluid-text-input { + .#{$prefix}--form--fluid .#{$prefix}--text-input-wrapper { + position: relative; + background: $field; + transition: background-color $duration-fast-01 motion(standard, productive), + outline $duration-fast-01 motion(standard, productive); + } + + .#{$prefix}--form--fluid .#{$prefix}--label { + position: absolute; + z-index: 1; + top: rem(13px); + left: $spacing-05; + display: flex; + height: rem(16px); + align-items: center; + margin: 0; + } + + .#{$prefix}--form--fluid .#{$prefix}--form__helper-text { + display: none; + } + + .#{$prefix}--form--fluid .#{$prefix}--text-input { + min-height: rem(64px); + padding: rem(32px) $spacing-05 rem(13px); + } + + .#{$prefix}--text-input__divider, + .#{$prefix}--form--fluid .#{$prefix}--text-input__divider { + display: none; + } + + .#{$prefix}--form--fluid .#{$prefix}--text-input--invalid, + .#{$prefix}--form--fluid .#{$prefix}--text-input--warning { + border-bottom: none; + } + + .#{$prefix}--form--fluid + .#{$prefix}--text-input--invalid + + .#{$prefix}--text-input__divider, + .#{$prefix}--form--fluid + .#{$prefix}--text-input--warning + + .#{$prefix}--text-input__divider { + display: block; + border-style: solid; + border-color: $border-subtle; + border-bottom: none; + margin: 0 1rem; + } + + .#{$prefix}--form--fluid .#{$prefix}--text-input__invalid-icon { + top: rem(80px); + } + + .#{$prefix}--form--fluid + .#{$prefix}--text-input__field-wrapper[data-invalid] + > .#{$prefix}--text-input--invalid, + .#{$prefix}--form--fluid + .#{$prefix}--text-input__field-wrapper--warning + > .#{$prefix}--text-input--warning { + outline: none; + } + + .#{$prefix}--form--fluid .#{$prefix}--text-input__field-wrapper--warning { + border-bottom: 1px solid $border-strong; + } + + .#{$prefix}--form--fluid + .#{$prefix}--text-input__field-wrapper[data-invalid]:not(:focus) { + @include focus-outline('invalid'); + } + + .#{$prefix}--form--fluid + .#{$prefix}--text-input__field-wrapper[data-invalid]:focus-within, + .#{$prefix}--form--fluid + .#{$prefix}--text-input__field-wrapper--warning:focus-within { + @include focus-outline('outline'); + } + + .#{$prefix}--form--fluid + .#{$prefix}--text-input__field-wrapper[data-invalid] + > .#{$prefix}--text-input--invalid:focus, + .#{$prefix}--form--fluid + .#{$prefix}--text-input__field-wrapper--warning + > .#{$prefix}--text-input--warning:focus { + outline: none; + } +} diff --git a/packages/styles/scss/components/fluid-text-input/_index.scss b/packages/styles/scss/components/fluid-text-input/_index.scss new file mode 100644 index 000000000000..a0619895a7bf --- /dev/null +++ b/packages/styles/scss/components/fluid-text-input/_index.scss @@ -0,0 +1,11 @@ +// +// Copyright IBM Corp. 2018, 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. +// + +@forward 'fluid-text-input'; +@use 'fluid-text-input'; + +@include fluid-text-input.fluid-text-input; diff --git a/packages/styles/scss/components/text-input/_text-input.scss b/packages/styles/scss/components/text-input/_text-input.scss index d66a01f6bd2b..7457b6228efc 100644 --- a/packages/styles/scss/components/text-input/_text-input.scss +++ b/packages/styles/scss/components/text-input/_text-input.scss @@ -248,6 +248,8 @@ @include skeleton; } + // Deprecated -- Styles have been moved to `fluid-text-input.scss` + // V12 - Remove this block //----------------------------- // Fluid Text Input //----------------------------- @@ -305,11 +307,6 @@ top: rem(80px); } - // V11: Possibly deprecate - .#{$prefix}--form--fluid .#{$prefix}--text-input-wrapper--light { - background: $field-02; - } - .#{$prefix}--form--fluid .#{$prefix}--text-input__field-wrapper[data-invalid] > .#{$prefix}--text-input--invalid, From b9742a43ec98f63cb2961403b296dfc20e5b89a2 Mon Sep 17 00:00:00 2001 From: TJ Egan Date: Thu, 25 Aug 2022 12:25:51 +0200 Subject: [PATCH 08/12] refactor(FluidTextInput): use isFluid context --- .../FluidTextInput/FluidTextInput.js | 13 +++-- .../FluidTextInput/FluidTextInput.stories.js | 16 +++++- .../fluid-text-input/_fluid-text-input.scss | 54 ++++++++++++------- 3 files changed, 59 insertions(+), 24 deletions(-) diff --git a/packages/react/src/components/FluidTextInput/FluidTextInput.js b/packages/react/src/components/FluidTextInput/FluidTextInput.js index 1cd0fb098365..5fa57ed60f87 100644 --- a/packages/react/src/components/FluidTextInput/FluidTextInput.js +++ b/packages/react/src/components/FluidTextInput/FluidTextInput.js @@ -7,14 +7,19 @@ import PropTypes from 'prop-types'; import React from 'react'; -import FluidForm from '../FluidForm'; +import classnames from 'classnames'; import TextInput from '../TextInput'; +import { usePrefix } from '../../internal/usePrefix'; +import { FormContext } from '../FluidForm/FormContext'; function FluidTextInput({ className, ...other }) { + const prefix = usePrefix(); + const classNames = classnames(`${prefix}--text-input--fluid`, className); + return ( - - - + + + ); } diff --git a/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js b/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js index 961f1b0fa904..bdcf2d4105c2 100644 --- a/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js +++ b/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js @@ -28,9 +28,14 @@ export const Default = () => ( export const Test = () => ( <>
- + ( /> ( />
- + ( /> .#{$prefix}--text-input--invalid, - .#{$prefix}--form--fluid + .#{$prefix}--text-input--fluid .#{$prefix}--text-input__field-wrapper--warning > .#{$prefix}--text-input--warning { outline: none; } - .#{$prefix}--form--fluid .#{$prefix}--text-input__field-wrapper--warning { + .#{$prefix}--text-input--fluid + .#{$prefix}--text-input__field-wrapper--warning { border-bottom: 1px solid $border-strong; } - .#{$prefix}--form--fluid + .#{$prefix}--text-input--fluid .#{$prefix}--text-input__field-wrapper[data-invalid]:not(:focus) { @include focus-outline('invalid'); } - .#{$prefix}--form--fluid + .#{$prefix}--text-input--fluid .#{$prefix}--text-input__field-wrapper[data-invalid]:focus-within, - .#{$prefix}--form--fluid + .#{$prefix}--text-input--fluid .#{$prefix}--text-input__field-wrapper--warning:focus-within { @include focus-outline('outline'); } - .#{$prefix}--form--fluid + .#{$prefix}--text-input--fluid .#{$prefix}--text-input__field-wrapper[data-invalid] > .#{$prefix}--text-input--invalid:focus, - .#{$prefix}--form--fluid + .#{$prefix}--text-input--fluid .#{$prefix}--text-input__field-wrapper--warning > .#{$prefix}--text-input--warning:focus { outline: none; From 39436b1b73d55e7fa69f312f7a75ed5fdc0606cb Mon Sep 17 00:00:00 2001 From: TJ Egan Date: Thu, 25 Aug 2022 14:16:54 +0200 Subject: [PATCH 09/12] test(FluidTextInput): add component API tests --- .../__tests__/FluidTextInput-test.js | 292 ++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100644 packages/react/src/components/FluidTextInput/__tests__/FluidTextInput-test.js diff --git a/packages/react/src/components/FluidTextInput/__tests__/FluidTextInput-test.js b/packages/react/src/components/FluidTextInput/__tests__/FluidTextInput-test.js new file mode 100644 index 000000000000..7162ffa631d3 --- /dev/null +++ b/packages/react/src/components/FluidTextInput/__tests__/FluidTextInput-test.js @@ -0,0 +1,292 @@ +/** + * 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 FluidTextInput from '../FluidTextInput'; +import userEvent from '@testing-library/user-event'; +import { render, screen } from '@testing-library/react'; +import { FeatureFlags } from '../../FeatureFlags'; + +const prefix = 'cds'; + +describe('FluidTextInput', () => { + describe('renders as expected - Component API', () => { + it('should spread extra props onto the input element', () => { + render( + + ); + + expect(screen.getByRole('textbox')).toHaveAttribute( + 'data-testid', + 'test-id' + ); + }); + + it('should support a custom `className` prop on the outermost element', () => { + const { container } = render( + + + + ); + + expect(container.firstChild).toHaveClass('custom-class'); + }); + + it('should support a custom `className` prop on the input element (V10)', () => { + render( + + ); + + expect(screen.getByRole('textbox')).toHaveClass('custom-class'); + }); + + it('should respect defaultValue prop', () => { + render( + + ); + + expect(screen.getByRole('textbox')).toHaveAttribute( + 'value', + 'This is default text' + ); + }); + + it('should respect disabled prop', () => { + render( + + ); + + expect(screen.getByRole('textbox')).toBeDisabled(); + }); + + it('should respect id prop', () => { + render(); + + expect(screen.getByRole('textbox')).toHaveAttribute('id', 'input-1'); + }); + + it('should respect invalid prop', () => { + const { container } = render( + + ); + + const invalidIcon = container.querySelector( + `svg.${prefix}--text-input__invalid-icon` + ); + + expect(screen.getByRole('textbox')).toHaveAttribute('data-invalid'); + expect(screen.getByRole('textbox')).toHaveClass( + `${prefix}--text-input--invalid` + ); + expect(invalidIcon).toBeInTheDocument(); + }); + + it('should respect invalidText prop', () => { + render( + + ); + + expect(screen.getByText('This is invalid text')).toBeInTheDocument(); + expect(screen.getByText('This is invalid text')).toHaveClass( + `${prefix}--form-requirement` + ); + }); + + it('should respect labelText prop', () => { + render(); + + expect(screen.getByText('FluidTextInput label')).toBeInTheDocument(); + expect(screen.getByText('FluidTextInput label')).toHaveClass( + `${prefix}--label` + ); + }); + + it('should respect placeholder prop', () => { + render( + + ); + + expect( + screen.getByPlaceholderText('Placeholder text') + ).toBeInTheDocument(); + }); + + it('should respect type prop', () => { + render( + + ); + + expect(screen.getByRole('textbox')).toHaveAttribute(`type`, 'text'); + }); + + it('should respect value prop', () => { + render( + + ); + + expect(screen.getByRole('textbox')).toHaveAttribute( + 'value', + 'This is a test value' + ); + }); + + it('should respect warn prop', () => { + const { container } = render( + + ); + + const warnIcon = container.querySelector( + `svg.${prefix}--text-input__invalid-icon--warning` + ); + + expect(screen.getByRole('textbox')).toHaveClass( + `${prefix}--text-input--warning` + ); + expect(warnIcon).toBeInTheDocument(); + }); + + it('should respect warnText prop', () => { + render( + + ); + + expect(screen.getByText('This is warning text')).toBeInTheDocument(); + expect(screen.getByText('This is warning text')).toHaveClass( + `${prefix}--form-requirement` + ); + }); + }); + + describe('behaves as expected - Component API', () => { + it('should respect onChange prop', () => { + const onChange = jest.fn(); + render( + + ); + + userEvent.type(screen.getByRole('textbox'), 'x'); + expect(screen.getByRole('textbox')).toHaveValue('x'); + expect(onChange).toHaveBeenCalledTimes(1); + expect(onChange).toHaveBeenCalledWith( + expect.objectContaining({ + target: expect.any(Object), + }) + ); + }); + + it('should respect onClick prop', () => { + const onClick = jest.fn(); + render( + + ); + + userEvent.click(screen.getByRole('textbox')); + expect(onClick).toHaveBeenCalledTimes(1); + expect(onClick).toHaveBeenCalledWith( + expect.objectContaining({ + target: expect.any(Object), + }) + ); + }); + + it('should not call `onClick` when the `` is clicked but disabled', () => { + const onClick = jest.fn(); + render( + + ); + + userEvent.click(screen.getByRole('textbox')); + expect(onClick).not.toHaveBeenCalled(); + }); + + it('should respect readOnly prop', () => { + const onChange = jest.fn(); + const onClick = jest.fn(); + const { container } = render( + + ); + + // Click events should fire + userEvent.click(screen.getByRole('textbox')); + expect(onClick).toHaveBeenCalledTimes(1); + + // Change events should *not* fire + userEvent.type(screen.getByRole('textbox'), 'x'); + expect(screen.getByRole('textbox')).not.toHaveValue('x'); + expect(onChange).toHaveBeenCalledTimes(0); + + // Should display the "read-only" icon + const icon = container.querySelector( + `svg.${prefix}--text-input__readonly-icon` + ); + expect(icon).toBeInTheDocument(); + }); + }); +}); From f0a584424ee90196e6d8d6a31a82f5c29702d2d3 Mon Sep 17 00:00:00 2001 From: TJ Egan Date: Mon, 29 Aug 2022 16:07:10 +0200 Subject: [PATCH 10/12] chore(FluidTextInput): export under unstable prefix --- .../src/components/FluidTextInput/FluidTextInput.stories.js | 2 +- packages/react/src/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js b/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js index bdcf2d4105c2..62e89130ae25 100644 --- a/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js +++ b/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js @@ -17,7 +17,7 @@ import { Information } from '@carbon/icons-react'; import './test.scss'; export default { - title: 'Components/FluidTextInput', + title: 'Experimental/unstable__FluidTextInput', component: FluidTextInput, }; diff --git a/packages/react/src/index.js b/packages/react/src/index.js index d5cd712fcda8..9c0006811ab5 100644 --- a/packages/react/src/index.js +++ b/packages/react/src/index.js @@ -66,7 +66,6 @@ export FileUploader, { export { FilterableMultiSelect } from './components/FilterableMultiSelect'; export Form from './components/Form'; export FluidForm from './components/FluidForm'; -export FluidTextInput from './components/FluidTextInput'; export FormGroup from './components/FormGroup'; export FormItem from './components/FormItem'; export FormLabel from './components/FormLabel'; @@ -214,6 +213,7 @@ export { useFeatureFlag as unstable_useFeatureFlag, useFeatureFlags as unstable_useFeatureFlags, } from './components/FeatureFlags'; +export { FluidTextInput as unstable__FluidTextInput } from './components/FluidTextInput'; export { Heading, Section } from './components/Heading'; export { IconButton } from './components/IconButton'; export { Layer, useLayer } from './components/Layer'; From 0ec410c53337071f218211a42ee8c80fbbdab070 Mon Sep 17 00:00:00 2001 From: TJ Egan Date: Mon, 29 Aug 2022 16:32:21 +0200 Subject: [PATCH 11/12] test(FluidTextInput): update snapshot --- .../FluidTextInput/FluidTextInput-test.e2e.js | 4 +- .../__snapshots__/PublicAPI-test.js.snap | 130 +++++++++--------- packages/react/src/__tests__/index-test.js | 2 +- .../src/components/FluidTextInput/index.js | 2 +- 4 files changed, 69 insertions(+), 69 deletions(-) diff --git a/e2e/components/FluidTextInput/FluidTextInput-test.e2e.js b/e2e/components/FluidTextInput/FluidTextInput-test.e2e.js index 2cf30c309135..b0d752edd574 100644 --- a/e2e/components/FluidTextInput/FluidTextInput-test.e2e.js +++ b/e2e/components/FluidTextInput/FluidTextInput-test.e2e.js @@ -17,7 +17,7 @@ test.describe('FluidTextInput', () => { test('fluid text input @vrt', async ({ page }) => { await snapshotStory(page, { component: 'FluidTextInput', - id: 'components-fluidtextinput--default', + id: 'experimental-unstable-fluidtextinput--default', theme, }); }); @@ -27,7 +27,7 @@ test.describe('FluidTextInput', () => { test('accessibility-checker @avt', async ({ page }) => { await visitStory(page, { component: 'FluidTextInput', - id: 'components-fluidtextinput--default', + id: 'experimental-unstable-fluidtextinput--default', globals: { theme: 'white', }, diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index fe9ec438dd78..13c08311100b 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -3334,71 +3334,6 @@ Map { }, }, }, - "FluidTextInput" => Object { - "propTypes": Object { - "className": Object { - "type": "string", - }, - "defaultValue": Object { - "args": Array [ - Array [ - Object { - "type": "string", - }, - Object { - "type": "number", - }, - ], - ], - "type": "oneOfType", - }, - "disabled": Object { - "type": "bool", - }, - "id": Object { - "isRequired": true, - "type": "string", - }, - "invalid": Object { - "type": "bool", - }, - "invalidText": Object { - "type": "node", - }, - "labelText": Object { - "isRequired": true, - "type": "node", - }, - "onChange": Object { - "type": "func", - }, - "onClick": Object { - "type": "func", - }, - "placeholder": Object { - "type": "string", - }, - "value": Object { - "args": Array [ - Array [ - Object { - "type": "string", - }, - Object { - "type": "number", - }, - ], - ], - "type": "oneOfType", - }, - "warn": Object { - "type": "bool", - }, - "warnText": Object { - "type": "node", - }, - }, - }, "Form" => Object { "propTypes": Object { "children": Object { @@ -9230,6 +9165,71 @@ Map { }, }, }, + "unstable__FluidTextInput" => Object { + "propTypes": Object { + "className": Object { + "type": "string", + }, + "defaultValue": Object { + "args": Array [ + Array [ + Object { + "type": "string", + }, + Object { + "type": "number", + }, + ], + ], + "type": "oneOfType", + }, + "disabled": Object { + "type": "bool", + }, + "id": Object { + "isRequired": true, + "type": "string", + }, + "invalid": Object { + "type": "bool", + }, + "invalidText": Object { + "type": "node", + }, + "labelText": Object { + "isRequired": true, + "type": "node", + }, + "onChange": Object { + "type": "func", + }, + "onClick": Object { + "type": "func", + }, + "placeholder": Object { + "type": "string", + }, + "value": Object { + "args": Array [ + Array [ + Object { + "type": "string", + }, + Object { + "type": "number", + }, + ], + ], + "type": "oneOfType", + }, + "warn": Object { + "type": "bool", + }, + "warnText": Object { + "type": "node", + }, + }, + }, "unstable_useContextMenu" => Object {}, "unstable_useFeatureFlag" => Object {}, "unstable_useFeatureFlags" => Object {}, diff --git a/packages/react/src/__tests__/index-test.js b/packages/react/src/__tests__/index-test.js index d1e8e8658fad..62077eab9c9a 100644 --- a/packages/react/src/__tests__/index-test.js +++ b/packages/react/src/__tests__/index-test.js @@ -63,7 +63,6 @@ describe('Carbon Components React', () => { "FilterableMultiSelect", "FlexGrid", "FluidForm", - "FluidTextInput", "Form", "FormGroup", "FormItem", @@ -230,6 +229,7 @@ describe('Carbon Components React', () => { "unstable_Pagination", "unstable_Text", "unstable_TextDirection", + "unstable__FluidTextInput", "unstable_useContextMenu", "unstable_useFeatureFlag", "unstable_useFeatureFlags", diff --git a/packages/react/src/components/FluidTextInput/index.js b/packages/react/src/components/FluidTextInput/index.js index df90b5ae9178..ad8946d3e7f9 100644 --- a/packages/react/src/components/FluidTextInput/index.js +++ b/packages/react/src/components/FluidTextInput/index.js @@ -6,4 +6,4 @@ */ export default from './FluidTextInput'; -export { FluidTextInput } from './FluidTextInput'; +export FluidTextInput from './FluidTextInput'; From 99fe42212033a96b1cb4dd05ed0991de16a3983a Mon Sep 17 00:00:00 2001 From: TJ Egan Date: Tue, 30 Aug 2022 18:26:54 +0200 Subject: [PATCH 12/12] chore(FluidTextInput): remove test story --- .../FluidTextInput/FluidTextInput.stories.js | 51 ------------------- 1 file changed, 51 deletions(-) diff --git a/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js b/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js index 62e89130ae25..93d3beef886c 100644 --- a/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js +++ b/packages/react/src/components/FluidTextInput/FluidTextInput.stories.js @@ -25,57 +25,6 @@ export const Default = () => ( ); -export const Test = () => ( - <> -
- - - - - -
-
- - - - - -
- -); - const ToggleTip = ( <> Label