🎨(react) enhance Select component styles

update Select token and css files with new css variables introduce
with the new tokens architectures
This commit is contained in:
Nathan Panchout
2025-08-22 10:14:28 +02:00
committed by NathanVss
parent 2a65010ecd
commit 2123aedb72
7 changed files with 82 additions and 64 deletions

View File

@@ -1,4 +1,4 @@
@use 'src/utils' as *; @use "src/utils" as *;
.c__select { .c__select {
position: relative; position: relative;
@@ -9,7 +9,11 @@
border-color: var(--c--components--forms-select--border-color); border-color: var(--c--components--forms-select--border-color);
border-style: var(--c--components--forms-select--border-style); border-style: var(--c--components--forms-select--border-style);
display: flex; display: flex;
transition: border var(--c--theme--transitions--duration) var(--c--theme--transitions--ease-out), border-radius var(--c--theme--transitions--duration) var(--c--theme--transitions--ease-out); transition:
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);
padding: 0 0.75rem; padding: 0 0.75rem;
gap: 1rem; gap: 1rem;
box-sizing: border-box; box-sizing: border-box;
@@ -30,7 +34,8 @@
border-color: var(--c--components--forms-select--border-color--hover); border-color: var(--c--components--forms-select--border-color--hover);
} }
&:focus-within, &--focus { &:focus-within,
&--focus {
border-radius: var(--c--components--forms-select--border-radius--focus); border-radius: var(--c--components--forms-select--border-radius--focus);
border-color: var(--c--components--forms-select--border-color--focus); border-color: var(--c--components--forms-select--border-color--focus);
@@ -83,22 +88,23 @@
span { span {
font-size: 1.25rem; font-size: 1.25rem;
transition: all var(--c--theme--transitions--duration) var(--c--theme--transitions--ease-out); transition: all var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out);
&.opened { &.opened {
transform: rotate(180deg); transform: rotate(180deg);
} }
} }
&__clear { &__clear {
color: var(--c--theme--colors--greyscale-500); color: var(--c--contextuals--content--semantic--neutral--secondary);
} }
&__separator { &__separator {
background-color: var(--c--theme--colors--greyscale-400); background-color: var(--c--contextuals--content--semantic--neutral--tertiary);
height: 24px; height: 24px;
width: 1px; width: 1px;
} }
&__open { &__open {
color: var(--c--theme--colors--greyscale-900); color: var(--c--contextuals--content--semantic--neutral--primary);
} }
} }
} }
@@ -140,11 +146,15 @@
cursor: pointer; cursor: pointer;
&--highlight { &--highlight {
background-color: var(--c--components--forms-select--item-background-color--hover); background-color: var(
--c--components--forms-select--item-background-color--hover
);
} }
&--selected { &--selected {
background-color: var(--c--components--forms-select--item-background-color--selected); background-color: var(
--c--components--forms-select--item-background-color--selected
);
} }
&--disabled { &--disabled {
@@ -154,7 +164,7 @@
} }
&__empty-placeholder { &__empty-placeholder {
color: var(--c--theme--colors--greyscale-600); color: var(--c--contextuals--content--semantic--neutral--secondary);
font-style: italic; font-style: italic;
} }
@@ -179,62 +189,60 @@
/** Modifiers */ /** Modifiers */
&--disabled { &--disabled {
.c__select__wrapper { .c__select__wrapper {
border-color: var(--c--theme--colors--greyscale-200); border-color: var(--c--contextuals--border--semantic--neutral--tertiary);
cursor: default; cursor: default;
label, input { label,
input {
cursor: default; cursor: default;
} }
.c__select__inner__value { .c__select__inner__value {
color: var(--c--components--forms-select--value-color--disabled) color: var(--c--components--forms-select--value-color--disabled);
} }
} }
&:hover { &:hover {
border-color: var(--c--theme--colors--greyscale-200); border-color: var(--c--contextuals--border--semantic--neutral--tertiary-hover);
} }
} }
&--error { &--error {
.c__select__wrapper { .c__select__wrapper {
border-color: var(--c--theme--colors--danger-600); border-color: var(--c--contextuals--border--semantic--error--secondary);
label { label {
color: var(--c--theme--colors--danger-600); color: var(--c--contextuals--content--semantic--error--secondary);
} }
} }
&:not(.c__select__wrapper--disabled) { &:not(.c__select__wrapper--disabled) {
.c__select__wrapper:hover { .c__select__wrapper:hover {
border-color: var(--c--theme--colors--danger-800); border-color: var(--c--contextuals--border--semantic--error--primary);
label { label {
color: var(--c--theme--colors--danger-800); color: var(--c--contextuals--content--semantic--error--primary);
} }
} }
} }
} }
&--success { &--success {
.c__select__wrapper { .c__select__wrapper {
border-color: var(--c--theme--colors--success-600); border-color: var(--c--contextuals--border--semantic--success--secondary);
label { label {
color: var(--c--theme--colors-success-600); color: var(--c--contextuals--content--semantic--success--secondary);
} }
} }
&:not(.c__select__wrapper--disabled) { &:not(.c__select__wrapper--disabled) {
.c__select__wrapper:hover { .c__select__wrapper:hover {
border-color: var(--c--theme--colors--success-800); border-color: var(--c--contextuals--border--semantic--success--primary);
label { label {
color: var(--c--theme--colors--success-800); color: var(--c--contextuals--content--semantic--success--primary);
} }
} }
} }
@@ -288,14 +296,17 @@
} }
.c__select__inner { .c__select__inner {
&__value { &__value {
gap: 0.25rem; gap: 0.25rem;
&__pill { &__pill {
background-color: var(--c--components--forms-select--multi-pill-background-color); background-color: var(
--c--components--forms-select--multi-pill-background-color
);
padding: 0.125rem 0.5rem; padding: 0.125rem 0.5rem;
border-radius: var(--c--components--forms-select--multi-pill-border-radius); border-radius: var(
--c--components--forms-select--multi-pill-border-radius
);
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: 0.25rem; gap: 0.25rem;
@@ -317,7 +328,7 @@
height: auto; height: auto;
.material-icons { .material-icons {
font-size: 1.1250rem; font-size: 1.125rem;
} }
} }
} }
@@ -340,7 +351,7 @@
} }
&::after { &::after {
content: attr(data-value) ' '; content: attr(data-value) " ";
visibility: hidden; visibility: hidden;
white-space: pre-wrap; white-space: pre-wrap;
} }
@@ -348,7 +359,6 @@
} }
} }
/** Modifiers */ /** Modifiers */
&.c__select--populated { &.c__select--populated {

View File

@@ -101,7 +101,7 @@ export const SelectMonoAux = ({
"c__select--" + state, "c__select--" + state,
{ {
"c__select--disabled": disabled, "c__select--disabled": disabled,
}, }
)} )}
onBlur={() => onBlur={() =>
onBlur?.({ target: { value: downshiftReturn.selectedItem?.value } }) onBlur?.({ target: { value: downshiftReturn.selectedItem?.value } })
@@ -138,10 +138,11 @@ export const SelectMonoAux = ({
{clearable && !disabled && downshiftReturn.selectedItem && ( {clearable && !disabled && downshiftReturn.selectedItem && (
<> <>
<Button <Button
color="tertiary-text" color="tertiary"
variant="neutral"
size="nano" size="nano"
aria-label={t( aria-label={t(
"components.forms.select.clear_button_aria_label", "components.forms.select.clear_button_aria_label"
)} )}
className="c__select__inner__actions__clear" className="c__select__inner__actions__clear"
onClick={(e) => { onClick={(e) => {
@@ -156,7 +157,8 @@ export const SelectMonoAux = ({
)} )}
<Button <Button
color="tertiary-text" color="tertiary"
variant="neutral"
size="nano" size="nano"
className="c__select__inner__actions__open" className="c__select__inner__actions__open"
icon={ icon={

View File

@@ -569,7 +569,7 @@ export const ReactHookForm = () => {
}} }}
onSubmit={methods.handleSubmit(onSubmit)} onSubmit={methods.handleSubmit(onSubmit)}
> >
<div className="clr-greyscale-900"> <div className="clr-gray-900">
Where will the 2024 Olympics take place? Where will the 2024 Olympics take place?
</div> </div>
<RhfSelect <RhfSelect

View File

@@ -24,14 +24,14 @@ import { SelectMultiMenu } from ":/components/Forms/Select/multi-menu";
*/ */
export function getMultiOptionsFilter( export function getMultiOptionsFilter(
selectedOptions: Option[], selectedOptions: Option[],
inputValue?: string, inputValue?: string
) { ) {
const optionsFilter = getOptionsFilter(inputValue); const optionsFilter = getOptionsFilter(inputValue);
return (option: Option) => { return (option: Option) => {
return ( return (
!selectedOptions.find( !selectedOptions.find(
(selectedOption) => (selectedOption) =>
optionToValue(selectedOption) === optionToValue(option), optionToValue(selectedOption) === optionToValue(option)
) && optionsFilter(option) ) && optionsFilter(option)
); );
}; };
@@ -83,7 +83,7 @@ export const SelectMultiAux = ({ children, ...props }: SelectMultiAuxProps) => {
"c__select--populated": props.selectedItems.length > 0, "c__select--populated": props.selectedItems.length > 0,
"c__select--monoline": props.monoline, "c__select--monoline": props.monoline,
"c__select--multiline": !props.monoline, "c__select--multiline": !props.monoline,
}, }
)} )}
> >
<div <div
@@ -117,10 +117,11 @@ export const SelectMultiAux = ({ children, ...props }: SelectMultiAuxProps) => {
props.selectedItems.length > 0 && ( props.selectedItems.length > 0 && (
<> <>
<Button <Button
color="tertiary-text" color="tertiary"
variant="neutral"
size="nano" size="nano"
aria-label={t( aria-label={t(
"components.forms.select.clear_all_button_aria_label", "components.forms.select.clear_all_button_aria_label"
)} )}
className="c__select__inner__actions__clear" className="c__select__inner__actions__clear"
onClick={(e) => { onClick={(e) => {
@@ -134,7 +135,8 @@ export const SelectMultiAux = ({ children, ...props }: SelectMultiAuxProps) => {
</> </>
)} )}
<Button <Button
color="tertiary-text" color="tertiary"
variant="neutral"
size="nano" size="nano"
className="c__select__inner__actions__open" className="c__select__inner__actions__open"
icon={ icon={

View File

@@ -39,7 +39,8 @@ const SelectedItemsChips = ({
<SelectedOption option={selectedItemForRender} {...props} /> <SelectedOption option={selectedItemForRender} {...props} />
<Button <Button
tabIndex={-1} tabIndex={-1}
color="tertiary-text" color="tertiary"
variant="neutral"
disabled={disabled} disabled={disabled}
size="small" size="small"
aria-label={t("components.forms.select.clear_button_aria_label")} aria-label={t("components.forms.select.clear_button_aria_label")}
@@ -48,7 +49,7 @@ const SelectedItemsChips = ({
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
useMultipleSelectionReturn.removeSelectedItem( useMultipleSelectionReturn.removeSelectedItem(
selectedItemForRender, selectedItemForRender
); );
}} }}
icon={<span className="material-icons">close</span>} icon={<span className="material-icons">close</span>}

View File

@@ -97,7 +97,7 @@ export const Controlled = () => {
const [value, setValue] = useState([OPTIONS[6].value, OPTIONS[8].value]); const [value, setValue] = useState([OPTIONS[6].value, OPTIONS[8].value]);
return ( return (
<div> <div>
<div className="clr-greyscale-900"> <div className="clr-gray-900">
Value: <span>{JSON.stringify(value)}</span> Value: <span>{JSON.stringify(value)}</span>
</div> </div>
<Select <Select
@@ -160,7 +160,7 @@ export const SearchableControlled = () => {
const [value, setValue] = useState([OPTIONS[6].value, OPTIONS[8].value]); const [value, setValue] = useState([OPTIONS[6].value, OPTIONS[8].value]);
return ( return (
<div> <div>
<div className="clr-greyscale-900"> <div className="clr-gray-900">
Value: <span>{JSON.stringify(value)}</span> Value: <span>{JSON.stringify(value)}</span>
</div> </div>
<Select <Select
@@ -509,7 +509,7 @@ export const ReactHookForm = () => {
.test({ .test({
test: (cityList) => test: (cityList) =>
cityList.every((city) => cityList.every((city) =>
[CitiesOptionEnum.PARIS, CitiesOptionEnum.TOKYO].includes(city), [CitiesOptionEnum.PARIS, CitiesOptionEnum.TOKYO].includes(city)
), ),
message: "Wrong answer!", message: "Wrong answer!",
}), }),
@@ -535,7 +535,7 @@ export const ReactHookForm = () => {
}} }}
onSubmit={methods.handleSubmit(onSubmit)} onSubmit={methods.handleSubmit(onSubmit)}
> >
<div className="clr-greyscale-900"> <div className="clr-gray-900">
Which cities are capital of countries ? Which cities are capital of countries ?
</div> </div>
<RhfSelect <RhfSelect

View File

@@ -1,28 +1,31 @@
import { DefaultTokens } from "@openfun/cunningham-tokens"; import { DefaultTokens } from "@openfun/cunningham-tokens";
export const tokens = (defaults: DefaultTokens) => ({ export const tokens = (defaults: DefaultTokens) => ({
"border-color": defaults.theme.colors["greyscale-300"], "border-color": defaults.contextuals.border.semantic.neutral.tertiary,
"border-color--focus": defaults.theme.colors["primary-600"], "border-color--focus": defaults.contextuals.border.semantic.brand.primary,
"border-color--hover": defaults.theme.colors["greyscale-500"], "border-color--hover": defaults.contextuals.border.semantic.neutral.secondary,
"border-radius": "8px", "border-radius": "8px",
"border-radius--focus": "2px", "border-radius--focus": "2px",
"border-radius--hover": "2px", "border-radius--hover": "2px",
"border-style": "solid", "border-style": "solid",
"border-width": "1px", "border-width": "1px",
"value-color": defaults.theme.colors["greyscale-900"], "value-color": defaults.contextuals.content.semantic.neutral.primary,
"value-color--disabled": defaults.theme.colors["greyscale-800"], "value-color--disabled": defaults.contextuals.content.semantic.disabled.primary,
"font-size": defaults.theme.font.sizes.l, "font-size": defaults.globals.font.sizes.md,
height: "3.5rem", height: "3.5rem",
"item-background-color--hover": defaults.theme.colors["greyscale-200"], "item-background-color--hover":
"item-background-color--selected": defaults.theme.colors["primary-100"], defaults.contextuals.background.semantic.neutral["tertiary-hover"],
"item-color": defaults.theme.colors["greyscale-800"], "item-background-color--selected":
"item-color--disabled": defaults.theme.colors["greyscale-500"], defaults.contextuals.background.semantic.brand.secondary,
"item-font-size": defaults.theme.font.sizes.l, "item-color": defaults.contextuals.content.semantic.neutral.primary,
"background-color": defaults.theme.colors["greyscale-000"], "item-color--disabled": defaults.contextuals.content.semantic.disabled.secondary,
"menu-background-color": defaults.theme.colors["greyscale-000"], "item-font-size": defaults.globals.font.sizes.md,
"label-color--focus": defaults.theme.colors["primary-600"], "background-color": defaults.contextuals.background.surface.primary,
"multi-pill-background-color": defaults.theme.colors["greyscale-200"], "menu-background-color": defaults.contextuals.background.surface.primary,
"label-color--focus": defaults.contextuals.border.semantic.brand.primary,
"multi-pill-background-color":
defaults.contextuals.background.semantic.neutral.tertiary,
"multi-pill-border-radius": "2px", "multi-pill-border-radius": "2px",
"multi-pill-max-width": "68%", "multi-pill-max-width": "68%",
"multi-pill-font-size": defaults.theme.font.sizes.m, "multi-pill-font-size": defaults.globals.font.sizes.md,
}); });