Skip to content

Commit

Permalink
refactor(Field): ♻️ merge CharacterCounter into Field (#2717)
Browse files Browse the repository at this point in the history
- Created new `Field.Counter` to replace `CharacterCounter`
- Will delete old `CharacterCounter` in #2710 when use is replaced with
`Field.Counter` there
- [Example
story](https://pr-2717.storybook.designsystemet.no/?path=/story/komponenter-field--counter)

---------

Co-authored-by: Eirik Backer <[email protected]>
  • Loading branch information
mimarz and eirikbacker authored Nov 1, 2024
1 parent f71573f commit af03291
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 1 deletion.
4 changes: 4 additions & 0 deletions packages/react/src/components/form/Field/Field.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ Du skal **ikke** bruke disse alene, siden skjermlesere ikke leser dem opp.
Det er viktig at samme informasjon som vises i prefixet eller suffixet også er inkludert i ledeteksten.

<Canvas of={FieldStories.Adornments} />

## Antall tegn

<Canvas of={FieldStories.Counter} />
8 changes: 8 additions & 0 deletions packages/react/src/components/form/Field/Field.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,11 @@ export const Adornments: Story = () => (
</Field>
</div>
);

export const Counter: Story = () => (
<Field>
<Label>Legg til en beskrivelse</Label>
<Textarea rows={2} />
<Field.Counter limit={10} />
</Field>
);
66 changes: 66 additions & 0 deletions packages/react/src/components/form/Field/FieldCounter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { forwardRef, useEffect, useRef, useState } from 'react';
import {
ValidationMessage,
type ValidationMessageProps,
} from '../../ValidationMessage';

export type FieldCounterProps = {
/** Label template for when `maxCount` is exceeded
* @default '%d tegn for mye'
*/
over?: string;
/** Label template for count
* @default '%d tegn igjen'
*/
under?: string;
/** The maximum allowed characters. */
limit: number;
} & ValidationMessageProps;

const label = (text: string, count: number) =>
text.replace('%d', Math.abs(count).toString());

export const FieldCounter = forwardRef<HTMLParagraphElement, FieldCounterProps>(
function FieldCounter(
{ limit, under = '%d tegn igjen', over = '%d tegn for mye', ...rest },
ref,
) {
const [count, setCount] = useState(0);
const counterRef = useRef<HTMLDivElement>(null);
const hasExceededLimit = count > limit;
const remainder = limit - count;

useEffect(() => {
const onInput = ({ target }: Event) => {
if (
target instanceof HTMLInputElement ||
target instanceof HTMLTextAreaElement
) {
setCount(target.value.length);
}
};

const field = counterRef.current?.closest('.ds-field');

field?.addEventListener('input', onInput);

return () => field?.removeEventListener('input', onInput);
}, [setCount]);

return (
<>
<div
data-field='description'
className='ds-sr-only'
aria-live={'polite'}
ref={counterRef}
>
{hasExceededLimit && label(over, remainder)}
</div>
<ValidationMessage error={hasExceededLimit} ref={ref} {...rest}>
{label(hasExceededLimit ? over : under, remainder)}
</ValidationMessage>
</>
);
},
);
6 changes: 5 additions & 1 deletion packages/react/src/components/form/Field/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Field as FieldParent } from './Field';
import { FieldAffix, FieldAffixWrapper } from './FieldAffix';
import { FieldCounter } from './FieldCounter';
import { FieldDescription } from './FieldDescription';

/**
Expand All @@ -15,16 +16,19 @@ const Field = Object.assign(FieldParent, {
Description: FieldDescription,
AffixWrapper: FieldAffixWrapper,
Affix: FieldAffix,
Counter: FieldCounter,
});

Field.Description.displayName = 'Field.Description';
Field.AffixWrapper.displayName = 'Field.AffixWrapper';
Field.Affix.displayName = 'Field.Affix';
Field.Counter.displayName = 'Field.Counter';

export type { FieldCounterProps } from './FieldCounter';
export type {
FieldAffixProps,
FieldAffixWrapperProps,
} from './FieldAffix';
export type { FieldProps } from './Field';
export type { FieldDescriptionProps } from './FieldDescription';
export { Field, FieldDescription, FieldAffix, FieldAffixWrapper };
export { Field, FieldDescription, FieldAffix, FieldAffixWrapper, FieldCounter };

0 comments on commit af03291

Please sign in to comment.