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: [ASL-4632] Word count component #352

Merged
merged 30 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
e5ed7aa
word count changes working
kiran-varma-home-office Nov 18, 2024
c820430
added govuk css
kiran-varma-home-office Nov 19, 2024
4c3e730
reafactor cleanup
kiran-varma-home-office Nov 19, 2024
d565817
minor refactor
kiran-varma-home-office Nov 19, 2024
ac74044
add aria desc
kiran-varma-home-office Nov 19, 2024
420913b
add eol
kiran-varma-home-office Nov 19, 2024
3f15b3a
add eol
kiran-varma-home-office Nov 19, 2024
1ef842f
rename
kiran-varma-home-office Nov 19, 2024
bf1b4ee
remove govuk-frontend dep
kiran-varma-home-office Nov 19, 2024
75506cc
add aria to textarea
kiran-varma-home-office Nov 19, 2024
0909e00
added tests and minor refactor
kiran-varma-home-office Nov 19, 2024
139c403
give form an id
kiran-varma-home-office Nov 19, 2024
46fb98b
Merge branch 'main' into feat/asl-4566-wordcount-component
kiran-varma-home-office Nov 19, 2024
c67b7b5
version update
kiran-varma-home-office Nov 19, 2024
abea8a2
update test titles
kiran-varma-home-office Nov 19, 2024
bf488b3
refactor WordCountHintMessage component
kiran-varma-home-office Nov 21, 2024
fd0e829
fix tests
kiran-varma-home-office Nov 21, 2024
144fc45
remove useCallback
kiran-varma-home-office Nov 21, 2024
8eb327c
remove unused prop from textArea
kiran-varma-home-office Nov 21, 2024
4352630
add more tests
kiran-varma-home-office Nov 21, 2024
0d8cf73
refactor test
kiran-varma-home-office Nov 21, 2024
ddc668b
minor refactor
kiran-varma-home-office Nov 21, 2024
939cf57
refactor - rename
kiran-varma-home-office Nov 21, 2024
c8843f1
fix test
kiran-varma-home-office Nov 21, 2024
b26a073
more refactor to fix warning
kiran-varma-home-office Nov 21, 2024
b635621
update css path
kiran-varma-home-office Nov 21, 2024
4546a53
eof nl
kiran-varma-home-office Nov 21, 2024
cfcb424
eof nl
kiran-varma-home-office Nov 21, 2024
15fd32f
Update src/text-area-word-count/index.spec.jsx
kiran-varma-home-office Nov 21, 2024
e6cfd0e
minor refactor
kiran-varma-home-office Nov 21, 2024
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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"classnames": "^2.2.6",
"date-fns": "^3.6.0",
"diff": "^4.0.1",
"govuk-frontend": "^5.7.1",
jeff-horton-ho-sas marked this conversation as resolved.
Show resolved Hide resolved
"lodash": "^4.17.21",
"moment": "^2.29.4",
"mustache": "^3.0.1",
Expand Down
74 changes: 74 additions & 0 deletions src/character-count/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React, { useState, useCallback } from 'react';
import { TextArea } from '@ukhomeoffice/react-components';
import classNames from 'classnames';

export default function CharacterCount(props) {

const { value, maxWordCount, error } = props;
const getWordCount = text => text?.split(/\s+/).filter(Boolean).length;

const [{ content, wordCount }, setContent] = useState({
content: value,
wordCount: getWordCount(value) ?? 0,
});

const handleChange = useCallback(text => {

const wordCount = getWordCount(text);

if (wordCount > maxWordCount) {
setContent({
content: text,
wordCount
});
} else {
setContent({
content: text,
wordCount
});
}
},[maxWordCount, content]);

const wordCountHintMessage = wordCount => {
if (!wordCount) {
return (
<div id="with-hint-info" className="govuk-hint govuk-character-count__message">
You have {maxWordCount} words remaining
</div>
);
}

if (wordCount > maxWordCount) {
const count = wordCount - maxWordCount;
return (
<div className="govuk-hint govuk-character-count__message">
You have {count === 1 ? count + ' word' : count + ' words' } too many
</div>
);
} else {
const count = maxWordCount - wordCount;
return (
<div className="govuk-hint govuk-character-count__message">
You have {count === 1 ? count + ' word' : count + ' words' } remaining
</div>
);
}
};

const formErrorClass = classNames({
'govuk-form-group': true,
'govuk-character-count': true,
'govuk-form-group--error': error
});

return (
<div className={formErrorClass}>
<TextArea
{...props}
value={content}
onChange={e => handleChange(e.target.value)}
/>
{wordCountHintMessage(wordCount)}
</div>
);
}
28 changes: 28 additions & 0 deletions src/character-count/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Added from govuk-frotnend

.govuk-character-count {
@include govuk-responsive-margin(6, "bottom");

.govuk-form-group,
.govuk-textarea {
margin-bottom: govuk-spacing(1);
}
}

.govuk-character-count__message {
margin-top: 0;
margin-bottom: 0;

&::after {
// Zero-width space that will reserve vertical space when no hint is
// provided as:
// - setting a min-height is not possible without a magic number because
// the line-height is set by the `govuk-font` call above
// - using `:empty` is not possible as the hint macro outputs line breaks
content: "\200B";
}
}

.govuk-character-count__message--disabled {
visibility: hidden;
}
4 changes: 3 additions & 1 deletion src/fieldset/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ import {
MultiInput,
DurationField,
SelectMany,
Inset
Inset,
CharacterCount
} from '../';

function getLabel(opt, name, type = 'label') {
Expand Down Expand Up @@ -70,6 +71,7 @@ const fields = {
declaration: props => <ApplicationConfirm { ...props } />,
inputDate: props => <DateInput { ...props } onChange={value => props.onChange({ target: { value } })} />,
textarea: props => <TextArea { ...omit(props, ['meta']) } autoExpand={true} />,
textAreaWithWordCount: props => <CharacterCount { ...omit(props, ['meta'])} maxWordCount = {250} />,
radioGroup: props => {
if (!props.options) {
throw new Error(`radioGroup '${props.name}' has undefined options`);
Expand Down
1 change: 1 addition & 0 deletions src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export { default as ApplicationConfirm } from './application-confirm';
export { default as ApplyChanges } from './apply-changes';
export { default as BackToTop } from './back-to-top';
export { default as Breadcrumbs } from './breadcrumbs';
export { default as CharacterCount } from './character-count';
export { default as Completable } from './completable';
export { default as Controls } from './controls';
export { default as ControlBar } from './control-bar';
Expand Down
1 change: 1 addition & 0 deletions styles/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ $highlight-colour: govuk-colour('grey-4');
@import '../src/sticky-nav-anchor/index';
@import '../src/tabs/index';
@import '../src/licence-status-banner/index';
@import '../src/character-count/index';

.hidden {
display: none;
Expand Down
Loading