Skip to content

Commit

Permalink
Feat(web-react): Introduce Label component #DS-1566
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelklibani committed Feb 4, 2025
1 parent 9b9c1fc commit bc28eb8
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 1 deletion.
1 change: 1 addition & 0 deletions packages/web-react/scripts/entryPoints.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const entryPoints = [
{ dirs: ['components', 'Heading'] },
{ dirs: ['components', 'Icon'] },
{ dirs: ['components', 'Item'] },
{ dirs: ['components', 'Label'] },
{ dirs: ['components', 'Link'] },
{ dirs: ['components', 'Modal'] },
{ dirs: ['components', 'NoSsr'] },
Expand Down
18 changes: 18 additions & 0 deletions packages/web-react/src/components/Label/Label.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use client';

import React, { ElementType } from 'react';
import { useStyleProps } from '../../hooks';
import { SpiritLabelProps } from '../../types';

const Label = <T extends ElementType = 'label'>(props: SpiritLabelProps<T>): JSX.Element => {
const { elementType: ElementTag = 'label', children, ...restProps } = props;
const { styleProps, props: otherProps } = useStyleProps(restProps);

return (
<ElementTag {...otherProps} {...styleProps}>
{children}
</ElementTag>
);
};

export default Label;
100 changes: 100 additions & 0 deletions packages/web-react/src/components/Label/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Label

The `Label` component is used to associate text with a form control, such as an input, checkbox, or radio button.
It improves accessibility by allowing users to click the label to interact with the corresponding input.
This component can be customized using various props to fit different use cases.

Simple Item example:

```jsx
import { Label } from '@lmc-eu/spirit-web-react';

<Label>Label</Label>
```

## Full Example

```jsx
import { Label } from '@lmc-eu/spirit-web-react';

<Label elementType="span" htmlFor="input-id">Label</Label>
```

## API

| Name | Type | Default | Required | Description |
| ------------- | ------------- | ------- | -------- | ----------------------------------------------- |
| `elementType` | `ElementType` | `label` || Type of element used as wrapper |
| `htmlFor` | `string` ||| ID of the associated form element (e.g., input) |

On top of the API options, the components accept [additional attributes][readme-additional-attributes].
If you need more control over the styling of a component, you can use [style props][readme-style-props]
and [escape hatches][readme-escape-hatches].

# ValidationText

The ValidationText subcomponent displays validation texts for Field components like TextField, TextArea, Checkbox, FileUploader, etc.

```jsx
import { ValidationText } from '@lmc-eu/spirit-web-react/components';
```

Basic example usage:

```jsx
<ValidationText className="Component__validationText" validationText="Danger validation text" />
```

Advanced example:

```jsx
<ValidationText
id="component__validationText"
className="Component__validationText"
elementType="span"
validationText="Danger validation text"
role="alert"
/>
```

## Role Attribute

When displaying text dynamically, set [`role="alert"`][aria-alert-role] on the `ValidationText` component to improve accessibility. This will help screen readers notify users about content updates.

## API

| Name | Type | Default | Required | Description |
| ---------------- | ------------------------------- | ------- | -------- | ---------------------------------------------------------------------------------------------- |
| `className` | `string` ||| Wrapper custom class name |
| `elementType` | \[`span` \| `div`] | `div` || Type of element used as main wrapper (applied only for single validation text, otherwise `ul`) |
| `id` | `string` ||| Component id |
| `role` | `string` | - || The role attribute that describes the role of an element |
| `validationText` | \[`ReactNode` \| `ReactNode[]`] ||| Validation text, only visible if validationState is set |

# HelperText

The HelperText subcomponent displays helper texts for Field components like TextField, TextArea, Checkbox, FileUploader, etc.

```jsx
<HelperText className="Component__helperText" helperText="Helper text" />
```

Advanced example:

```jsx
<HelperText id="component__helperText" className="Component__helperText" elementType="span" helperText="Helper text" />
```

## API

| Name | Type | Default | Required | Description |
| ------------- | ------------------------------- | ------- | -------- | ---------------------------------------------------------------------------------------------- |
| `className` | `string` ||| Wrapper custom class name |
| `elementType` | \[`span` \| `div`] | `div` || Type of element used as main wrapper (applied only for single validation text, otherwise `ul`) |
| `helperText` | \[`ReactNode` \| `ReactNode[]`] ||| Validation text, only visible if validationState is |
| `id` | `string` ||| Component id |

[aria-alert-role]: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/alert_role
[readme-additional-attributes]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/README.md#additional-attributes
[readme-escape-hatches]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/README.md#escape-hatches
[readme-style-props]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/README.md#style-props
25 changes: 25 additions & 0 deletions packages/web-react/src/components/Label/__tests__/Label.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import '@testing-library/jest-dom';
import { render, screen } from '@testing-library/react';
import React from 'react';
import { restPropsTest, stylePropsTest } from '@local/tests';
import { SpiritLabelProps } from '../../../types';
import Label from '../Label';

describe('Label', () => {
stylePropsTest(Label);

restPropsTest((props: SpiritLabelProps) => <Label {...props} />, 'label');

it('should render children', () => {
const label = 'Label';
render(<Label data-testid="test">{label}</Label>);

expect(screen.getByTestId('test')).toHaveTextContent(label);
});

it('should render as span', () => {
render(<Label data-testid="test" elementType="span" />);

expect(screen.getByTestId('test').tagName).toBe('SPAN');
});
});
1 change: 1 addition & 0 deletions packages/web-react/src/components/Label/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{> web-react/demo title="Label" parentPageName="Components" }}
3 changes: 3 additions & 0 deletions packages/web-react/src/components/Label/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
'use client';

export { default as Label } from './Label';
1 change: 1 addition & 0 deletions packages/web-react/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export * from './Header';
export * from './Heading';
export * from './Icon';
export * from './Item';
export * from './Label';
export * from './Link';
export * from './Modal';
export * from './NoSsr';
Expand Down
18 changes: 17 additions & 1 deletion packages/web-react/src/types/label.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
import { ReactNode } from 'react';
import { ElementType, ReactNode } from 'react';
import { StyleProps, TransferProps } from './shared';

export type LabelElementProps<E extends ElementType> = {
/**
* The HTML element or React element used to render the label, e.g. 'div', 'a', or `RouterLink`.
*
* @default 'label'
*/
elementType?: E;
};

export interface LabelProps {
children?: ReactNode;
htmlFor?: string; // for compatibility with React
for?: string;
}

export interface SpiritLabelProps<T extends ElementType = 'label'>
extends LabelElementProps<T>,
LabelProps,
StyleProps,
TransferProps {}

0 comments on commit bc28eb8

Please sign in to comment.