Skip to content

Commit

Permalink
refactor(look&feel): select native
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonathan VACHERAT committed Feb 17, 2025
1 parent beee942 commit 86eb66f
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 320 deletions.
152 changes: 52 additions & 100 deletions client/look-and-feel/css/src/Form/Select/Select.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,126 +2,78 @@
@use "../../common/reboot";
@use "../../common/common" as common;

.af-form {
&__select {
&-label {
display: inline-block;
margin-bottom: 0.5rem;
font-size: common.rem(18);
font-weight: 600;
color: var(--color-gray-900);
}
.af-form__select {
&-label {
display: inline-block;
margin-bottom: 0.5rem;
font-size: common.rem(18);
font-weight: 600;
color: var(--color-gray-900);
}

&-single-value {
&-input {
display: block;
width: 100%;
margin-bottom: 0.5rem;
padding: 1rem;
border: 1px solid var(--color-gray);
border-radius: var(--default-border-radius);
color: var(--color-gray-900);
background: url("@material-symbols/svg-400/outlined/arrow_drop_down.svg")
no-repeat right 1rem center / 1.5rem 1.5rem;
background-color: white;
background-position-x: calc(100% - 1rem);
appearance: none;
appearance: none;

option {
color: var(--color-gray-900);

&-disabled {
color: var(--color-gray-500);
&:disabled {
color: var(--color-gray-700);
}
}

&-error {
display: flex;
margin-top: 0.5rem;
gap: 0.5rem;
color: var(--color-red-700);

&-icon {
path {
fill: var(--color-red-700);
}
}
&:open {
background-image: url("@material-symbols/svg-400/outlined/arrow_drop_up.svg");
}
}

&__input-select {
min-height: unset !important;
padding: 0.75rem 1rem;
font-size: 1.125rem;
color: var(--color-gray-700);

&[aria-disabled] {
cursor: not-allowed !important;
pointer-events: auto !important;
&:focus-visible {
border-color: var(--color-axa);
box-shadow: 0 0 0 1px var(--color-axa) inset;
outline: 2px solid var(--color-focus);
outline-offset: 3px;
}

&-container {
border: 1px solid var(--color-gray-700);
border-radius: var(--default-border-radius);
color: var(--color-gray-700);
background-color: var(--color-white);
&:disabled {
cursor: not-allowed;
}

&-error {
margin-bottom: 0.5rem;
border-width: 1px;
border-color: var(--color-red-700);
&:not(:disabled):hover,
&:not(:disabled):active {
border-color: var(--color-axa);
box-shadow: 0 0 0 1px var(--color-axa) inset;
}

&:not([class*="-disabled"]):hover,
&:not([class*="-disabled"]):active {
border-color: var(--color-red-700);
box-shadow: 0 0 0 1px var(--color-red-700) inset !important;
}
}
&--error {
border-color: var(--color-red-700);

&-focused,
&:focus-visible {
box-shadow: 0 0 0 1px var(--color-axa) inset;
border-color: var(--color-red-700);
box-shadow: 0 0 0 1px var(--color-red-700) inset;
outline: 2px solid var(--color-focus);
outline-offset: 3px;
}

&:not(&-disabled, &-error):hover,
&:not(&-disabled, &-error):active {
border-color: var(--color-axa);
box-shadow: 0 0 0 1px var(--color-axa) inset;
}

&-disabled {
border-color: var(--color-gray-400);
background-color: var(--color-gray-200);
cursor: not-allowed !important;
pointer-events: auto !important;
}

&-icon {
&-disabled {
path {
fill: var(--color-gray-500);
}
}
&:not(:disabled):hover,
&:not(:disabled):active {
border-color: var(--color-red-700);
box-shadow: 0 0 0 1px var(--color-red-700) inset;
}
}
}

&-menu {
margin-top: 0.4rem;
margin-left: -1rem;
background-color: var(--color-white);
box-shadow: 0 4px 16px -2px #00008f40;

&-options {
padding: 0.75rem 1rem;
border: 1px solid transparent;
font-weight: 400;
color: var(--color-gray-900);
box-shadow: none;

&-selected {
font-weight: 600;
color: var(--color-axa);
}

&-focused {
border: 1px solid var(--color-axa);
}

&:nth-child(odd) {
background-color: var(--color-blue-2);
}

&:nth-child(even) {
background-color: var(--color-white);
}
}
}
&-placeholder {
color: var(--color-gray-700);
}
}
3 changes: 1 addition & 2 deletions client/look-and-feel/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@
"@types/react-dom": "^18.2.24",
"classnames": "^2.5.1",
"dompurify": "^3.1.5",
"rc-slider": "^11.1.7",
"react-select": "^5.9.0"
"rc-slider": "^11.1.7"
},
"lint-staged": {
"*.(js|jsx|ts|tsx)": "eslint --fix",
Expand Down
11 changes: 0 additions & 11 deletions client/look-and-feel/react/src/Form/Select/CustomOption.tsx

This file was deleted.

25 changes: 0 additions & 25 deletions client/look-and-feel/react/src/Form/Select/DropdownIndicator.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,13 @@ export const SelectStory: Story = {
</div>
),
args: {
className: "",
options,
label: "Label",
disabled: false,
required: false,
placeholder: "Placeholder",
noOptionsMessage: "Pas d'option",
errorLabel: "",
value: "",
},
argTypes: {
onChange: { action: "onChange" },
Expand Down
121 changes: 29 additions & 92 deletions client/look-and-feel/react/src/Form/Select/Select.tsx
Original file line number Diff line number Diff line change
@@ -1,61 +1,36 @@
import "@axa-fr/design-system-look-and-feel-css/dist/Form/Select/Select.scss";
import ReactSelect, {
ActionMeta,
ContainerProps,
GroupBase,
OptionProps,
SelectInstance,
SingleValue,
SingleValueProps,
} from "react-select";
import { ComponentPropsWithRef, forwardRef, useId } from "react";
import classNames from "classnames";
import { DropdownIndicator } from "./DropdownIndicator";
import { CustomOption } from "./CustomOption";
import { defaultAriaLiveMessages } from "./arialiveMessagesDefault";
import { InputError } from "../InputError";

type Option = { label: string; value: string | number };

type Props = Omit<
ComponentPropsWithRef<ReactSelect>,
"placeholder" | "noOptionsMessage"
> & {
type Props = Omit<ComponentPropsWithRef<"select">, "children"> & {
id?: string;
label?: string;
options: { label: string; value?: string | number | readonly string[] }[];
value: Option | null;
errorLabel?: string;
placeholder?: string;
noOptionsMessage?: string;
onChange: (
newValue: SingleValue<Option>,
actionMeta: ActionMeta<string>,
) => void;
disabled?: boolean;
required?: boolean;
};

const Select = forwardRef<
SelectInstance<unknown, boolean, GroupBase<unknown>>,
Props
>(
const Select = forwardRef<HTMLSelectElement, Props>(
(
{
id,
required,
disabled,
label,
errorLabel,
noOptionsMessage,
...otherProps
},
{ id, required, label, errorLabel, options, placeholder, ...otherProps },
inputRef,
) => {
const idError = useId();
let inputId = useId();
inputId = id || inputId;

const currentOption = options.find((o) => o.value === otherProps.value);
const currentText = currentOption ? currentOption.label : "";

const isShowingPlaceholder = placeholder ? currentText === "" : false;

const classname = classNames(
"af-form__select-input",
errorLabel && "af-form__select-input--error",
isShowingPlaceholder && "af-form__select-placeholder",
);

return (
<div>
{label && (
Expand All @@ -64,61 +39,23 @@ const Select = forwardRef<
{required && <span aria-hidden="true"> *</span>}
</label>
)}
<ReactSelect
inputId={inputId}
aria-errormessage={idError}
aria-invalid={Boolean(errorLabel)}
ariaLiveMessages={defaultAriaLiveMessages}
screenReaderStatus={({ count }: { count: number }) =>
`${count} résultat${count > 1 ? "s" : ""} disponible${count > 1 ? "s" : ""}`
}
unstyled
isDisabled={disabled}
noOptionsMessage={() => noOptionsMessage || "Aucun résultat"}
components={{
DropdownIndicator,
Option: CustomOption,
}}
classNames={{
control: () => "af-form__input-select",
menu: () => "af-form__input-select-menu",
menuList: () => "af-form__select-menu-list",
container: ({
isFocused,
isDisabled,
selectProps: { menuIsOpen },
}: ContainerProps<unknown, boolean, GroupBase<unknown>>) =>
classNames(
"af-form__input-select-container",
isFocused && "af-form__input-select-container-focused",
isDisabled && "af-form__input-select-container-disabled",
errorLabel &&
!isFocused &&
!menuIsOpen &&
"af-form__input-select-container-error",
),
option: ({
isSelected,
isFocused,
}: OptionProps<unknown, boolean, GroupBase<unknown>>) =>
classNames(
"af-form__input-select-menu-options",
isSelected && "af-form__input-select-menu-options-selected",
isFocused && "af-form__input-select-menu-options-focused",
),
singleValue: ({
isDisabled,
}: SingleValueProps<unknown, boolean, GroupBase<unknown>>) =>
classNames(
"af-form__select-single-value",
isDisabled && "af-form__select-single-value-disabled",
),
dropdownIndicator: () => "af-form__select-dropdown-indicator",
}}
className="af-form__input-select"
<select
className={classname}
{...otherProps}
ref={inputRef}
/>
id={inputId}
>
{Boolean(placeholder) && (
<option disabled value="">
{placeholder}
</option>
)}
{options.map((o) => (
<option key={o.label} value={o.value}>
{o.label}
</option>
))}
</select>
{errorLabel && <InputError id={idError} message={errorLabel} />}
</div>
);
Expand Down
Loading

0 comments on commit 86eb66f

Please sign in to comment.