Skip to content

Commit 272d552

Browse files
Add character count support for countFunction option
1 parent 69cc57c commit 272d552

2 files changed

Lines changed: 43 additions & 4 deletions

File tree

packages/nhsuk-frontend/src/nhsuk/components/character-count/character-count.jsdom.test.mjs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,42 @@ describe('Character count', () => {
390390

391391
expect(component.getCountMessage()).toBe('You have 97 words remaining')
392392
})
393+
394+
it('uses custom `countFunction` for `maxlength` limit when set', async () => {
395+
const component = new CharacterCount($root, {
396+
maxlength: 100,
397+
countFunction: jest.fn().mockReturnValue(10)
398+
})
399+
400+
$textarea.focus()
401+
await user.keyboard('Newly updated value')
402+
403+
expect(component.config.countFunction).toHaveBeenCalledWith(
404+
'Newly updated value',
405+
component.segmenter
406+
)
407+
408+
expect(component.getCountMessage()).toBe(
409+
'You have 90 characters remaining'
410+
)
411+
})
412+
413+
it('uses custom `countFunction` for `maxwords` limit when set', async () => {
414+
const component = new CharacterCount($root, {
415+
maxwords: 100,
416+
countFunction: jest.fn().mockReturnValue(10)
417+
})
418+
419+
$textarea.focus()
420+
await user.keyboard('Newly updated value')
421+
422+
expect(component.config.countFunction).toHaveBeenCalledWith(
423+
'Newly updated value',
424+
component.segmenter
425+
)
426+
427+
expect(component.getCountMessage()).toBe('You have 90 words remaining')
428+
})
393429
})
394430

395431
describe('with HTML lang attribute', () => {

packages/nhsuk-frontend/src/nhsuk/components/character-count/character-count.mjs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export class CharacterCount extends ConfigurableComponent {
6161
const {
6262
i18n,
6363
maxlength,
64+
countFunction,
6465
countType,
6566
screenReaderCountMessageClass,
6667
textareaDescriptionClass,
@@ -72,9 +73,9 @@ export class CharacterCount extends ConfigurableComponent {
7273
locale: closestAttributeValue(this.$root, 'lang')
7374
})
7475

75-
if ('Segmenter' in Intl && countType === 'graphemes') {
76+
if ('Segmenter' in Intl && (countType === 'graphemes' || !!countFunction)) {
7677
this.segmenter = new Intl.Segmenter(this.i18n.locale, {
77-
granularity: 'grapheme'
78+
granularity: countType === 'words' ? 'word' : 'grapheme'
7879
})
7980
}
8081

@@ -212,9 +213,9 @@ export class CharacterCount extends ConfigurableComponent {
212213
*/
213214
updateCount(text) {
214215
const { $textarea } = this
215-
let { countType } = this.config
216+
let { countFunction, countType } = this.config
216217

217-
const countFunction =
218+
countFunction ??=
218219
countType === 'words'
219220
? CharacterCount.countFunctions.words
220221
: CharacterCount.countFunctions.characters
@@ -518,6 +519,7 @@ export class CharacterCount extends ConfigurableComponent {
518519
maxlength: { type: 'number' },
519520
threshold: { type: 'number' },
520521
countType: { type: 'string' },
522+
countFunction: { type: 'function' },
521523
textareaDescriptionClass: { type: 'string' },
522524
visibleCountMessageClass: { type: 'string' },
523525
screenReaderCountMessageClass: { type: 'string' },
@@ -564,6 +566,7 @@ export function initCharacterCounts(options) {
564566
* @property {number} [threshold=0] - The percentage value of the limit at which point the count message is displayed.
565567
* If this attribute is set, the count message will be hidden by default.
566568
* @property {'characters' | 'graphemes' | 'words'} countType - The count type (`"characters"`, `"graphemes"` or `"words"`) used to count the text.
569+
* @property {(text: string, segmenter?: Intl.Segmenter | null) => number} [countFunction] - Custom character or word counting function.
567570
* @property {string} textareaDescriptionClass - Textarea description class
568571
* @property {string} visibleCountMessageClass - Visible count message class
569572
* @property {string} screenReaderCountMessageClass - Screen reader count message class

0 commit comments

Comments
 (0)