Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(textarea): added char counter #10442

Merged
merged 21 commits into from
Feb 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
6670f90
feat(textarea): added char counter
TannerS Jan 6, 2022
0f55482
feat(textarea): added value prop into consideration with count
TannerS Jan 7, 2022
8bf2116
Merge branch 'main' into tanner_textAreaCounter
TannerS Jan 13, 2022
e86bb81
Merge branch 'main' into tanner_textAreaCounter
TannerS Jan 14, 2022
52cab86
Merge branch 'main' into tanner_textAreaCounter
TannerS Jan 15, 2022
16e5a35
Merge branch 'main' into tanner_textAreaCounter
TannerS Jan 19, 2022
8453e94
Merge branch 'main' into tanner_textAreaCounter
TannerS Jan 21, 2022
7c98273
Merge branch 'main' into tanner_textAreaCounter
Jan 24, 2022
b3ac185
feat(textarea): updated styles to use text area
Jan 25, 2022
2481afd
feat(textarea): updated unit test
Jan 25, 2022
bccf667
feat(textarea): updated styles
TannerS Jan 25, 2022
62dc9a9
Merge branch 'main' into tanner_textAreaCounter
Jan 25, 2022
014b6fd
Merge branch 'main' into tanner_textAreaCounter
TannerS Feb 1, 2022
3c860b3
Merge branch 'main' into tanner_textAreaCounter
Feb 1, 2022
a9a4d0f
chore(react): updated file after running yarn test -u after main merge
TannerS Feb 2, 2022
92cb652
Merge branch 'main' into tanner_textAreaCounter
TannerS Feb 2, 2022
8d10cf3
fix(react): fixed textarea counter limit still limiting when not enabled
TannerS Feb 3, 2022
9ab7860
Merge branch 'main' into tanner_textAreaCounter
Feb 3, 2022
4a30986
Merge branch 'main' into tanner_textAreaCounter
Feb 3, 2022
2982cf8
chore(react): edited how textarea maxCount prop is set
Feb 4, 2022
dbe11e4
Merge branch 'main' into tanner_textAreaCounter
kodiakhq[bot] Feb 7, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@
color: transparent;
}
}

.#{$prefix}--text-area__label-wrapper {
display: flex;
width: 100%;
justify-content: space-between;
}
tw15egan marked this conversation as resolved.
Show resolved Hide resolved
}

@include exports('text-area') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6859,10 +6859,12 @@ Map {
"defaultProps": Object {
"cols": 50,
"disabled": false,
"enableCounter": false,
"helperText": "",
"invalid": false,
"invalidText": "",
"light": false,
"maxCount": undefined,
"onChange": [Function],
"onClick": [Function],
"placeholder": "",
Expand Down Expand Up @@ -6891,6 +6893,9 @@ Map {
"disabled": Object {
"type": "bool",
},
"enableCounter": Object {
"type": "bool",
},
"helperText": Object {
"type": "node",
},
Expand All @@ -6913,6 +6918,9 @@ Map {
"light": Object {
"type": "bool",
},
"maxCount": Object {
"type": "number",
},
"onChange": Object {
"type": "func",
},
Expand Down
5 changes: 5 additions & 0 deletions packages/react/src/components/TextArea/TextArea-story.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ const TextAreaProps = () => ({
'A valid value is required'
),
helperText: text('Helper text (helperText)', 'Optional helper text.'),
enableCounter: boolean(
'Enable character counter/limit (enableCounter)',
false
),
maxCount: number('Character limit (maxCount)', undefined),
id: 'test2',
cols: number('Columns (columns)', 50),
rows: number('Rows (rows)', 4),
Expand Down
50 changes: 50 additions & 0 deletions packages/react/src/components/TextArea/TextArea-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,16 @@ describe('TextArea', () => {
wrapper.setProps({ light: true });
expect(wrapper.props().light).toEqual(true);
});

it('should set enableCounter as expected', () => {
wrapper.setProps({ enableCounter: true });
expect(wrapper.props().enableCounter).toEqual(true);
});

it('should set maxCount as expected', () => {
wrapper.setProps({ maxCount: 5 });
expect(wrapper.props().maxCount).toEqual(5);
});
});

describe('label', () => {
Expand Down Expand Up @@ -117,6 +127,46 @@ describe('TextArea', () => {
expect(renderedHelper.text()).toEqual('Helper text');
});
});

describe('counter', () => {
const counterTestWrapper1 = mount(
<TextArea id="counter1" labelText="someLabel" enableCounter={true} />
);

const counterTestWrapper2 = mount(
<TextArea id="counter2" labelText="someLabel" maxCount={5} />
);

it('should not render element without only enableCounter prop passed in', () => {
expect(
counterTestWrapper1.exists(`${prefix}--text-area__counter`)
).toEqual(false);
});

it('should not render element without only maxCount prop passed in', () => {
expect(
counterTestWrapper2.exists(`${prefix}--text-area__counter`)
).toEqual(false);
});

it('has the expected classes', () => {
const counterTextarea = () =>
counterTestWrapper1.find(`.${prefix}--text-area__counter`);
expect(counterTextarea).not.toBeNull();
});

it('should have label and counter disabled', () => {
counterTestWrapper1.setProps({ disabled: true });
const wrapper = counterTestWrapper1.find(
`.${prefix}--text-area__label-wrapper`
);
const labels = wrapper.find(`.${prefix}--label`);

labels.forEach((node) => {
expect(node.hasClass(`${prefix}--label--disabled`)).toEqual(true);
});
});
});
});

describe('events', () => {
Expand Down
41 changes: 38 additions & 3 deletions packages/react/src/components/TextArea/TextArea.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import PropTypes from 'prop-types';
import React from 'react';
import React, { useState } from 'react';
import classNames from 'classnames';
import { WarningFilled16 } from '@carbon/icons-react';
import { useFeatureFlag } from '../FeatureFlags';
Expand All @@ -25,17 +25,24 @@ const TextArea = React.forwardRef(function TextArea(
helperText,
light,
placeholder,
enableCounter,
maxCount,
...other
},
ref
) {
const prefix = usePrefix();
const enabled = useFeatureFlag('enable-v11-release');
const { defaultValue, value, disabled } = other;
const [textCount, setTextCount] = useState(
defaultValue?.length || value?.length || 0
);

const textareaProps = {
id,
onChange: (evt) => {
if (!other.disabled) {
setTextCount(evt.target.value?.length);
onChange(evt);
}
},
Expand All @@ -47,9 +54,13 @@ const TextArea = React.forwardRef(function TextArea(
ref,
};

if (enableCounter) {
textareaProps.maxLength = maxCount;
}

Comment on lines +57 to +60
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const labelClasses = classNames(`${prefix}--label`, {
[`${prefix}--visually-hidden`]: hideLabel,
[`${prefix}--label--disabled`]: other.disabled,
[`${prefix}--label--disabled`]: disabled,
});

const label = labelText ? (
Expand All @@ -58,6 +69,15 @@ const TextArea = React.forwardRef(function TextArea(
</label>
) : null;

const counterClasses = classNames(`${prefix}--label`, {
[`${prefix}--label--disabled`]: disabled,
});

const counter =
enableCounter && maxCount ? (
<div className={counterClasses}>{`${textCount}/${maxCount}`}</div>
) : null;

const helperTextClasses = classNames(`${prefix}--form__helper-text`, {
[`${prefix}--form__helper-text--disabled`]: other.disabled,
});
Expand Down Expand Up @@ -102,7 +122,10 @@ const TextArea = React.forwardRef(function TextArea(
? classNames(`${prefix}--form-item`, className)
: `${prefix}--form-item`
}>
{label}
<div className={`${prefix}--text-area__label-wrapper`}>
{label}
{counter}
</div>
<div
className={`${prefix}--text-area__wrapper`}
data-invalid={invalid || null}>
Expand Down Expand Up @@ -139,6 +162,11 @@ TextArea.propTypes = {
*/
disabled: PropTypes.bool,

/**
* Specify whether to display the character counter
*/
enableCounter: PropTypes.bool,
tw15egan marked this conversation as resolved.
Show resolved Hide resolved

/**
* Provide text that is used alongside the control label for additional help
*/
Expand Down Expand Up @@ -176,6 +204,11 @@ TextArea.propTypes = {
*/
light: PropTypes.bool,

/**
* Max character count allowed for the textarea. This is needed in order for enableCounter to display
*/
maxCount: PropTypes.number,

/**
* Optionally provide an `onChange` handler that is called whenever `<textarea>`
* is updated
Expand Down Expand Up @@ -215,6 +248,8 @@ TextArea.defaultProps = {
invalidText: '',
helperText: '',
light: false,
enableCounter: false,
maxCount: undefined,
};

export default TextArea;
6 changes: 6 additions & 0 deletions packages/styles/scss/components/text-area/_text-area.scss
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,10 @@
color: transparent;
}
}

.#{$prefix}--text-area__label-wrapper {
display: flex;
width: 100%;
TannerS marked this conversation as resolved.
Show resolved Hide resolved
justify-content: space-between;
}
}