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

chore(Textarea): add support for object based characterCounter #3260

Merged
merged 1 commit into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -62,8 +62,7 @@ export const TextareaCharacterCounter = () => (
autoresize
value="Textarea value\nNewline"
status="Message to the user"
characterCounter
maxLength={40}
characterCounter={40}
/>
</ComponentBox>
</Wrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ showTabs: true
| `label_sr_only` | _(optional)_ use `true` to make the label only readable by screen readers. |
| `autoresize` | _(optional)_ use `true` to make the Textarea grow and shrink depending on how many lines the user has filled. |
| `autoresize_max_rows` | _(optional)_ set a number to define how many rows the Textarea can auto grow. |
| `characterCounter` | _(optional)_ use `up` or `down` or `true` (down) to show a character counter. You need to set a `maxLength={number}` in order to show the counter. |
| `characterCounter` | _(optional)_ use a number to define the displayed max length. You can also use an object defining the [TextCounter](/uilib/fragments/TextCounter/) `variant` or properties. Please avoid using `maxLength` for accessibility reasons. |
| `status` | _(optional)_ text with a status message. The style defaults to an error message. You can use `true` to only get the status color, without a message. |
| `status_state` | _(optional)_ defines the state of the status. Currently, there are two statuses `[error, info]`. Defaults to `error`. |
| `status_props` | _(optional)_ use an object to define additional FormStatus properties. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,28 @@ import DataValueReadwriteProperties from '../../data-value-readwrite-properties.

### Component-specific props

| Property | Type | Description |
| --------------------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type` | `string` | _(optional)_ Input DOM element type. |
| `multiline` | `boolean` | _(optional)_ True to be able to write in multiple lines (switching from input-element to textarea-element). |
| `leftIcon` | `string` | _(optional)_ For icon at the left side of the text input. |
| `rightIcon` | `string` | _(optional)_ For icon at the right side of the text input. |
| `inputClassName` | `string` | _(optional)_ Class name set on the &lt;input&gt; DOM element. |
| `innerRef` | `React.ref` | _(optional)_ by providing a React.ref we can get the internally used input element (DOM). E.g. `innerRef={myRef}` by using `React.createRef()` or `React.useRef()`. |
| `clear` | `boolean` | _(optional)_ True to have a clickable clear-icon for removing the active value. |
| `autoresize` | `boolean` | _(optional)_ For `multiline`, set `true` to expand when writing longer texts. |
| `autoComplete` | `on` or `string` | _(optional)_ For HTML `autocomplete` [attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete). |
| `capitalize` | `boolean` | _(optional)_ When set to `true`, it will capitalize the first letter of every word, transforming the rest to lowercase. |
| `trim` | `boolean` | _(optional)_ When `true`, it will trim leading and trailing whitespaces on blur, triggering onChange if the value changes. |
| `inputMode` | `string` | _(optional)_ Define a [inputmode](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode). |
| `autoresizeMaxRows` | `boolean` | _(optional)_ For `multiline`, set how many rows of text can be shown at max. |
| `characterCounter` | `boolean` or `string` | _(optional)_ Use `up` or `down` or `true` (down) to show a character counter. You need to set a `maxLength={number}` as well as have `multiline` enabled in order to show the counter. |
| `minLength` | `number` | _(optional)_ Validation for minimum length of the text (number of characters). |
| `maxLength` | `number` | _(optional)_ Validation for maximum length of the text (number of characters). |
| `pattern` | `string` | _(optional)_ Validation based on regex pattern. |
| `width` | `string` or `false` | _(optional)_ `false` for no width (use browser default), `small`, `medium` or `large` for predefined standard widths, `stretch` for fill available width. |
| `help` | `object` | _(optional)_ Provide a help button. Object consisting of `title` and `content`. |
| [Space](/uilib/layout/space/properties) | Various | _(optional)_ Spacing properties like `top` or `bottom` are supported. |
| Property | Type | Description |
| --------------------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type` | `string` | _(optional)_ Input DOM element type. |
| `multiline` | `boolean` | _(optional)_ True to be able to write in multiple lines (switching from input-element to textarea-element). |
| `leftIcon` | `string` | _(optional)_ For icon at the left side of the text input. |
| `rightIcon` | `string` | _(optional)_ For icon at the right side of the text input. |
| `inputClassName` | `string` | _(optional)_ Class name set on the &lt;input&gt; DOM element. |
| `innerRef` | `React.ref` | _(optional)_ by providing a React.ref we can get the internally used input element (DOM). E.g. `innerRef={myRef}` by using `React.createRef()` or `React.useRef()`. |
| `clear` | `boolean` | _(optional)_ True to have a clickable clear-icon for removing the active value. |
| `autoresize` | `boolean` | _(optional)_ For `multiline`, set `true` to expand when writing longer texts. |
| `autoComplete` | `on` or `string` | _(optional)_ For HTML `autocomplete` [attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete). |
| `capitalize` | `boolean` | _(optional)_ When set to `true`, it will capitalize the first letter of every word, transforming the rest to lowercase. |
| `trim` | `boolean` | _(optional)_ When `true`, it will trim leading and trailing whitespaces on blur, triggering onChange if the value changes. |
| `inputMode` | `string` | _(optional)_ Define a [inputmode](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode). |
| `autoresizeMaxRows` | `boolean` | _(optional)_ For `multiline`, set how many rows of text can be shown at max. |
| `characterCounter` | `boolean` or `string` | _(optional)_ For `multiline`, use a number to define the displayed max length. You can also use an object defining the [TextCounter](/uilib/fragments/TextCounter/) `variant` or properties. |
| `minLength` | `number` | _(optional)_ Validation for minimum length of the text (number of characters). |
| `maxLength` | `number` | _(optional)_ Validation for maximum length of the text (number of characters). |
| `pattern` | `string` | _(optional)_ Validation based on regex pattern. |
| `width` | `string` or `false` | _(optional)_ `false` for no width (use browser default), `small`, `medium` or `large` for predefined standard widths, `stretch` for fill available width. |
| `help` | `object` | _(optional)_ Provide a help button. Object consisting of `title` and `content`. |
| [Space](/uilib/layout/space/properties) | Various | _(optional)_ Spacing properties like `top` or `bottom` are supported. |

## Properties

Expand Down
3 changes: 2 additions & 1 deletion packages/dnb-eufemia/src/components/textarea/Textarea.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { SkeletonShow } from '../Skeleton';
import type { SpacingProps } from '../space/types';
import type { FormLabelLabelDirection, FormLabelText } from '../FormLabel';
import type { GlobalStatusConfigObject } from '../GlobalStatus';
import type { TextCounterProps } from '../../fragments/TextCounter';
export type TextareaSuffix =
| string
| ((...args: any[]) => any)
Expand Down Expand Up @@ -90,7 +91,7 @@ export interface TextareaProps
/**
* Use `up` or `down` or `true` (down) to show a character counter. You need to set a `maxLength={number}` in order to show the counter.
*/
characterCounter?: boolean;
characterCounter?: Omit<TextCounterProps, 'text'> | number;
/**
* Set a number to define how many rows the Textarea can auto grow.
*/
Expand Down
15 changes: 8 additions & 7 deletions packages/dnb-eufemia/src/components/textarea/Textarea.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,11 @@ export default class Textarea extends React.PureComponent {
disabled: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
skeleton: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
characterCounter: PropTypes.oneOfType([
PropTypes.oneOf(['down', 'up']),
PropTypes.bool,
PropTypes.shape({
max: PropTypes.number,
variant: PropTypes.oneOf(['down', 'up']),
}),
PropTypes.number,
]),
autoresize: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
autoresize_max_rows: PropTypes.oneOfType([
Expand Down Expand Up @@ -374,7 +377,6 @@ export default class Textarea extends React.PureComponent {
className,
autoresize,
characterCounter,
maxLength,
autoresize_max_rows, //eslint-disable-line
id: _id, //eslint-disable-line
children, //eslint-disable-line
Expand Down Expand Up @@ -405,7 +407,6 @@ export default class Textarea extends React.PureComponent {
value: hasValue ? value : '',
id,
name: id,
maxLength,
disabled: isTrue(disabled) || isTrue(skeleton),
'aria-placeholder': placeholder,
...attributes,
Expand Down Expand Up @@ -547,14 +548,14 @@ export default class Textarea extends React.PureComponent {
)}
</span>

{characterCounter && maxLength > 0 && (
{characterCounter && (
<TextCounter
variant={characterCounter}
text={value}
max={maxLength}
max={characterCounter}
bypassAriaLive={textareaState === 'virgin'}
lang={this.props.lang}
locale={this.props.locale}
{...characterCounter}
/>
)}
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ describe('Textarea component', () => {

it('should render characterCounter', async () => {
const { rerender } = render(
<Textarea maxLength={8} characterCounter value="foo" />
<Textarea characterCounter={{ max: 8 }} value="foo" />
)

const counter = document.querySelector('.dnb-text-counter__message')
Expand All @@ -315,14 +315,24 @@ describe('Textarea component', () => {
expect(ariaLive).toHaveTextContent('6 av 8 tegn gjenstår')

rerender(
<Textarea maxLength={8} characterCounter value="foo" lang="en-GB" />
<Textarea characterCounter={{ max: 8 }} value="foo" lang="en-GB" />
)

expect(counter).toHaveTextContent('6 of 8 characters remaining')

await userEvent.type(textarea, 'baz')

expect(ariaLive).toHaveTextContent('8 of 8 characters remaining')

rerender(
<Textarea
characterCounter={{ max: 8, variant: 'up' }}
value="foo"
lang="en-GB"
/>
)

expect(counter).toHaveTextContent('You have used 8 of 8 characters')
})
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import InputMasked, {
import SharedContext from '../../../../shared/Context'
import FieldBlock from '../../FieldBlock'
import { useDataValue } from '../../hooks'
import { FieldProps, FieldHelpProps, JSONSchema } from '../../types'
import { pickSpacingProps } from '../../../../components/flex/utils'
import { toCapitalized } from '../../../../shared/component-helper'
import type { TextCounterProps } from '../../../../fragments/TextCounter'
import type { FieldProps, FieldHelpProps, JSONSchema } from '../../types'

interface ErrorMessages {
required?: string
Expand All @@ -32,7 +33,7 @@ export type Props = FieldHelpProps &
autoComplete?: HTMLInputElement['autocomplete']
inputMode?: React.HTMLAttributes<HTMLInputElement>['inputMode']
autoresizeMaxRows?: number
characterCounter?: boolean
characterCounter?: Omit<TextCounterProps, 'text'> | number
mask?: InputMaskedProps['mask']
// Validation
minLength?: number
Expand Down Expand Up @@ -200,7 +201,6 @@ function StringComponent(props: Props) {
autoresize={autoresize}
autoresize_max_rows={autoresizeMaxRows}
characterCounter={characterCounter}
maxLength={characterCounter ? props.maxLength : undefined}
/>
) : mask ? (
<InputMasked
Expand Down
Loading
Loading