Skip to content

Commit 35a8a95

Browse files
committed
Rollback to old Select component #64
1 parent 9dd0d10 commit 35a8a95

File tree

2 files changed

+156
-210
lines changed

2 files changed

+156
-210
lines changed

src/Select.tsx

Lines changed: 79 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,147 +1,113 @@
11
"use client";
22

3-
import React, { memo, forwardRef, ReactNode, useId, type CSSProperties, ForwardedRef } from "react";
3+
import React, { memo, forwardRef, ReactNode, useId, type CSSProperties } from "react";
44
import { symToStr } from "tsafe/symToStr";
55
import { assert } from "tsafe/assert";
66
import type { Equals } from "tsafe";
77
import { fr } from "./fr";
88
import { cx } from "./tools/cx";
99

10-
export type SelectProps<Options extends GenericOption<DefaultOptionValue>[]> = {
11-
options: Options;
10+
export type SelectProps = {
1211
className?: string;
1312
label: ReactNode;
1413
hint?: ReactNode;
15-
nativeSelectProps?: Omit<
16-
React.DetailedHTMLProps<React.SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>,
17-
"value" | "defaultValue"
18-
> & {
19-
// Overriding the type of value and defaultValue to only accept the value type of the options
20-
value?: Options[number]["value"];
21-
defaultValue?: Options[number]["value"];
22-
};
14+
nativeSelectProps: React.DetailedHTMLProps<
15+
React.SelectHTMLAttributes<HTMLSelectElement>,
16+
HTMLSelectElement
17+
>;
18+
children: ReactNode;
2319
/** Default: false */
2420
disabled?: boolean;
2521
/** Default: "default" */
2622
state?: "success" | "error" | "default";
2723
/** The message won't be displayed if state is "default" */
2824
stateRelatedMessage?: ReactNode;
2925
style?: CSSProperties;
30-
placeholder?: string;
3126
};
32-
export type GenericOption<OptionValue> = {
33-
value: OptionValue;
34-
label: string;
35-
disabled?: boolean;
36-
hidden?: boolean;
37-
selected?: boolean;
38-
};
39-
40-
type DefaultOptionValue = string | number | readonly string[] | undefined;
4127

4228
/**
4329
* @see <https://react-dsfr-components.etalab.studio/?path=/docs/components-select>
4430
* */
45-
export const Select = <T extends GenericOption<DefaultOptionValue>[]>(
46-
props: SelectProps<T>,
47-
ref: React.LegacyRef<HTMLDivElement>
48-
) => {
49-
const {
50-
className,
51-
label,
52-
hint,
53-
nativeSelectProps,
54-
disabled = false,
55-
options,
56-
state = "default",
57-
stateRelatedMessage,
58-
placeholder,
59-
style,
60-
...rest
61-
} = props;
31+
export const Select = memo(
32+
forwardRef<HTMLDivElement, SelectProps>((props, ref) => {
33+
const {
34+
className,
35+
label,
36+
hint,
37+
nativeSelectProps,
38+
disabled = false,
39+
children,
40+
state = "default",
41+
stateRelatedMessage,
42+
style,
43+
...rest
44+
} = props;
6245

63-
assert<Equals<keyof typeof rest, never>>();
64-
const elementId = nativeSelectProps?.id || useId();
65-
const selectId = `select-${elementId}`;
66-
const stateDescriptionId = `select-${elementId}-desc`;
67-
const displayedOptions = placeholder
68-
? [
69-
{
70-
label: placeholder,
71-
value: "",
72-
disabled: true
73-
},
74-
...options
75-
]
76-
: options;
77-
return (
78-
<div
79-
className={cx(
80-
fr.cx(
81-
"fr-select-group",
82-
disabled && "fr-select-group--disabled",
83-
(() => {
84-
switch (state) {
85-
case "error":
86-
return "fr-select-group--error";
87-
case "success":
88-
return "fr-select-group--valid";
89-
case "default":
90-
return undefined;
91-
}
92-
assert<Equals<typeof state, never>>(false);
93-
})()
94-
),
95-
className
96-
)}
97-
ref={ref}
98-
style={style}
99-
{...rest}
100-
>
101-
<label className={fr.cx("fr-label")} htmlFor={selectId}>
102-
{label}
103-
{hint !== undefined && <span className={fr.cx("fr-hint-text")}>{hint}</span>}
104-
</label>
105-
<select
106-
{...nativeSelectProps}
107-
className={cx(fr.cx("fr-select"), nativeSelectProps?.className)}
108-
id={selectId}
109-
aria-describedby={stateDescriptionId}
110-
disabled={disabled}
111-
>
112-
{displayedOptions.map(option => (
113-
<option {...option}>{option.label}</option>
114-
))}
115-
</select>
116-
{state !== "default" && (
117-
<p
118-
id={stateDescriptionId}
119-
className={fr.cx(
46+
assert<Equals<keyof typeof rest, never>>();
47+
48+
const selectId = `select-${useId()}`;
49+
const stateDescriptionId = `select-${useId()}-desc`;
50+
51+
return (
52+
<div
53+
className={cx(
54+
fr.cx(
55+
"fr-select-group",
56+
disabled && "fr-select-group--disabled",
12057
(() => {
12158
switch (state) {
12259
case "error":
123-
return "fr-error-text";
60+
return "fr-select-group--error";
12461
case "success":
125-
return "fr-valid-text";
62+
return "fr-select-group--valid";
63+
case "default":
64+
return undefined;
12665
}
12766
assert<Equals<typeof state, never>>(false);
12867
})()
129-
)}
68+
),
69+
className
70+
)}
71+
ref={ref}
72+
style={style}
73+
{...rest}
74+
>
75+
<label className={fr.cx("fr-label")} htmlFor={selectId}>
76+
{label}
77+
{hint !== undefined && <span className={fr.cx("fr-hint-text")}>{hint}</span>}
78+
</label>
79+
<select
80+
{...nativeSelectProps}
81+
className={cx(fr.cx("fr-select"), nativeSelectProps.className)}
82+
id={selectId}
83+
aria-describedby={stateDescriptionId}
84+
disabled={disabled}
13085
>
131-
{stateRelatedMessage}
132-
</p>
133-
)}
134-
</div>
135-
);
136-
};
86+
{children}
87+
</select>
88+
{state !== "default" && (
89+
<p
90+
id={stateDescriptionId}
91+
className={fr.cx(
92+
(() => {
93+
switch (state) {
94+
case "error":
95+
return "fr-error-text";
96+
case "success":
97+
return "fr-valid-text";
98+
}
99+
assert<Equals<typeof state, never>>(false);
100+
})()
101+
)}
102+
>
103+
{stateRelatedMessage}
104+
</p>
105+
)}
106+
</div>
107+
);
108+
})
109+
);
137110

138-
const ForwardedSelect = forwardRef(Select) as <T extends GenericOption<DefaultOptionValue>[]>(
139-
props: SelectProps<T> & { ref?: ForwardedRef<HTMLDivElement> }
140-
) => ReturnType<typeof Select>;
141-
142-
const MemoizedSelect = memo(ForwardedSelect) as typeof ForwardedSelect & {
143-
displayName: string;
144-
};
145-
MemoizedSelect.displayName = symToStr({ Select });
111+
Select.displayName = symToStr({ Select });
146112

147-
export default MemoizedSelect;
113+
export default Select;

0 commit comments

Comments
 (0)