Merged in feat/SW-3655-input-component (pull request #3296)

feat: (SW-3655) new Input and FormInput components

* First version new Input and FormInput components

* Handle aria-describedby with react-aria instead of manually add it

* Update breaking unit and stories tests

* Merge branch 'master' into feat/SW-3655-input-component

* Update example form

* Merge branch 'master' into feat/SW-3655-input-component

* New lock file


Approved-by: Linus Flood
This commit is contained in:
Rasmus Langvad
2025-12-08 08:51:03 +00:00
parent de4b3c1c3c
commit edca33c49f
33 changed files with 2159 additions and 71 deletions

View File

@@ -0,0 +1,34 @@
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
import { InputLabel } from './InputLabel'
const meta: Meta<typeof InputLabel> = {
title: 'Components/InputLabel',
component: InputLabel,
argTypes: {},
}
export default meta
type Story = StoryObj<typeof InputLabel>
export const Default: Story = {
args: {
children: 'Label',
required: false,
},
}
export const Discreet: Story = {
args: {
children: 'Label',
size: 'discreet',
},
}
export const Small: Story = {
args: {
children: 'Label',
size: 'small',
},
}

View File

@@ -0,0 +1,22 @@
import { inputLabelVariants } from './variants'
import type { InputLabelProps } from './types'
export function InputLabel({
children,
className,
selected,
required,
disabled,
size,
}: InputLabelProps) {
const classNames = inputLabelVariants({
size,
required,
selected,
disabled,
className,
})
return <span className={classNames}>{children}</span>
}

View File

@@ -0,0 +1 @@
export { InputLabel } from './InputLabel'

View File

@@ -0,0 +1,97 @@
.inputLabel {
font-family:
var(--Body-Paragraph-Font-family), var(--Body-Paragraph-Font-fallback);
font-size: var(--Body-Paragraph-Size);
font-weight: var(--Body-Paragraph-Font-weight);
letter-spacing: var(--Body-Paragraph-Letter-spacing);
text-transform: unset;
line-height: 1.5;
text-decoration: none;
transition: font-size 100ms ease;
text-align: left;
color: var(--Text-Interactive-Placeholder);
user-select: none;
}
.small {
font-family: var(--Label-Font-family), var(--Label-Font-fallback);
font-size: var(--Label-Size);
font-weight: var(--Label-Font-weight);
letter-spacing: var(--Label-Letter-spacing);
text-transform: unset;
line-height: 1.5;
text-decoration: none;
}
.discreet {
font-family:
var(--Body-Supporting-text-Font-family),
var(--Body-Supporting-text-Font-fallback);
font-size: var(--Body-Supporting-text-Size);
font-weight: var(--Body-Supporting-text-Font-weight-2);
letter-spacing: var(--Body-Supporting-text-Letter-spacing);
text-transform: unset;
line-height: 1.4;
text-decoration: none;
color: var(--Text-Default);
order: unset;
}
.required:after {
content: ' *';
}
input:focus ~ .inputLabel,
input:placeholder-shown ~ .inputLabel,
input[value]:not([value='']) ~ .inputLabel,
textarea:focus ~ .inputLabel,
textarea:placeholder-shown ~ .inputLabel,
textarea[value]:not([value='']) ~ .inputLabel,
.selected {
font-family: var(--Label-Font-family), var(--Label-Font-fallback);
font-size: var(--Label-Size);
font-weight: var(--Label-Font-weight);
letter-spacing: var(--Label-Letter-spacing);
text-transform: unset;
line-height: 1.5;
text-decoration: none;
margin-bottom: var(--Space-x025);
}
.inputLabel.disabled,
input:read-only ~ .inputLabel,
input:disabled ~ .inputLabel,
textarea:disabled ~ .inputLabel {
color: var(--Text-Interactive-Disabled);
}
@media (hover: hover) {
input:active:not(:disabled) ~ .inputLabel {
font-family: var(--Label-Font-family), var(--Label-Font-fallback);
font-size: var(--Label-Size);
font-weight: var(--Label-Font-weight);
letter-spacing: var(--Label-Letter-spacing);
text-transform: unset;
line-height: 1.5;
text-decoration: none;
margin-bottom: var(--Space-x025);
}
}
/* Legacy selector for deprecated select component */
:global(.select-container)[data-disabled] .inputLabel {
color: var(--Text-Interactive-Disabled);
}
:global(.select-button) .inputLabel {
order: unset;
}
:global(.select-container)[data-open='true'] .inputLabel:not(.discreet),
:global(.react-aria-SelectValue):has(:nth-child(2)) .inputLabel:not(.discreet) {
font-size: 12px;
}

View File

@@ -0,0 +1,10 @@
import type { VariantProps } from 'class-variance-authority'
import type { inputLabelVariants } from './variants'
export interface InputLabelProps
extends
React.PropsWithChildren<React.HTMLAttributes<HTMLSpanElement>>,
VariantProps<typeof inputLabelVariants> {
required?: boolean
}

View File

@@ -0,0 +1,26 @@
import { cva } from 'class-variance-authority'
import styles from './inputLabel.module.css'
export const inputLabelVariants = cva(styles.inputLabel, {
variants: {
size: {
small: styles.small,
regular: styles.regular,
discreet: styles.discreet,
},
required: {
true: styles.required,
},
selected: {
true: styles.selected,
},
disabled: {
true: styles.disabled,
},
},
defaultVariants: {
size: 'regular',
required: false,
},
})