Skip to content

Commit

Permalink
chore(Expiry): make Expiry FieldBlock compatible
Browse files Browse the repository at this point in the history
So we can forward labelDescription.
  • Loading branch information
tujoworker committed Jan 21, 2024
1 parent 1aa3338 commit 8b0d3c7
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 51 deletions.
78 changes: 45 additions & 33 deletions packages/dnb-eufemia/src/components/input-masked/MultiInputMask.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export type MultiInputMaskProps<T extends string> = {
SpacingProps

function MultiInputMask<T extends string>({
id = makeUniqueId(),
label,
labelDirection = 'horizontal',
inputs,
Expand Down Expand Up @@ -155,29 +156,35 @@ function MultiInputMask<T extends string>({
status_state={statusState}
suffix={suffix}
stretch={stretch}
input_element={inputs.map((input, index) => (
<MultiInputMaskInput
key={input.id}
{...input}
inputMode={inputMode}
value={values[input.id]}
delimiter={index !== inputs.length - 1 ? delimiter : undefined}
onKeyDown={onKeyDown}
onChange={onChange}
onFocus={() => {
if (onFocus) {
onFocus(values)
input_element={inputs.map(({ id: inputId, ...rest }, index) => {
return (
<MultiInputMaskInput
key={inputId}
id={id}
inputId={inputId}
delimiter={
index !== inputs.length - 1 ? delimiter : undefined
}
}}
onBlur={() => {
if (onBlur) {
onBlur(values)
}
}}
disabled={disabled}
inputRef={getInputRef}
/>
))}
disabled={disabled}
inputMode={inputMode}
onKeyDown={onKeyDown}
onChange={onChange}
onFocus={() => {
if (onFocus) {
onFocus(values)
}
}}
onBlur={() => {
if (onBlur) {
onBlur(values)
}
}}
getInputRef={getInputRef}
{...rest}
value={values[inputId]}
/>
)
})}
/>
</WrapperElement>
)
Expand All @@ -195,12 +202,16 @@ function MultiInputMask<T extends string>({
}

// Utilities
function getInputRef(ref: any) {
function getInputRef(ref?: {
inputRef?: MutableRefObject<HTMLInputElement>
}) {
const inputRef = ref?.inputRef

if (inputRef && !inputRefs.current.includes(inputRef)) {
inputRefs.current.push(inputRef)
}

return inputRef
}

function getKeysToHandle() {
Expand Down Expand Up @@ -238,6 +249,7 @@ function MultiInputMask<T extends string>({
type MultiInputMaskInputProps<T extends string> =
MultiInputMaskInput<T> & {
id: MultiInputMaskInput<T>['id']
inputId: MultiInputMaskInput<T>['id']
label: MultiInputMaskInput<T>['label']
value: string
mask: MultiInputMaskInput<T>['mask']
Expand All @@ -249,32 +261,32 @@ type MultiInputMaskInputProps<T extends string> =
id: string,
placeholderCharacter: MultiInputMaskInput<T>['placeholderCharacter']
) => void
inputRef: any
getInputRef: () => MutableRefObject<HTMLInputElement>
}

function MultiInputMaskInput<T extends string>({
id,
inputId,
label,
value,
mask,
placeholderCharacter,
delimiter,
disabled,
inputRef,
getInputRef,
onKeyDown,
onChange,
onBlur,
onFocus,
...attributes
}: MultiInputMaskInputProps<T>) {
const shouldHighlight = !disabled && /\w+/.test(value)
const markupId = `${id}-${makeUniqueId()}`

return (
<>
<TextMask
id={`${markupId}__input`}
data-mask-id={id}
id={`${id}-${inputId}`}
data-mask-id={inputId}
className={classnames(
'dnb-input__input',
'dnb-multi-input-mask__input',
Expand All @@ -288,8 +300,8 @@ function MultiInputMaskInput<T extends string>({
guide={true}
showMask={true}
keepCharPositions={false} // so we can overwrite next value, if it already exists
aria-labelledby={`${markupId}__label`}
ref={inputRef}
aria-labelledby={`${id}-${inputId}__label`}
ref={getInputRef}
onKeyDown={onKeyDown}
onBlur={onBlur}
onFocus={({ target, ...event }) => {
Expand All @@ -302,15 +314,15 @@ function MultiInputMaskInput<T extends string>({
}}
onChange={(event) => {
onChange(
id,
inputId,
removePlaceholder(event.target.value, placeholderCharacter)
)
}}
{...attributes}
/>
<label
id={`${markupId}__label`}
htmlFor={`${markupId}__input`}
id={`${id}-${inputId}__label`}
htmlFor={`${id}-${inputId}`}
hidden
>
{label}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,39 +107,39 @@ describe('MultiInputMask', () => {
})

it('render inputs based on inputs prop', () => {
render(<MultiInputMask {...defaultProps} />)
render(<MultiInputMask {...defaultProps} id="given-id" />)

const [first, second, third] = Array.from(
document.querySelectorAll('.dnb-multi-input-mask__input')
) as HTMLInputElement[]

expect(first.id).toMatch(new RegExp(/^day-id-\w+__input/))
expect(first.id).toBe('given-id-day')
expect(first.tagName).toBe('INPUT')

expect(second.id).toMatch(new RegExp(/^month-id-\w+__input/))
expect(second.id).toBe('given-id-month')
expect(second.tagName).toBe('INPUT')

expect(third.id).toMatch(new RegExp(/^year-id-\w+__input/))
expect(third.id).toBe('given-id-year')
expect(third.tagName).toBe('INPUT')
})

it('should apply labels to input inputs', () => {
render(<MultiInputMask {...defaultProps} />)
render(<MultiInputMask {...defaultProps} id="given-id" />)

const [first, second, third] = Array.from(
document.querySelectorAll('.dnb-multi-input-mask__input')
) as HTMLInputElement[]

expect(first.nextElementSibling).toHaveTextContent('the day')
expect(first.labels[0].id).toMatch(new RegExp(/^day-id-\w+__label/))
expect(first.labels[0].id).toBe('given-id-day__label')
expect(first.nextElementSibling.tagName).toBe('LABEL')

expect(second.nextElementSibling).toHaveTextContent('the month')
expect(second.labels[0].id).toMatch(new RegExp(/^month-id-\w+__label/))
expect(second.labels[0].id).toBe('given-id-month__label')
expect(second.nextElementSibling.tagName).toBe('LABEL')

expect(third.nextElementSibling).toHaveTextContent('the year')
expect(third.labels[0].id).toMatch(new RegExp(/^year-id-\w+__label/))
expect(third.labels[0].id).toBe('given-id-year__label')
expect(third.nextElementSibling.tagName).toBe('LABEL')
})

Expand Down
16 changes: 6 additions & 10 deletions packages/dnb-eufemia/src/extensions/forms/Field/Expiry/Expiry.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { useCallback, useContext, useMemo, useRef } from 'react'
import { makeUniqueId } from '../../../../shared/component-helper'
import React, { useCallback, useContext, useMemo } from 'react'
import SharedContext from '../../../../shared/Context'
import { FieldHelpProps, FieldProps } from '../../types'
import { pickSpacingProps } from '../../../../components/flex/utils'
Expand Down Expand Up @@ -43,7 +42,7 @@ function Expiry(props: ExpiryProps) {
}

const {
id: propsId,
id,
className,
label = translations.expiryLabel,
error,
Expand All @@ -54,7 +53,6 @@ function Expiry(props: ExpiryProps) {
disabled,
value = '',
layout = 'vertical',
required,
handleFocus,
handleBlur,
handleChange,
Expand All @@ -67,8 +65,6 @@ function Expiry(props: ExpiryProps) {
year: value?.substring(2, 4) ?? '',
}

const idRef = useRef(propsId || makeUniqueId()).current

const status = hasError
? 'error'
: warning
Expand All @@ -80,21 +76,21 @@ function Expiry(props: ExpiryProps) {
return (
<FieldBlock
className={classnames('dnb-forms-field-expiry', className)}
forId={`${id}-input-month`}
label={label}
layout={layout}
info={info}
warning={warning}
error={error}
{...pickSpacingProps(props)}
>
<MultiInputMask
stretch
id={`${idRef}__input`}
label={label}
labelDirection={layout}
id={`${id}-input`}
values={expiry}
status={status}
statusState={disabled ? 'disabled' : undefined}
disabled={disabled}
required={required}
onChange={handleChange}
onBlur={handleBlur}
onFocus={handleFocus}
Expand Down

0 comments on commit 8b0d3c7

Please sign in to comment.