generated from nl-design-system/example
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(react): Added FormField, its subcomponents and FormFieldTextbox (#…
…306) # Contents De volgende componenten toegevoegd: - FormField - FormFieldLabel - FormFieldDescription - FormFieldErrorMessage - Textbox - FormFieldTextbox ## Checklist - [X] New features/components and bugfixes are covered by tests - [X] Changesets are created - [X] Definition of Done is checked --------- Co-authored-by: Vlad Afanasev <[email protected]> Co-authored-by: Jaap-Hein Wester <[email protected]>
- Loading branch information
1 parent
c834cc4
commit 2ac36c4
Showing
35 changed files
with
2,053 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@lux-design-system/components-react": minor | ||
--- | ||
|
||
Nieuw component: Form Field |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@lux-design-system/components-react": minor | ||
--- | ||
|
||
Nieuw component: Lux Form Field Text Input |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@lux-design-system/components-react": minor | ||
--- | ||
|
||
Nieuw component: Form Field Error Message |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@lux-design-system/components-react": minor | ||
--- | ||
|
||
Nieuw component: Form Field Description |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
packages/components-react/src/form-field-description/FormFieldDescription.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { | ||
FormFieldDescription as UtrechtFormFieldDescription, | ||
FormFieldDescriptionProps as UtrechtFormFieldDescriptionProps, | ||
} from '@utrecht/component-library-react/dist/css-module'; | ||
import clsx from 'clsx'; | ||
|
||
const FORM_FIELD_DESCRIPTION_CLASSES: Record<LuxFormFieldDescriptionAppearance, string> = { | ||
valid: 'utrecht-form-field-description--valid', | ||
invalid: 'utrecht-form-field-description--invalid', | ||
}; | ||
|
||
export type LuxFormFieldDescriptionAppearance = 'valid' | 'invalid'; | ||
// Extend the Utrecht props but omit valid and invalid since we're replacing them | ||
export interface LuxFormFieldDescriptionProps extends Omit<UtrechtFormFieldDescriptionProps, 'valid' | 'invalid'> { | ||
appearance?: LuxFormFieldDescriptionAppearance; | ||
} | ||
|
||
export const LuxFormFieldDescription = (props: LuxFormFieldDescriptionProps) => { | ||
const { appearance, className, ...restProps } = props; | ||
|
||
const classNames = clsx( | ||
{ | ||
[FORM_FIELD_DESCRIPTION_CLASSES.valid]: appearance === 'valid', | ||
[FORM_FIELD_DESCRIPTION_CLASSES.invalid]: appearance === 'invalid', | ||
}, | ||
className, | ||
); | ||
|
||
return <UtrechtFormFieldDescription {...restProps} className={classNames} />; | ||
}; | ||
|
||
LuxFormFieldDescription.displayName = 'LuxFormFieldDescription'; |
60 changes: 60 additions & 0 deletions
60
packages/components-react/src/form-field-description/test/FormFieldDescription.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { describe, expect, it } from '@jest/globals'; | ||
import { render, screen } from '@testing-library/react'; | ||
import { LuxFormFieldDescription } from '../FormFieldDescription'; | ||
|
||
describe('Form Field Description', () => { | ||
it('renders a basic description', () => { | ||
render(<LuxFormFieldDescription>Test Description</LuxFormFieldDescription>); | ||
|
||
const description = screen.getByText('Test Description'); | ||
expect(description).toBeInTheDocument(); | ||
}); | ||
|
||
it('applies the base class', () => { | ||
render(<LuxFormFieldDescription>Test Description</LuxFormFieldDescription>); | ||
|
||
const description = screen.getByText('Test Description'); | ||
expect(description).toHaveClass('utrecht-form-field-description'); | ||
}); | ||
|
||
it('can have an additional class name', () => { | ||
render(<LuxFormFieldDescription className="custom-class">Test Description</LuxFormFieldDescription>); | ||
|
||
const description = screen.getByText('Test Description'); | ||
expect(description).toHaveClass('utrecht-form-field-description'); | ||
expect(description).toHaveClass('custom-class'); | ||
}); | ||
|
||
it('passes through other HTML attributes', () => { | ||
render(<LuxFormFieldDescription data-testid="test-description">Test Description</LuxFormFieldDescription>); | ||
|
||
const description = screen.getByTestId('test-description'); | ||
expect(description).toBeInTheDocument(); | ||
}); | ||
it('renders content with a paragraph', () => { | ||
render( | ||
<LuxFormFieldDescription data-testid="rich-text-description"> | ||
<p>This is a paragraph</p> | ||
</LuxFormFieldDescription>, | ||
); | ||
const description = screen.getByTestId('rich-text-description'); | ||
expect(description).toBeInTheDocument(); | ||
|
||
const paragraph = description.querySelector('p'); | ||
expect(paragraph).toBeInTheDocument(); | ||
expect(paragraph).toHaveTextContent('This is a paragraph'); | ||
}); | ||
it('renders rich text content', () => { | ||
render( | ||
<LuxFormFieldDescription data-testid="rich-text-description"> | ||
<strong>Bold</strong> Description | ||
</LuxFormFieldDescription>, | ||
); | ||
const description = screen.getByTestId('rich-text-description'); | ||
expect(description).toBeInTheDocument(); | ||
|
||
const boldText = description.querySelector('strong'); | ||
expect(boldText).toBeInTheDocument(); | ||
expect(boldText).toHaveTextContent('Bold'); | ||
}); | ||
}); |
36 changes: 36 additions & 0 deletions
36
packages/components-react/src/form-field-error-message/FormFieldErrorMessage.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { | ||
FormFieldErrorMessage as UtrechtFormFieldErrorMessage, | ||
FormFieldErrorMessageProps as UtrechtFormFieldErrorMessageProps, | ||
} from '@utrecht/component-library-react/dist/css-module'; | ||
import clsx from 'clsx'; | ||
import { ForwardedRef, forwardRef, PropsWithChildren } from 'react'; | ||
|
||
const FORM_FIELD_ERROR_MESSAGE_CLASSES: { [key: string]: string } = { | ||
distanced: 'utrecht-form-field-error-message--distanced', | ||
}; | ||
|
||
export type LuxFormFieldErrorMessageProps = UtrechtFormFieldErrorMessageProps & { | ||
distanced?: boolean; | ||
}; | ||
|
||
export const LuxFormFieldErrorMessage = forwardRef( | ||
( | ||
{ children, className, distanced, ...restProps }: PropsWithChildren<LuxFormFieldErrorMessageProps>, | ||
ref: ForwardedRef<HTMLParagraphElement>, | ||
) => { | ||
const classNames = clsx( | ||
{ | ||
[FORM_FIELD_ERROR_MESSAGE_CLASSES.distanced]: distanced, | ||
}, | ||
className, | ||
); | ||
|
||
return ( | ||
<UtrechtFormFieldErrorMessage {...restProps} ref={ref} className={classNames}> | ||
{children} | ||
</UtrechtFormFieldErrorMessage> | ||
); | ||
}, | ||
); | ||
|
||
LuxFormFieldErrorMessage.displayName = 'LuxFormFieldErrorMessage'; |
55 changes: 55 additions & 0 deletions
55
packages/components-react/src/form-field-error-message/test/FormFieldErrorMessage.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { describe, expect, it } from '@jest/globals'; | ||
import { render, screen } from '@testing-library/react'; | ||
import { LuxFormFieldErrorMessage } from '../FormFieldErrorMessage'; | ||
|
||
describe('Form Field Error Message', () => { | ||
it('renders a basic error message', () => { | ||
render(<LuxFormFieldErrorMessage>Test Error Message</LuxFormFieldErrorMessage>); | ||
|
||
const errorMessage = screen.getByText('Test Error Message'); | ||
expect(errorMessage).toBeInTheDocument(); | ||
}); | ||
|
||
it('applies the base class', () => { | ||
render(<LuxFormFieldErrorMessage>Test Error Message</LuxFormFieldErrorMessage>); | ||
|
||
const errorMessage = screen.getByText('Test Error Message'); | ||
expect(errorMessage).toHaveClass('utrecht-form-field-error-message'); | ||
}); | ||
|
||
it('can have an additional class name', () => { | ||
render(<LuxFormFieldErrorMessage className="custom-class">Test Error Message</LuxFormFieldErrorMessage>); | ||
|
||
const errorMessage = screen.getByText('Test Error Message'); | ||
expect(errorMessage).toHaveClass('utrecht-form-field-error-message'); | ||
expect(errorMessage).toHaveClass('custom-class'); | ||
}); | ||
|
||
it('applies the distanced class when distanced prop is true', () => { | ||
render(<LuxFormFieldErrorMessage distanced>Test Error Message</LuxFormFieldErrorMessage>); | ||
|
||
const errorMessage = screen.getByText('Test Error Message'); | ||
expect(errorMessage).toHaveClass('utrecht-form-field-error-message--distanced'); | ||
}); | ||
|
||
it('passes through other HTML attributes', () => { | ||
render(<LuxFormFieldErrorMessage data-testid="test-error-message">Test Error Message</LuxFormFieldErrorMessage>); | ||
|
||
const errorMessage = screen.getByTestId('test-error-message'); | ||
expect(errorMessage).toBeInTheDocument(); | ||
}); | ||
|
||
it('renders rich text content', () => { | ||
render( | ||
<LuxFormFieldErrorMessage data-testid="rich-text-error-message"> | ||
<strong>Error:</strong> Invalid input | ||
</LuxFormFieldErrorMessage>, | ||
); | ||
const errorMessage = screen.getByTestId('rich-text-error-message'); | ||
expect(errorMessage).toBeInTheDocument(); | ||
|
||
const strongText = errorMessage.querySelector('strong'); | ||
expect(strongText).toBeInTheDocument(); | ||
expect(strongText).toHaveTextContent('Error:'); | ||
}); | ||
}); |
41 changes: 41 additions & 0 deletions
41
packages/components-react/src/form-field-label/FormFieldLabel.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { FormLabel as UtrechtFormLabel } from '@utrecht/component-library-react/dist/css-module'; | ||
import clsx from 'clsx'; | ||
import { ForwardedRef, forwardRef, LabelHTMLAttributes, PropsWithChildren } from 'react'; | ||
|
||
const FORM_LABEL_CLASSES: { [key: string]: string } = { | ||
checkbox: 'utrecht-form-label--checkbox', | ||
radio: 'utrecht-form-label--radio', | ||
disabled: 'utrecht-form-label--disabled', | ||
checked: 'utrecht-form-label--checked', | ||
}; | ||
|
||
export interface LuxFormFieldLabelProps extends LabelHTMLAttributes<HTMLLabelElement> { | ||
type?: 'checkbox' | 'radio'; | ||
disabled?: boolean; | ||
checked?: boolean; | ||
} | ||
|
||
export const LuxFormFieldLabel = forwardRef( | ||
( | ||
{ children, className, type, disabled, checked, ...restProps }: PropsWithChildren<LuxFormFieldLabelProps>, | ||
ref: ForwardedRef<HTMLLabelElement>, | ||
) => { | ||
const classNames = clsx( | ||
{ | ||
[FORM_LABEL_CLASSES.radio]: type === 'radio', | ||
[FORM_LABEL_CLASSES.checkbox]: type === 'checkbox', | ||
[FORM_LABEL_CLASSES.disabled]: disabled, | ||
[FORM_LABEL_CLASSES.checked]: checked, | ||
}, | ||
className, | ||
); | ||
|
||
return ( | ||
<UtrechtFormLabel {...restProps} ref={ref} className={classNames}> | ||
{children} | ||
</UtrechtFormLabel> | ||
); | ||
}, | ||
); | ||
|
||
LuxFormFieldLabel.displayName = 'LuxFormFieldLabel'; |
85 changes: 85 additions & 0 deletions
85
packages/components-react/src/form-field-label/test/FormFieldLabel.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import { describe, expect, it } from '@jest/globals'; | ||
import { render, screen } from '@testing-library/react'; | ||
import { LuxFormFieldLabel } from '../FormFieldLabel'; | ||
|
||
describe('Form Field Label', () => { | ||
it('renders a basic label', () => { | ||
render(<LuxFormFieldLabel htmlFor="test-input">Test Label</LuxFormFieldLabel>); | ||
|
||
const label = screen.getByText('Test Label'); | ||
expect(label).toBeInTheDocument(); | ||
expect(label).toHaveAttribute('for', 'test-input'); | ||
}); | ||
|
||
it('applies the correct class for checkbox type', () => { | ||
render(<LuxFormFieldLabel type="checkbox">Checkbox Label</LuxFormFieldLabel>); | ||
|
||
const label = screen.getByText('Checkbox Label'); | ||
expect(label).toHaveClass('utrecht-form-label--checkbox'); | ||
}); | ||
|
||
it('applies the correct class for radio type', () => { | ||
render(<LuxFormFieldLabel type="radio">Radio Label</LuxFormFieldLabel>); | ||
|
||
const label = screen.getByText('Radio Label'); | ||
expect(label).toHaveClass('utrecht-form-label--radio'); | ||
}); | ||
|
||
it('applies the disabled class when disabled prop is true', () => { | ||
render(<LuxFormFieldLabel disabled>Disabled Label</LuxFormFieldLabel>); | ||
|
||
const label = screen.getByText('Disabled Label'); | ||
expect(label).toHaveClass('utrecht-form-label--disabled'); | ||
}); | ||
|
||
it('applies the checked class when checked prop is true', () => { | ||
render(<LuxFormFieldLabel checked>Checked Label</LuxFormFieldLabel>); | ||
|
||
const label = screen.getByText('Checked Label'); | ||
expect(label).toHaveClass('utrecht-form-label--checked'); | ||
}); | ||
|
||
it('can have an additional class name', () => { | ||
render(<LuxFormFieldLabel className="custom-class">Custom Label</LuxFormFieldLabel>); | ||
|
||
const label = screen.getByText('Custom Label'); | ||
expect(label).toHaveClass('custom-class'); | ||
expect(label).toHaveClass('utrecht-form-label'); | ||
}); | ||
|
||
it('passes through other HTML attributes', () => { | ||
render(<LuxFormFieldLabel data-testid="test-label">Test Label</LuxFormFieldLabel>); | ||
|
||
const label = screen.getByTestId('test-label'); | ||
expect(label).toBeInTheDocument(); | ||
}); | ||
|
||
it('renders rich text content', () => { | ||
render( | ||
<LuxFormFieldLabel data-testid="rich-text-label"> | ||
<strong>Bold</strong> Label | ||
</LuxFormFieldLabel>, | ||
); | ||
const label = screen.getByTestId('rich-text-label'); | ||
expect(label).toBeInTheDocument(); | ||
|
||
const boldText = label.querySelector('strong'); | ||
expect(boldText).toBeInTheDocument(); | ||
expect(boldText).toHaveTextContent('Bold'); | ||
}); | ||
|
||
it('combines multiple classes correctly', () => { | ||
render( | ||
<LuxFormFieldLabel type="checkbox" disabled checked className="custom-class"> | ||
Complex Label | ||
</LuxFormFieldLabel>, | ||
); | ||
|
||
const label = screen.getByText('Complex Label'); | ||
expect(label).toHaveClass('utrecht-form-label'); | ||
expect(label).toHaveClass('utrecht-form-label--checkbox'); | ||
expect(label).toHaveClass('utrecht-form-label--disabled'); | ||
expect(label).toHaveClass('utrecht-form-label--checked'); | ||
expect(label).toHaveClass('custom-class'); | ||
}); | ||
}); |
Oops, something went wrong.