💥(react) upgrade to React 19
https://react.dev/blog/2024/04/25/react-19-upgrade-guide https://react.dev/blog/2024/12/05/react-19
This commit is contained in:
committed by
Jean-Baptiste PENRATH
parent
0f6a8dfa72
commit
56d9ed88f0
5
.changeset/gorgeous-clocks-wash.md
Normal file
5
.changeset/gorgeous-clocks-wash.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@openfun/cunningham-react": major
|
||||
---
|
||||
|
||||
Upgrade to React 19
|
||||
@@ -2,14 +2,16 @@ import React, {
|
||||
AnchorHTMLAttributes,
|
||||
ButtonHTMLAttributes,
|
||||
createElement,
|
||||
forwardRef,
|
||||
ReactNode,
|
||||
RefAttributes,
|
||||
} from "react";
|
||||
|
||||
type DomProps = ButtonHTMLAttributes<HTMLButtonElement> &
|
||||
AnchorHTMLAttributes<HTMLAnchorElement>;
|
||||
|
||||
export type ButtonProps = Omit<DomProps, "color"> & {
|
||||
export type ButtonElement = HTMLButtonElement & HTMLAnchorElement;
|
||||
export type ButtonProps = Omit<DomProps, "color"> &
|
||||
RefAttributes<ButtonElement> & {
|
||||
size?: "medium" | "small" | "nano";
|
||||
color?:
|
||||
| "primary"
|
||||
@@ -24,11 +26,7 @@ export type ButtonProps = Omit<DomProps, "color"> & {
|
||||
fullWidth?: boolean;
|
||||
};
|
||||
|
||||
export type ButtonElement = HTMLButtonElement & HTMLAnchorElement;
|
||||
|
||||
export const Button = forwardRef<ButtonElement, ButtonProps>(
|
||||
(
|
||||
{
|
||||
export const Button = ({
|
||||
children,
|
||||
color = "primary",
|
||||
size = "medium",
|
||||
@@ -37,10 +35,9 @@ export const Button = forwardRef<ButtonElement, ButtonProps>(
|
||||
active,
|
||||
className,
|
||||
fullWidth,
|
||||
...props
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
...props
|
||||
}: ButtonProps) => {
|
||||
const classes = [
|
||||
"c__button",
|
||||
"c__button--" + color,
|
||||
@@ -77,5 +74,4 @@ export const Button = forwardRef<ButtonElement, ButtonProps>(
|
||||
{!!icon && iconPosition === "right" && iconElement}
|
||||
</>,
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React, {
|
||||
InputHTMLAttributes,
|
||||
PropsWithChildren,
|
||||
forwardRef,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
ReactNode,
|
||||
RefAttributes,
|
||||
} from "react";
|
||||
import classNames from "classnames";
|
||||
import { Field, FieldProps } from ":/components/Forms/Field";
|
||||
@@ -16,15 +16,19 @@ export type CheckboxOnlyProps = {
|
||||
};
|
||||
|
||||
export type CheckboxProps = InputHTMLAttributes<HTMLInputElement> &
|
||||
RefAttributes<HTMLInputElement> &
|
||||
FieldProps &
|
||||
CheckboxOnlyProps;
|
||||
|
||||
export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
||||
(
|
||||
{ indeterminate, className = "", checked, label, ...props }: CheckboxProps,
|
||||
export const Checkbox = ({
|
||||
indeterminate,
|
||||
className = "",
|
||||
checked,
|
||||
label,
|
||||
ref,
|
||||
) => {
|
||||
const inputRef = useRef<HTMLInputElement>();
|
||||
...props
|
||||
}: CheckboxProps) => {
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const [value, setValue] = useState<boolean>(!!checked);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -69,7 +73,7 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
||||
if (typeof ref === "function") {
|
||||
ref(checkboxRef);
|
||||
}
|
||||
inputRef.current = checkboxRef || undefined;
|
||||
inputRef.current = checkboxRef || null;
|
||||
}}
|
||||
/>
|
||||
<Indeterminate />
|
||||
@@ -80,8 +84,7 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
||||
</Field>
|
||||
</label>
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const CheckboxGroup = ({
|
||||
children,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { forwardRef, Ref, useMemo, useRef, useState } from "react";
|
||||
import React, { RefAttributes, useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
CalendarDate,
|
||||
createCalendar,
|
||||
@@ -83,24 +83,22 @@ const DropdownValues = ({ options, downShift }: DropdownValuesProps) => (
|
||||
</div>
|
||||
);
|
||||
|
||||
interface CalendarAuxProps extends CalendarAria {
|
||||
type CalendarAuxProps = CalendarAria &
|
||||
RefAttributes<HTMLDivElement> & {
|
||||
minYear?: number;
|
||||
maxYear?: number;
|
||||
state: RangeCalendarState | CalendarState;
|
||||
}
|
||||
};
|
||||
|
||||
const CalendarAux = forwardRef(
|
||||
(
|
||||
{
|
||||
const CalendarAux = ({
|
||||
state,
|
||||
minYear = 1900, // in gregorian calendar.
|
||||
maxYear = 2050, // in gregorian calendar.
|
||||
prevButtonProps,
|
||||
nextButtonProps,
|
||||
calendarProps,
|
||||
}: CalendarAuxProps,
|
||||
ref: Ref<HTMLDivElement>,
|
||||
) => {
|
||||
ref,
|
||||
}: CalendarAuxProps) => {
|
||||
const { t } = useCunningham();
|
||||
|
||||
const useTimeZoneFormatter = (formatOptions: DateFormatterOptions) => {
|
||||
@@ -310,8 +308,7 @@ const CalendarAux = forwardRef(
|
||||
onClick={() => state.focusPreviousSection(true)}
|
||||
disabled={
|
||||
!!state.minValue &&
|
||||
state.minValue.year >
|
||||
state.focusedDate.add({ years: -1 }).year
|
||||
state.minValue.year > state.focusedDate.add({ years: -1 }).year
|
||||
}
|
||||
aria-label={t(
|
||||
"components.forms.date_picker.previous_year_button_aria_label",
|
||||
@@ -355,8 +352,7 @@ const CalendarAux = forwardRef(
|
||||
<DropdownValues options={yearItems} downShift={downshiftYear} />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const Calendar = (props: CalendarProps<DateValue>) => {
|
||||
const { locale } = useLocale();
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import React, {
|
||||
forwardRef,
|
||||
PropsWithChildren,
|
||||
Ref,
|
||||
useMemo,
|
||||
useRef,
|
||||
RefAttributes,
|
||||
} from "react";
|
||||
import {
|
||||
DateRangePickerState,
|
||||
@@ -36,7 +35,8 @@ export type DatePickerAuxSubProps = FieldProps & {
|
||||
};
|
||||
|
||||
export type DatePickerAuxProps = PropsWithChildren &
|
||||
DatePickerAuxSubProps & {
|
||||
DatePickerAuxSubProps &
|
||||
RefAttributes<HTMLDivElement> & {
|
||||
pickerState: DateRangePickerState | DatePickerState;
|
||||
pickerProps: Pick<
|
||||
DateRangePickerAria | DatePickerAria,
|
||||
@@ -54,9 +54,7 @@ export type DatePickerAuxProps = PropsWithChildren &
|
||||
* This component is used by date and date range picker components.
|
||||
* It contains the common logic between the two.
|
||||
*/
|
||||
const DatePickerAux = forwardRef(
|
||||
(
|
||||
{
|
||||
const DatePickerAux = ({
|
||||
className,
|
||||
pickerState,
|
||||
pickerProps,
|
||||
@@ -70,16 +68,14 @@ const DatePickerAux = forwardRef(
|
||||
disabled = false,
|
||||
optionalClassName,
|
||||
isRange,
|
||||
ref,
|
||||
...props
|
||||
}: DatePickerAuxProps,
|
||||
ref: Ref<HTMLDivElement>,
|
||||
) => {
|
||||
}: DatePickerAuxProps) => {
|
||||
const { t, currentLocale } = useCunningham();
|
||||
const pickerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const isDateInvalid = useMemo(
|
||||
() =>
|
||||
pickerState.validationState === "invalid" || props.state === "error",
|
||||
() => pickerState.validationState === "invalid" || props.state === "error",
|
||||
[pickerState.validationState, props.state],
|
||||
);
|
||||
|
||||
@@ -98,9 +94,7 @@ const DatePickerAux = forwardRef(
|
||||
"c__date-picker--invalid": isDateInvalid,
|
||||
"c__date-picker--success": props.state === "success",
|
||||
"c__date-picker--focused":
|
||||
!isDateInvalid &&
|
||||
!disabled &&
|
||||
(pickerState.isOpen || isFocused),
|
||||
!isDateInvalid && !disabled && (pickerState.isOpen || isFocused),
|
||||
})}
|
||||
>
|
||||
<div
|
||||
@@ -201,7 +195,6 @@ const DatePickerAux = forwardRef(
|
||||
</Field>
|
||||
</I18nProvider>
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export default DatePickerAux;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, {
|
||||
forwardRef,
|
||||
PropsWithChildren,
|
||||
RefAttributes,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
@@ -15,13 +15,13 @@ import {
|
||||
FileUploaderRefType,
|
||||
} from ":/components/Forms/FileUploader/index";
|
||||
|
||||
interface DropZoneProps extends FileUploaderProps, PropsWithChildren {
|
||||
type DropZoneProps = FileUploaderProps &
|
||||
RefAttributes<FileUploaderRefType> &
|
||||
PropsWithChildren<{
|
||||
files: File[];
|
||||
}
|
||||
}>;
|
||||
|
||||
export const DropZone = forwardRef<FileUploaderRefType, DropZoneProps>(
|
||||
(
|
||||
{
|
||||
export const DropZone = ({
|
||||
multiple,
|
||||
name,
|
||||
state,
|
||||
@@ -34,10 +34,9 @@ export const DropZone = forwardRef<FileUploaderRefType, DropZoneProps>(
|
||||
files,
|
||||
onFilesChange,
|
||||
children,
|
||||
...props
|
||||
}: DropZoneProps,
|
||||
ref,
|
||||
) => {
|
||||
...props
|
||||
}: DropZoneProps) => {
|
||||
const [dragActive, setDragActive] = useState(false);
|
||||
const container = useRef<HTMLLabelElement>(null);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
@@ -92,14 +91,10 @@ export const DropZone = forwardRef<FileUploaderRefType, DropZoneProps>(
|
||||
|
||||
return (
|
||||
<label
|
||||
className={classNames(
|
||||
"c__file-uploader",
|
||||
"c__file-uploader--" + state,
|
||||
{
|
||||
className={classNames("c__file-uploader", "c__file-uploader--" + state, {
|
||||
"c__file-uploader--active": dragActive,
|
||||
"c__file-uploader--animate-icon": animateIcon,
|
||||
},
|
||||
)}
|
||||
})}
|
||||
onDragEnter={() => {
|
||||
setDragActive(true);
|
||||
}}
|
||||
@@ -157,5 +152,4 @@ export const DropZone = forwardRef<FileUploaderRefType, DropZoneProps>(
|
||||
</div>
|
||||
</label>
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import React, { forwardRef, useEffect, useMemo, useState } from "react";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { useCunningham } from ":/components/Provider";
|
||||
import { Button } from ":/components/Button";
|
||||
import {
|
||||
FileUploaderProps,
|
||||
FileUploaderRefType,
|
||||
} from ":/components/Forms/FileUploader/index";
|
||||
import { FileUploaderProps } from ":/components/Forms/FileUploader/index";
|
||||
import { DropZone } from ":/components/Forms/FileUploader/DropZone";
|
||||
|
||||
export const FileUploaderMono = forwardRef<
|
||||
FileUploaderRefType,
|
||||
FileUploaderProps
|
||||
>(({ fakeDefaultFiles, ...props }, ref) => {
|
||||
export const FileUploaderMono = ({
|
||||
fakeDefaultFiles,
|
||||
ref,
|
||||
...props
|
||||
}: FileUploaderProps) => {
|
||||
const { t } = useCunningham();
|
||||
const [file, setFile] = useState<File | undefined>(
|
||||
fakeDefaultFiles && fakeDefaultFiles.length > 0
|
||||
@@ -91,4 +89,4 @@ export const FileUploaderMono = forwardRef<
|
||||
)}
|
||||
</>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import React, { forwardRef, useEffect, useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useCunningham } from ":/components/Provider";
|
||||
import { formatBytes } from ":/components/Forms/FileUploader/utils";
|
||||
import { Button } from ":/components/Button";
|
||||
import {
|
||||
FileUploaderProps,
|
||||
FileUploaderRefType,
|
||||
} from ":/components/Forms/FileUploader/index";
|
||||
import { FileUploaderProps } from ":/components/Forms/FileUploader/index";
|
||||
import { DropZone } from ":/components/Forms/FileUploader/DropZone";
|
||||
|
||||
export const FileUploaderMulti = forwardRef<
|
||||
FileUploaderRefType,
|
||||
FileUploaderProps
|
||||
>(({ fullWidth, fakeDefaultFiles, ...props }, ref) => {
|
||||
export const FileUploaderMulti = ({
|
||||
fullWidth,
|
||||
fakeDefaultFiles,
|
||||
ref,
|
||||
...props
|
||||
}: FileUploaderProps) => {
|
||||
const { t } = useCunningham();
|
||||
const [files, setFiles] = useState<File[]>(fakeDefaultFiles || []);
|
||||
|
||||
@@ -59,4 +58,4 @@ export const FileUploaderMulti = forwardRef<
|
||||
)}
|
||||
</>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import React, { forwardRef, InputHTMLAttributes, ReactElement } from "react";
|
||||
import React, { InputHTMLAttributes, ReactElement, RefAttributes } from "react";
|
||||
import { Field, FieldProps, FieldState } from ":/components/Forms/Field";
|
||||
import { FileUploaderMulti } from ":/components/Forms/FileUploader/FileUploaderMulti";
|
||||
import { FileUploaderMono } from ":/components/Forms/FileUploader/FileUploaderMono";
|
||||
|
||||
export interface FileUploaderProps
|
||||
extends Omit<FieldProps, "state">,
|
||||
InputHTMLAttributes<HTMLInputElement> {
|
||||
InputHTMLAttributes<HTMLInputElement>,
|
||||
RefAttributes<FileUploaderRefType> {
|
||||
state?: FieldState | "uploading" | undefined;
|
||||
multiple?: boolean;
|
||||
icon?: ReactElement;
|
||||
@@ -25,8 +26,11 @@ export interface FileUploaderRefType {
|
||||
reset: () => void;
|
||||
}
|
||||
|
||||
export const FileUploader = forwardRef<FileUploaderRefType, FileUploaderProps>(
|
||||
({ fullWidth, ...props }, ref) => {
|
||||
export const FileUploader = ({
|
||||
fullWidth,
|
||||
ref,
|
||||
...props
|
||||
}: FileUploaderProps) => {
|
||||
return (
|
||||
<Field fullWidth={fullWidth} className={props.className}>
|
||||
{props.multiple ? (
|
||||
@@ -36,5 +40,4 @@ export const FileUploader = forwardRef<FileUploaderRefType, FileUploaderProps>(
|
||||
)}
|
||||
</Field>
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import React, { forwardRef } from "react";
|
||||
import React from "react";
|
||||
import { Input, InputProps } from ":/components/Forms/Input/index";
|
||||
import { Button } from ":/components/Button";
|
||||
import { useCunningham } from ":/components/Provider";
|
||||
|
||||
export const InputPassword = forwardRef<
|
||||
HTMLInputElement,
|
||||
Omit<InputProps, "rightIcon">
|
||||
>((props: InputProps, ref) => {
|
||||
export const InputPassword = (props: Omit<InputProps, "rightIcon">) => {
|
||||
const [showPassword, setShowPassword] = React.useState(false);
|
||||
const { className, ...otherProps } = props;
|
||||
const customClassName = "c__input--password";
|
||||
@@ -14,7 +11,6 @@ export const InputPassword = forwardRef<
|
||||
return (
|
||||
<Input
|
||||
{...otherProps}
|
||||
ref={ref}
|
||||
className={className + " " + customClassName}
|
||||
type={showPassword ? "text" : "password"}
|
||||
rightIcon={
|
||||
@@ -38,4 +34,4 @@ export const InputPassword = forwardRef<
|
||||
}
|
||||
/>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, {
|
||||
forwardRef,
|
||||
InputHTMLAttributes,
|
||||
ReactNode,
|
||||
RefAttributes,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
@@ -20,12 +20,11 @@ export type InputOnlyProps = {
|
||||
};
|
||||
|
||||
export type InputProps = InputHTMLAttributes<HTMLInputElement> &
|
||||
RefAttributes<HTMLInputElement> &
|
||||
FieldProps &
|
||||
InputOnlyProps;
|
||||
|
||||
export const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
(
|
||||
{
|
||||
export const Input = ({
|
||||
className,
|
||||
defaultValue,
|
||||
label,
|
||||
@@ -34,10 +33,9 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
rightIcon,
|
||||
charCounter,
|
||||
charCounterMax,
|
||||
...props
|
||||
}: InputProps,
|
||||
ref,
|
||||
) => {
|
||||
...props
|
||||
}: InputProps) => {
|
||||
const classes = ["c__input"];
|
||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||
const [inputFocus, setInputFocus] = useState(false);
|
||||
@@ -132,11 +130,8 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
}}
|
||||
/>
|
||||
</LabelledBox>
|
||||
{!!rightIcon && (
|
||||
<div className="c__input__icon-right">{rightIcon}</div>
|
||||
)}
|
||||
{!!rightIcon && <div className="c__input__icon-right">{rightIcon}</div>}
|
||||
</div>
|
||||
</Field>
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, {
|
||||
InputHTMLAttributes,
|
||||
PropsWithChildren,
|
||||
forwardRef,
|
||||
ReactNode,
|
||||
RefAttributes,
|
||||
} from "react";
|
||||
import classNames from "classnames";
|
||||
import { Field, FieldProps } from ":/components/Forms/Field";
|
||||
@@ -12,11 +12,11 @@ export type RadioOnlyProps = {
|
||||
};
|
||||
|
||||
export type RadioProps = InputHTMLAttributes<HTMLInputElement> &
|
||||
RefAttributes<HTMLInputElement> &
|
||||
FieldProps &
|
||||
RadioOnlyProps;
|
||||
|
||||
export const Radio = forwardRef<HTMLInputElement, RadioProps>(
|
||||
({ className, label, ...props }: RadioProps, ref) => {
|
||||
export const Radio = ({ className, label, ref, ...props }: RadioProps) => {
|
||||
const {
|
||||
compact,
|
||||
fullWidth,
|
||||
@@ -42,8 +42,7 @@ export const Radio = forwardRef<HTMLInputElement, RadioProps>(
|
||||
</Field>
|
||||
</label>
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const RadioGroup = ({
|
||||
className,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { forwardRef, PropsWithChildren, ReactNode } from "react";
|
||||
import React, { PropsWithChildren, ReactNode, RefAttributes } from "react";
|
||||
import { SelectMulti } from ":/components/Forms/Select/multi";
|
||||
import { SelectMono } from ":/components/Forms/Select/mono";
|
||||
import { FieldProps } from ":/components/Forms/Field";
|
||||
@@ -28,6 +28,7 @@ export interface SelectHandle {
|
||||
}
|
||||
|
||||
export type SelectProps = PropsWithChildren &
|
||||
RefAttributes<SelectHandle> &
|
||||
FieldProps & {
|
||||
label: string;
|
||||
hideLabel?: boolean;
|
||||
@@ -53,16 +54,12 @@ export type SelectProps = PropsWithChildren &
|
||||
target: { value: string | undefined };
|
||||
}) => void;
|
||||
};
|
||||
export const Select = forwardRef<SelectHandle, SelectProps>((props, ref) => {
|
||||
export const Select = (props: SelectProps) => {
|
||||
if (props.defaultValue && props.value) {
|
||||
throw new Error(
|
||||
"You cannot use both defaultValue and value props on Select component",
|
||||
);
|
||||
}
|
||||
|
||||
return props.multi ? (
|
||||
<SelectMulti {...props} ref={ref} />
|
||||
) : (
|
||||
<SelectMono {...props} ref={ref} />
|
||||
);
|
||||
});
|
||||
return props.multi ? <SelectMulti {...props} /> : <SelectMono {...props} />;
|
||||
};
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
import React, {
|
||||
forwardRef,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import React, { useEffect, useImperativeHandle, useRef, useState } from "react";
|
||||
import { useCombobox } from "downshift";
|
||||
import classNames from "classnames";
|
||||
import { useCunningham } from ":/components/Provider";
|
||||
@@ -15,11 +9,13 @@ import {
|
||||
SelectMonoAux,
|
||||
SubProps,
|
||||
} from ":/components/Forms/Select/mono-common";
|
||||
import { SelectHandle } from ":/components/Forms/Select";
|
||||
import { isOptionWithRender } from ":/components/Forms/Select/utils";
|
||||
|
||||
export const SelectMonoSearchable = forwardRef<SelectHandle, SubProps>(
|
||||
({ showLabelWhenSelected = true, ...props }, ref) => {
|
||||
export const SelectMonoSearchable = ({
|
||||
showLabelWhenSelected = true,
|
||||
ref,
|
||||
...props
|
||||
}: SubProps) => {
|
||||
const { t } = useCunningham();
|
||||
const [optionsToDisplay, setOptionsToDisplay] = useState(props.options);
|
||||
const [hasInputFocused, setHasInputFocused] = useState(false);
|
||||
@@ -152,5 +148,4 @@ export const SelectMonoSearchable = forwardRef<SelectHandle, SubProps>(
|
||||
downshiftReturn.selectedItem.render()}
|
||||
</SelectMonoAux>
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
import { useSelect, UseSelectReturnValue } from "downshift";
|
||||
import React, {
|
||||
forwardRef,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
} from "react";
|
||||
import React, { useEffect, useImperativeHandle, useRef } from "react";
|
||||
import {
|
||||
optionToString,
|
||||
optionToValue,
|
||||
SelectMonoAux,
|
||||
SubProps,
|
||||
} from ":/components/Forms/Select/mono-common";
|
||||
import { Option, SelectHandle, SelectProps } from ":/components/Forms/Select";
|
||||
import { Option, SelectProps } from ":/components/Forms/Select";
|
||||
import { SelectedOption } from ":/components/Forms/Select/utils";
|
||||
|
||||
/**
|
||||
@@ -32,8 +27,7 @@ const useKeepSelectedItemInSyncWithOptions = (
|
||||
}, [props.value, props.options]);
|
||||
};
|
||||
|
||||
export const SelectMonoSimple = forwardRef<SelectHandle, SubProps>(
|
||||
(props, ref) => {
|
||||
export const SelectMonoSimple = ({ ref, ...props }: SubProps) => {
|
||||
const downshiftReturn = useSelect({
|
||||
...props.downshiftProps,
|
||||
items: props.options,
|
||||
@@ -67,5 +61,4 @@ export const SelectMonoSimple = forwardRef<SelectHandle, SubProps>(
|
||||
<SelectedOption option={downshiftReturn.selectedItem} {...props} />
|
||||
</SelectMonoAux>
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import React, { forwardRef, useEffect, useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { UseSelectStateChange } from "downshift";
|
||||
import { optionToValue, SubProps } from ":/components/Forms/Select/mono-common";
|
||||
import { SelectMonoSearchable } from ":/components/Forms/Select/mono-searchable";
|
||||
import { SelectMonoSimple } from ":/components/Forms/Select/mono-simple";
|
||||
import { Option, SelectHandle, SelectProps } from ":/components/Forms/Select";
|
||||
import { Option, SelectProps } from ":/components/Forms/Select";
|
||||
|
||||
export const SelectMono = forwardRef<SelectHandle, SelectProps>(
|
||||
(props, ref) => {
|
||||
export const SelectMono = (props: SelectProps) => {
|
||||
const defaultSelectedItem = props.defaultValue
|
||||
? props.options.find(
|
||||
(option) => optionToValue(option) === props.defaultValue,
|
||||
@@ -53,15 +52,12 @@ export const SelectMono = forwardRef<SelectHandle, SelectProps>(
|
||||
{...props}
|
||||
downshiftProps={commonDownshiftProps}
|
||||
value={value}
|
||||
ref={ref}
|
||||
/>
|
||||
) : (
|
||||
<SelectMonoSimple
|
||||
{...props}
|
||||
downshiftProps={commonDownshiftProps}
|
||||
value={value}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -12,7 +12,7 @@ import { SelectMenu } from ":/components/Forms/Select/select-menu";
|
||||
|
||||
export const SelectMultiMenu = (
|
||||
props: SelectMultiAuxProps & {
|
||||
selectRef: React.RefObject<HTMLDivElement>;
|
||||
selectRef: React.RefObject<HTMLDivElement | null>;
|
||||
},
|
||||
) => {
|
||||
const { t } = useCunningham();
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
import React, {
|
||||
forwardRef,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import React, { useEffect, useImperativeHandle, useRef, useState } from "react";
|
||||
import { useCombobox, useMultipleSelection } from "downshift";
|
||||
import { optionToString } from ":/components/Forms/Select/mono-common";
|
||||
import {
|
||||
@@ -12,10 +6,8 @@ import {
|
||||
SelectMultiAux,
|
||||
SubProps,
|
||||
} from ":/components/Forms/Select/multi-common";
|
||||
import { SelectHandle } from ":/components/Forms/Select/index";
|
||||
|
||||
export const SelectMultiSearchable = forwardRef<SelectHandle, SubProps>(
|
||||
(props, ref) => {
|
||||
export const SelectMultiSearchable = ({ ref, ...props }: SubProps) => {
|
||||
const [inputValue, setInputValue] = React.useState<string>();
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const options = React.useMemo(
|
||||
@@ -30,8 +22,7 @@ export const SelectMultiSearchable = forwardRef<SelectHandle, SubProps>(
|
||||
selectedItems: props.selectedItems,
|
||||
onStateChange({ selectedItems: newSelectedItems, type }) {
|
||||
switch (type) {
|
||||
case useMultipleSelection.stateChangeTypes
|
||||
.SelectedItemKeyDownBackspace:
|
||||
case useMultipleSelection.stateChangeTypes.SelectedItemKeyDownBackspace:
|
||||
case useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete:
|
||||
case useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace:
|
||||
case useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem:
|
||||
@@ -151,10 +142,7 @@ export const SelectMultiSearchable = forwardRef<SelectHandle, SubProps>(
|
||||
}}
|
||||
useMultipleSelectionReturn={useMultipleSelectionReturn}
|
||||
>
|
||||
<span
|
||||
className="c__select__inner__value__input"
|
||||
data-value={inputValue}
|
||||
>
|
||||
<span className="c__select__inner__value__input" data-value={inputValue}>
|
||||
<input
|
||||
{...inputProps}
|
||||
onFocus={() => {
|
||||
@@ -169,5 +157,4 @@ export const SelectMultiSearchable = forwardRef<SelectHandle, SubProps>(
|
||||
</span>
|
||||
</SelectMultiAux>
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { forwardRef, useImperativeHandle, useRef } from "react";
|
||||
import React, { useImperativeHandle, useRef } from "react";
|
||||
import { useMultipleSelection, useSelect } from "downshift";
|
||||
import {
|
||||
getMultiOptionsFilter,
|
||||
@@ -9,10 +9,9 @@ import {
|
||||
optionsEqual,
|
||||
optionToString,
|
||||
} from ":/components/Forms/Select/mono-common";
|
||||
import { Option, SelectHandle } from ":/components/Forms/Select/index";
|
||||
import { Option } from ":/components/Forms/Select/index";
|
||||
|
||||
export const SelectMultiSimple = forwardRef<SelectHandle, SubProps>(
|
||||
(props, ref) => {
|
||||
export const SelectMultiSimple = ({ ref, ...props }: SubProps) => {
|
||||
const isSelected = (option: Option) =>
|
||||
!!props.selectedItems.find((selectedItem) =>
|
||||
optionsEqual(selectedItem, option),
|
||||
@@ -25,17 +24,14 @@ export const SelectMultiSimple = forwardRef<SelectHandle, SubProps>(
|
||||
highlighted: isSelected(option),
|
||||
}));
|
||||
}
|
||||
return props.options.filter(
|
||||
getMultiOptionsFilter(props.selectedItems, ""),
|
||||
);
|
||||
return props.options.filter(getMultiOptionsFilter(props.selectedItems, ""));
|
||||
}, [props.selectedItems]);
|
||||
|
||||
const useMultipleSelectionReturn = useMultipleSelection({
|
||||
selectedItems: props.selectedItems,
|
||||
onStateChange({ selectedItems: newSelectedItems, type }) {
|
||||
switch (type) {
|
||||
case useMultipleSelection.stateChangeTypes
|
||||
.SelectedItemKeyDownBackspace:
|
||||
case useMultipleSelection.stateChangeTypes.SelectedItemKeyDownBackspace:
|
||||
case useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete:
|
||||
case useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace:
|
||||
case useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem:
|
||||
@@ -78,8 +74,7 @@ export const SelectMultiSimple = forwardRef<SelectHandle, SubProps>(
|
||||
// Remove the item if it is already selected.
|
||||
props.onSelectedItemsChange(
|
||||
props.selectedItems.filter(
|
||||
(selectedItem) =>
|
||||
!optionsEqual(selectedItem, newSelectedItem),
|
||||
(selectedItem) => !optionsEqual(selectedItem, newSelectedItem),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
@@ -131,5 +126,4 @@ export const SelectMultiSimple = forwardRef<SelectHandle, SubProps>(
|
||||
useMultipleSelectionReturn={useMultipleSelectionReturn}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
import React, { forwardRef, useEffect } from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import { optionToValue } from ":/components/Forms/Select/mono-common";
|
||||
import { SelectMultiSearchable } from ":/components/Forms/Select/multi-searchable";
|
||||
import { SelectMultiSimple } from ":/components/Forms/Select/multi-simple";
|
||||
import { SubProps } from ":/components/Forms/Select/multi-common";
|
||||
import {
|
||||
Option,
|
||||
SelectHandle,
|
||||
SelectProps,
|
||||
} from ":/components/Forms/Select/index";
|
||||
import { Option, SelectProps } from ":/components/Forms/Select/index";
|
||||
|
||||
export type SelectMultiProps = Omit<SelectProps, "onChange"> & {
|
||||
onChange?: (event: { target: { value: string[] } }) => void;
|
||||
};
|
||||
|
||||
export const SelectMulti = forwardRef<SelectHandle, SelectMultiProps>(
|
||||
(props, ref) => {
|
||||
export const SelectMulti = (props: SelectMultiProps) => {
|
||||
const getSelectedItemsFromProps = () => {
|
||||
const valueToUse = props.defaultValue ?? props.value ?? [];
|
||||
return props.options.filter((option) =>
|
||||
@@ -58,7 +53,6 @@ export const SelectMulti = forwardRef<SelectHandle, SelectMultiProps>(
|
||||
{...props}
|
||||
selectedItems={selectedItems}
|
||||
onSelectedItemsChange={onSelectedItemsChange}
|
||||
ref={ref}
|
||||
/>
|
||||
) : (
|
||||
<SelectMultiSimple
|
||||
@@ -66,8 +60,6 @@ export const SelectMulti = forwardRef<SelectHandle, SelectMultiProps>(
|
||||
{...props}
|
||||
selectedItems={selectedItems}
|
||||
onSelectedItemsChange={onSelectedItemsChange}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@ import { SelectMultiAuxProps } from ":/components/Forms/Select/multi-common";
|
||||
|
||||
export interface SelectDropdownProps extends PropsWithChildren {
|
||||
isOpen: boolean;
|
||||
selectRef: React.RefObject<HTMLDivElement>;
|
||||
selectRef: React.RefObject<HTMLDivElement | null>;
|
||||
menuOptionsStyle?: SelectProps["menuOptionsStyle"];
|
||||
downshiftReturn:
|
||||
| SelectAuxProps["downshiftReturn"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { InputHTMLAttributes, forwardRef } from "react";
|
||||
import React, { InputHTMLAttributes, RefAttributes } from "react";
|
||||
import classNames from "classnames";
|
||||
import { Field, FieldProps } from ":/components/Forms/Field";
|
||||
|
||||
@@ -8,11 +8,16 @@ export type SwitchOnlyProps = {
|
||||
};
|
||||
|
||||
export type SwitchProps = InputHTMLAttributes<HTMLInputElement> &
|
||||
RefAttributes<HTMLInputElement> &
|
||||
FieldProps &
|
||||
SwitchOnlyProps;
|
||||
|
||||
export const Switch = forwardRef<HTMLInputElement, SwitchProps>(
|
||||
({ label, labelSide = "left", ...props }: SwitchProps, ref) => {
|
||||
export const Switch = ({
|
||||
label,
|
||||
labelSide = "left",
|
||||
ref,
|
||||
...props
|
||||
}: SwitchProps) => {
|
||||
const {
|
||||
compact,
|
||||
className,
|
||||
@@ -50,5 +55,4 @@ export const Switch = forwardRef<HTMLInputElement, SwitchProps>(
|
||||
</Field>
|
||||
</label>
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, {
|
||||
forwardRef,
|
||||
RefAttributes,
|
||||
TextareaHTMLAttributes,
|
||||
useEffect,
|
||||
useRef,
|
||||
@@ -11,14 +11,22 @@ import { LabelledBox } from ":/components/Forms/LabelledBox";
|
||||
import { randomString } from ":/utils";
|
||||
|
||||
export type TextAreaProps = TextareaHTMLAttributes<HTMLTextAreaElement> &
|
||||
RefAttributes<HTMLTextAreaElement> &
|
||||
FieldProps & {
|
||||
label?: string;
|
||||
charCounter?: boolean;
|
||||
charCounterMax?: number;
|
||||
};
|
||||
|
||||
export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(
|
||||
({ label, id, defaultValue, charCounter, charCounterMax, ...props }, ref) => {
|
||||
export const TextArea = ({
|
||||
label,
|
||||
id,
|
||||
defaultValue,
|
||||
charCounter,
|
||||
charCounterMax,
|
||||
ref,
|
||||
...props
|
||||
}: TextAreaProps) => {
|
||||
const areaRef = useRef<HTMLTextAreaElement | null>(null);
|
||||
const [inputFocus, setInputFocus] = useState(false);
|
||||
const [value, setValue] = useState(defaultValue || props.value || "");
|
||||
@@ -100,5 +108,4 @@ export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(
|
||||
</div>
|
||||
</Field>
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@ import classNames from "classnames";
|
||||
import { useHandleClickOutside } from ":/hooks/useHandleClickOutside";
|
||||
|
||||
export type PopoverProps = PropsWithChildren & {
|
||||
parentRef: RefObject<HTMLDivElement>;
|
||||
parentRef: RefObject<HTMLDivElement | null>;
|
||||
onClickOutside: () => void;
|
||||
borderless?: boolean;
|
||||
};
|
||||
@@ -22,7 +22,7 @@ export const Popover = ({
|
||||
}: PopoverProps) => {
|
||||
const popoverRef = useRef<HTMLDivElement>(null);
|
||||
useHandleClickOutside(parentRef, onClickOutside);
|
||||
const timeout = useRef<ReturnType<typeof setTimeout>>();
|
||||
const timeout = useRef<ReturnType<typeof setTimeout>>(null);
|
||||
const [topPosition, setTopPosition] = useState<number | undefined>();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
|
||||
@@ -25,7 +25,7 @@ export interface ToastProps extends PropsWithChildren {
|
||||
export const Toast = (props: ToastProps) => {
|
||||
const [animateDisappear, setAnimateDisappear] = React.useState(false);
|
||||
const container = useRef<HTMLDivElement>(null);
|
||||
const disappearTimeout = useRef<NodeJS.Timeout>();
|
||||
const disappearTimeout = useRef<NodeJS.Timeout>(null);
|
||||
|
||||
// Register a timeout to remove the toast after the duration.
|
||||
useEffect(() => {
|
||||
@@ -34,7 +34,7 @@ export const Toast = (props: ToastProps) => {
|
||||
}
|
||||
disappearTimeout.current = setTimeout(async () => {
|
||||
setAnimateDisappear(true);
|
||||
disappearTimeout.current = undefined;
|
||||
disappearTimeout.current = null;
|
||||
}, props.duration);
|
||||
return () => {
|
||||
if (disappearTimeout.current) {
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import React, { PropsWithChildren, ReactElement, ReactNode } from "react";
|
||||
import React, {
|
||||
PropsWithChildren,
|
||||
ReactElement,
|
||||
ReactNode,
|
||||
RefObject,
|
||||
} from "react";
|
||||
import { OverlayArrow } from "react-aria-components";
|
||||
import {
|
||||
mergeProps,
|
||||
@@ -72,7 +77,11 @@ export const Tooltip = ({
|
||||
return (
|
||||
<>
|
||||
{React.cloneElement(
|
||||
React.Children.toArray(props.children)[0] as ReactElement,
|
||||
React.Children.toArray(props.children)[0] as ReactElement<
|
||||
typeof useTooltipTriggerRes.triggerProps & {
|
||||
ref: RefObject<ReactElement | null>;
|
||||
}
|
||||
>,
|
||||
{
|
||||
ref,
|
||||
...useTooltipTriggerRes.triggerProps,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { RefObject, useEffect } from "react";
|
||||
|
||||
export const useHandleClickOutside = (
|
||||
ref: RefObject<HTMLDivElement>,
|
||||
ref: RefObject<HTMLDivElement | null>,
|
||||
onClickOutside: any,
|
||||
) => {
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user