💄(react) homegenize form inputs states

Currently between all components some states were not aligned (error, success,
hover, focus,...)
This commit is contained in:
jbpenrath
2025-12-08 14:29:52 +01:00
committed by Jean-Baptiste PENRATH
parent 992061fc8e
commit 67ba361370
21 changed files with 540 additions and 770 deletions

View File

@@ -23,11 +23,14 @@
margin-left: -1 * $padding;
cursor: pointer;
&:focus-within {
outline: 0;
border-color: var(--c--contextuals--border--semantic--brand--primary);
box-shadow: 0 0 0 1px var(--c--contextuals--border--semantic--brand--primary);
}
&--disabled {
pointer-events: none;
}
&__container {
@@ -53,13 +56,25 @@
background-color: var(--c--components--forms-checkbox--background-color);
width: var(--c--components--forms-checkbox--size);
height: var(--c--components--forms-checkbox--size);
border: 1.5px solid var(--c--components--forms-checkbox--border-color);
border: var(--c--components--forms-checkbox--border-width) solid var(--c--components--forms-checkbox--border-color);
border-radius: var(--c--components--forms-checkbox--border-radius);
display: block;
cursor: pointer;
transition:
border var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out),
box-shadow var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out);
&:hover {
border-color: var(--c--components--forms-checkbox--border-color--hover);
box-shadow: 0 0 0 var(--c--components--forms-checkbox--border-width--hover) var(--c--components--forms-checkbox--border-color--hover);
}
&:focus {
outline: none;
border-color: var(--c--components--forms-checkbox--border-color--focus);
box-shadow: 0 0 0 var(--c--components--forms-checkbox--border-width--hover) var(--c--components--forms-checkbox--border-color--focus);
}
&:not(:checked) {
@@ -73,10 +88,10 @@
&:checked {
background-color: var(
--c--components--forms-checkbox--background-color--checked
--c--components--forms-checkbox--accent-color
);
border-color: var(
--c--components--forms-checkbox--background-color--checked
--c--components--forms-checkbox--accent-color
);
~ .checkmark {
clip-path: $clipPathShow;
@@ -84,14 +99,24 @@
~ .indeterminate {
clip-path: $clipPathHide;
}
&:hover {
border-color: var(--c--components--forms-checkbox--accent-color);
box-shadow: 0 0 0 var(--c--components--forms-checkbox--border-width--hover) var(--c--components--forms-checkbox--accent-color);
}
&:focus {
border-color: var(--c--components--forms-checkbox--accent-color);
box-shadow: 0 0 0 var(--c--components--forms-checkbox--border-width--hover) var(--c--components--forms-checkbox--accent-color);
}
}
&:indeterminate {
background-color: var(
--c--components--forms-checkbox--background-color--indeterminate
--c--components--forms-checkbox--accent-color
);
border-color: var(
--c--components--forms-checkbox--background-color--indeterminate
--c--components--forms-checkbox--accent-color
);
~ .indeterminate {
clip-path: $clipPathShow;
@@ -99,28 +124,32 @@
~ .checkmark {
clip-path: $clipPathHide;
}
&:hover {
border-color: var(--c--components--forms-checkbox--accent-color);
box-shadow: 0 0 0 var(--c--components--forms-checkbox--border-width--hover) var(--c--components--forms-checkbox--accent-color);
}
&:focus {
border-color: var(--c--components--forms-checkbox--accent-color);
box-shadow: 0 0 0 var(--c--components--forms-checkbox--border-width--hover) var(--c--components--forms-checkbox--accent-color);
}
}
&:disabled {
cursor: not-allowed !important;
svg {
color: var(--c--components--forms-checkbox--accent-color);
color: var(--c--components--forms-checkbox--checkmark-color);
}
&:not(:checked):not(:indeterminate) {
background-color: white;
border-color: var(
--c--components--forms-checkbox--border-color--disabled
);
background-color: var(--c--components--forms-checkbox--background-color);
}
&:checked,
&:indeterminate {
background-color: var(
--c--components--forms-checkbox--background-color--disabled
);
border-color: var(
--c--components--forms-checkbox--border-color--disabled
);
background-color: var(--c--components--forms-checkbox--accent-color--disabled);
border-color: var(--c--components--forms-checkbox--accent-color--disabled);
}
}
}
@@ -132,7 +161,7 @@
position: absolute;
top: 0;
left: 0;
color: var(--c--components--forms-checkbox--accent-color);
color: var(--c--components--forms-checkbox--checkmark-color);
}
}

View File

@@ -8,16 +8,15 @@ export const tokens = (defaults: DefaultTokens) => ({
"font-weight": defaults.globals.font.weights.medium,
color: defaults.contextuals.content.semantic.neutral.primary,
"border-color": defaults.contextuals.content.semantic.neutral.tertiary,
"border-color--hover": defaults.contextuals.content.semantic.neutral.tertiary,
"border-color--focus": defaults.contextuals.content.semantic.brand.primary,
"border-radius": "2px",
"accent-color": defaults.contextuals.content.semantic.contextual.primary,
"border-width": "1.5px",
"border-width--hover": "1px",
"accent-color": defaults.contextuals.content.semantic.brand.tertiary,
"accent-color--disabled":
defaults.contextuals.content.semantic.disabled.primary,
"checkmark-color": defaults.contextuals.content.semantic.contextual.primary,
size: "1.5rem",
"background-color--checked":
defaults.contextuals.content.semantic.brand.tertiary,
"background-color--indeterminate":
defaults.contextuals.content.semantic.brand.tertiary,
"background-color--disabled":
defaults.contextuals.content.semantic.disabled.primary,
"border-color--disabled":
defaults.contextuals.content.semantic.disabled.primary,
});

View File

@@ -14,6 +14,8 @@
border var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out),
border-radius var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out),
box-shadow var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out);
padding: 0 0.75rem;
gap: 1rem;
@@ -98,6 +100,7 @@
/** Modifiers */
&--disabled {
pointer-events: none;
.c__date-picker__wrapper {
color: var(--c--contextuals--content--semantic--disabled--primary);
border-color: var(
@@ -129,73 +132,34 @@
&--invalid {
.c__date-picker__wrapper {
border-color: var(--c--contextuals--border--semantic--error--primary);
border-radius: var(--c--components--forms-datepicker--border-radius);
&__toggle {
color: var(--c--contextuals--content--semantic--error--primary);
}
label {
color: var(--c--contextuals--content--semantic--error--primary);
}
}
&:not(.c__date-picker--disabled) {
&:hover {
.c__date-picker__wrapper {
border-color: var(--c--contextuals--border--semantic--error--secondary);
&__toggle {
color: var(--c--contextuals--content--semantic--error--secondary);
}
label {
color: var(--c--contextuals--content--semantic--error--secondary);
}
}
color: var(--c--contextuals--content--semantic--error--secondary);
}
}
}
&--success {
.c__date-picker__wrapper {
border-color: var(--c--contextuals--border--semantic--success--secondary);
border-radius: var(--c--components--forms-datepicker--border-radius);
border-color: var(--c--contextuals--border--semantic--success--primary);
&__toggle {
color: var(--c--contextuals--content--semantic--success--secondary);
}
label {
color: var(--c--contextuals--content--semantic--success--secondary);
}
}
&:not(.c__date-picker--disabled) {
&:hover {
.c__date-picker__wrapper {
border-color: var(--c--contextuals--border--semantic--success--primary);
&__toggle {
color: var(--c--contextuals--content--semantic--success--primary);
}
label {
color: var(--c--contextuals--content--semantic--success--primary);
}
}
}
}
}
&:not(&--focused):not(&--invalid):not(&--disabled):not(&--success) {
&:hover {
.c__date-picker__wrapper {
border-radius: var(
--c--components--forms-datepicker--border-radius--hover
);
border-color: var(
--c--components--forms-datepicker--border-color--hover
);
}
&:hover {
.c__date-picker__wrapper {
border-radius: var(
--c--components--forms-datepicker--border-radius--hover
);
border-color: var(
--c--components--forms-datepicker--border-color--hover
);
box-shadow: 0 0 0 var(--c--components--forms-datepicker--border-width--hover)
var(--c--components--forms-datepicker--border-color--hover);
}
}
@@ -210,6 +174,8 @@
border-color: var(
--c--components--forms-datepicker--border-color--focus
) !important;
box-shadow: 0 0 0 var(--c--components--forms-datepicker--border-width--focus)
var(--c--components--forms-datepicker--border-color--focus) !important;
.c__date-picker__wrapper__toggle {
color: var(

View File

@@ -3,14 +3,16 @@ import { DefaultTokens } from "@gouvfr-lasuite/cunningham-tokens";
export const tokens = (defaults: DefaultTokens) => ({
"border-color": defaults.contextuals.border.semantic.neutral.tertiary,
"border-color--disabled":
defaults.contextuals.border.semantic.disabled.primary,
defaults.contextuals.border.semantic.neutral.tertiary,
"border-color--focus": defaults.contextuals.border.semantic.brand.primary,
"border-color--hover": defaults.contextuals.border.semantic.neutral.secondary,
"border-color--hover": defaults.contextuals.border.semantic.neutral.tertiary,
"border-radius": "8px",
"border-radius--focus": "2px",
"border-radius--hover": "2px",
"border-style": "solid",
"border-width": "1px",
"border-width--focus": "1px",
"border-width--hover": "1px",
"value-color": defaults.contextuals.content.semantic.neutral.tertiary,
"value-color--disabled":
defaults.contextuals.content.semantic.disabled.primary,
@@ -32,5 +34,5 @@ export const tokens = (defaults: DefaultTokens) => ({
defaults.contextuals.border.semantic.brand.primary,
"grid-cell--color--today":
defaults.contextuals.content.semantic.brand.primary,
"label-color--focus": defaults.contextuals.border.semantic.brand.secondary,
"label-color--focus": defaults.contextuals.content.semantic.brand.primary,
});

View File

@@ -46,7 +46,8 @@
&--success {
color: var(--c--components--forms-field--color--success);
.c__field__text {
label,
.labelled-box label {
color: var(--c--components--forms-field--color--success);
}
}

View File

@@ -9,6 +9,8 @@
border var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out),
border-radius var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out),
box-shadow var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out);
padding: 0 1rem;
gap: 1rem;
@@ -77,8 +79,7 @@
&:not(.c__input__wrapper--disabled) {
border-radius: var(--c--components--forms-input--border-radius--hover);
border-color: var(--c--components--forms-input--border-color--hover);
box-shadow: 0 0 0 1px
box-shadow: 0 0 0 var(--c--components--forms-input--border-width--hover)
var(--c--components--forms-input--border-color--hover);
}
}
@@ -90,7 +91,7 @@
}
&:focus-within {
box-shadow: 0 0 0 1px var(--c--components--forms-input--border-color--focus) !important;
box-shadow: 0 0 0 var(--c--components--forms-input--border-width--focus) var(--c--components--forms-input--border-color--focus) !important;
border-radius: var(--c--components--forms-input--border-radius--focus);
border-color: var(
--c--components--forms-input--border-color--focus
@@ -103,6 +104,7 @@
&--disabled {
cursor: default;
pointer-events: none;
border-color: var(--c--contextuals--border--semantic--neutral--tertiary);
.c__input {
@@ -116,37 +118,10 @@
&--success {
border-color: var(--c--contextuals--border--semantic--success--primary);
.labelled-box label {
color: var(--c--contextuals--border--semantic--success--primary);
}
&:not(.c__input__wrapper--disabled) {
&:hover {
border-color: var(--c--contextuals--border--semantic--success--primary);
color: var(--c--contextuals--content--semantic--success--primary);
.labelled-box label {
color: var(--c--contextuals--content--semantic--success--primary);
}
}
}
}
&--error {
border-color: var(--c--contextuals--border--semantic--error--secondary);
&:not(.c__input__wrapper--disabled) {
&:hover {
// border-color: var(--c--contextuals--border--semantic--error--primary);
// color: var(--c--contextuals--content--semantic--error--primary);
// box-shadow: 0 0 0 1px var(--c--contextuals--border--semantic--error--primary);
label {
// color: var(--c--contextuals--content--semantic--error--primary);
}
}
}
border-color: var(--c--contextuals--border--semantic--error--primary);
}
}

View File

@@ -14,6 +14,15 @@ import { Button } from ":/components/Button";
export default {
title: "Components/Forms/Input",
component: Input,
argTypes: {
disabled: {
control: "boolean",
},
state: {
control: "select",
options: ["default", "success", "error"],
},
},
} as Meta<typeof Input>;
export const Default = {
@@ -40,6 +49,7 @@ export const Error = {
state: "error",
icon: <span className="material-icons">person</span>,
text: "This is an optional error message",
disabled: false,
},
};

View File

@@ -4,20 +4,38 @@
margin: 0;
width: var(--c--components--forms-checkbox--size);
height: var(--c--components--forms-checkbox--size);
border: 1.5px solid var(--c--components--forms-radio--border-color);
background-color: var(--c--components--forms-radio--background-color);
border: var(--c--components--forms-checkbox--border-width) solid var(--c--components--forms-checkbox--border-color);
background-color: var(--c--components--forms-checkbox--background-color);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition:
border var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out),
box-shadow var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out);
&:hover {
box-shadow: 0 0 0 var(--c--components--forms-checkbox--border-width--hover) var(--c--components--forms-checkbox--border-color);
}
&:focus {
outline: none;
box-shadow: 0 0 0 var(--c--components--forms-checkbox--border-width--hover) var(--c--components--forms-checkbox--border-color);
}
&:checked {
border-color: var(--c--components--forms-radio--accent-color);
border-color: var(--c--components--forms-checkbox--accent-color);
&:hover {
box-shadow: 0 0 0 var(--c--components--forms-checkbox--border-width--hover) var(--c--components--forms-checkbox--accent-color);
}
&:focus {
box-shadow: 0 0 0 var(--c--components--forms-checkbox--border-width--hover) var(--c--components--forms-checkbox--accent-color);
}
}
&::before {
@@ -28,7 +46,7 @@
transform: scale(0);
transition: all var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out);
box-shadow: inset 1em 1em var(--c--components--forms-radio--accent-color);
box-shadow: inset 1em 1em var(--c--components--forms-checkbox--accent-color);
}
&:checked::before {
@@ -37,11 +55,12 @@
}
&.c__checkbox--disabled {
pointer-events: none;
input {
border-color: var(--c--components--forms-radio--border-color--disabled);
border-color: var(--c--components--forms-checkbox--accent-color--disabled);
&::before {
box-shadow: inset 1em 1em
var(--c--components--forms-radio--border-color--disabled);
var(--c--components--forms-checkbox--accent-color--disabled);
}
}
}

View File

@@ -1,9 +1,6 @@
import { DefaultTokens } from "@gouvfr-lasuite/cunningham-tokens";
// TODO : Homegenize tokens between all inputs
export const tokens = (defaults: DefaultTokens) => ({
"border-color": defaults.contextuals.border.semantic.neutral.tertiary,
"border-color--disabled":
defaults.contextuals.border.semantic.neutral.tertiary,
"accent-color": defaults.contextuals.content.semantic.brand.tertiary,
"background-color": defaults.contextuals.background.surface.primary,
});
// For now, radio tokens are the same as checkbox tokens
// Take a look at the checkbox tokens
export const tokens = () => ({});

View File

@@ -13,6 +13,8 @@
border var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out),
border-radius var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out),
box-shadow var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out);
padding: 0 0.75rem;
gap: 1rem;
@@ -32,12 +34,14 @@
&:hover {
border-radius: var(--c--components--forms-select--border-radius--hover);
border-color: var(--c--components--forms-select--border-color--hover);
box-shadow: 0 0 0 var(--c--components--forms-select--border-width--hover) var(--c--components--forms-select--border-color--hover);
}
&:focus-within,
&--focus {
border-radius: var(--c--components--forms-select--border-radius--focus);
border-color: var(--c--components--forms-select--border-color--focus);
box-shadow: 0 0 0 var(--c--components--forms-select--border-width--focus) var(--c--components--forms-select--border-color--focus);
label {
color: var(--c--components--forms-select--label-color--focus);
@@ -160,6 +164,7 @@
&--disabled {
color: var(--c--components--forms-select--item-color--disabled);
cursor: default;
pointer-events: none;
}
}
@@ -189,6 +194,7 @@
/** Modifiers */
&--disabled {
pointer-events: none;
.c__select__wrapper {
border-color: var(--c--contextuals--border--semantic--neutral--tertiary);
cursor: default;

View File

@@ -3,19 +3,21 @@ import { DefaultTokens } from "@gouvfr-lasuite/cunningham-tokens";
export const tokens = (defaults: DefaultTokens) => ({
"border-color": defaults.contextuals.border.semantic.neutral.tertiary,
"border-color--focus": defaults.contextuals.border.semantic.brand.primary,
"border-color--hover": defaults.contextuals.border.semantic.neutral.secondary,
"border-color--hover": defaults.contextuals.border.semantic.neutral.tertiary,
"border-radius": "8px",
"border-radius--focus": "2px",
"border-radius--hover": "2px",
"border-style": "solid",
"border-width": "1px",
"border-width--focus": "1px",
"border-width--hover": "1px",
"value-color": defaults.contextuals.content.semantic.neutral.primary,
"value-color--disabled":
defaults.contextuals.content.semantic.disabled.primary,
"font-size": defaults.globals.font.sizes.md,
height: "3.5rem",
"item-background-color--hover":
defaults.contextuals.background.semantic.neutral["tertiary-hover"],
defaults.contextuals.background.semantic.overlay.primary,
"item-background-color--selected":
defaults.contextuals.background.semantic.brand.secondary,
"item-color": defaults.contextuals.content.semantic.neutral.primary,
@@ -23,8 +25,9 @@ export const tokens = (defaults: DefaultTokens) => ({
defaults.contextuals.content.semantic.disabled.secondary,
"item-font-size": defaults.globals.font.sizes.md,
"background-color": defaults.contextuals.background.surface.primary,
"menu-background-color": defaults.contextuals.background.surface.primary,
"label-color--focus": defaults.contextuals.border.semantic.brand.primary,
"menu-background-color": defaults.contextuals.background.surface.secondary,
"label-color": defaults.contextuals.content.semantic.neutral.tertiary,
"label-color--focus": defaults.contextuals.content.semantic.brand.primary,
"multi-pill-background-color":
defaults.contextuals.background.semantic.neutral.tertiary,
"multi-pill-border-radius": "2px",

View File

@@ -17,6 +17,8 @@
border var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out),
border-radius var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out),
box-shadow var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out);
overflow: hidden;
@@ -42,14 +44,14 @@
&:hover {
border-radius: var(--c--components--forms-textarea--border-radius--hover);
border-color: var(--c--components--forms-textarea--border-color--hover);
border-color: var(--c--components--forms-textarea--border-color--hover) !important;
box-shadow: 0 0 0 var(--c--components--forms-textarea--border-width--hover) var(--c--components--forms-textarea--border-color--hover) !important;
}
&:focus-within {
border-radius: var(--c--components--forms-textarea--border-radius--focus);
border-color: var(
--c--components--forms-textarea--border-color--focus
) !important;
border-color: var(--c--components--forms-textarea--border-color--focus) !important;
box-shadow: 0 0 0 var(--c--components--forms-textarea--border-width--focus) var(--c--components--forms-textarea--border-color--focus) !important;
label {
color: var(--c--components--forms-textarea--label-color--focus);
@@ -58,6 +60,7 @@
&--disabled {
cursor: default;
pointer-events: none;
border-color: var(--c--components--forms-textarea--border-color--disabled);
.c__textarea {
@@ -78,38 +81,12 @@
&--success {
.c__textarea__wrapper {
border-color: var(--c--contextuals--content--semantic--success--tertiary);
.labelled-box label {
color: var(--c--contextuals--content--semantic--success--tertiary);
}
&:not(.c__input__wrapper--disabled) {
&:hover {
border-color: var(--c--contextuals--content--semantic--success--secondary);
color: var(--c--contextuals--content--semantic--success--secondary);
.labelled-box label {
color: var(--c--contextuals--content--semantic--success--secondary);
}
}
}
}
}
&--error {
.c__textarea__wrapper {
border-color: var(--c--contextuals--content--semantic--error--tertiary);
&:not(.c__input__wrapper--disabled) {
&:hover {
border-color: var(--c--contextuals--content--semantic--error--secondary);
color: var(--c--contextuals--content--semantic--error--secondary);
label {
color: var(--c--contextuals--content--semantic--error--secondary);
}
}
}
}
}
}

View File

@@ -7,13 +7,16 @@ export const tokens = (defaults: DefaultTokens) => ({
"border-radius--hover": "2px",
"border-radius--focus": "2px",
"border-width": "1px",
"border-width--hover": "1px",
"border-width--focus": "1px",
"border-color": defaults.contextuals.border.semantic.neutral.tertiary,
"border-color--hover": defaults.contextuals.border.semantic.neutral.secondary,
"border-color--hover": defaults.contextuals.border.semantic.neutral.tertiary,
"border-color--focus": defaults.contextuals.border.semantic.brand.primary,
"border-color--disabled":
defaults.contextuals.border.semantic.disabled.primary,
"border-style": "solid",
"label-color--focus": defaults.contextuals.border.semantic.brand.primary,
"label-color": defaults.contextuals.content.semantic.neutral.tertiary,
"label-color--focus": defaults.contextuals.content.semantic.brand.primary,
"background-color": defaults.contextuals.background.surface.primary,
"value-color": defaults.contextuals.content.semantic.neutral.primary,
"value-color--disabled":