This commit is contained in:
Benjamin Toby
2025-02-04 13:21:44 +01:00
parent f0850146be
commit 442ad5aa32
17 changed files with 207 additions and 79 deletions
+1
View File
@@ -27,6 +27,7 @@ export default function Form<T extends object = { [key: string]: any }>({
const formData = new FormData(formEl);
const data = Object.fromEntries(formData.entries()) as T;
props.submitHandler?.(e, data);
props.onSubmit?.(e);
}}
>
{props.children}
+9 -4
View File
@@ -14,7 +14,9 @@ type ImageUploadProps = DetailedHTMLProps<
React.HTMLAttributes<HTMLDivElement>,
HTMLDivElement
> & {
onChange?: (imgData: ImageInputToBase64FunctionReturn | undefined) => any;
onChangeHandler?: (
imgData: ImageInputToBase64FunctionReturn | undefined
) => any;
fileInputProps?: DetailedHTMLProps<
React.InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement
@@ -35,8 +37,11 @@ type ImageUploadProps = DetailedHTMLProps<
disablePreview?: boolean;
};
/**
* @note use the `onChangeHandler` prop to grab the parsed base64 image object
*/
export default function ImageUpload({
onChange,
onChangeHandler,
fileInputProps,
placeHolderWrapper,
previewImageWrapperProps,
@@ -60,7 +65,7 @@ export default function ImageUpload({
onChange={(e) => {
imageInputToBase64({ imageInput: e.target }).then((res) => {
setSrc(res.imageBase64Full);
onChange?.(res);
onChangeHandler?.(res);
fileInputProps?.onChange?.(e);
});
}}
@@ -88,7 +93,7 @@ export default function ImageUpload({
className="absolute p-2 top-2 right-2 z-20"
onClick={(e) => {
setSrc(undefined);
onChange?.(undefined);
onChangeHandler?.(undefined);
}}
>
<X className="text-slate-950 dark:text-white" />
+18 -3
View File
@@ -107,6 +107,7 @@ export type InputProps<KeyType extends string> = DetailedHTMLProps<
validationFunction?: (value: string) => Promise<boolean>;
autoComplete?: (typeof autocompleteOptions)[number];
name?: KeyType;
valueUpdate?: string;
};
/**
@@ -130,11 +131,16 @@ export default function Input<KeyType extends string>({
autoComplete,
validationFunction,
validationRegex,
valueUpdate,
...props
}: InputProps<KeyType>) {
const [focus, setFocus] = React.useState(false);
const [value, setValue] = React.useState(
props.defaultValue ? String(props.defaultValue) : ""
props.value
? String(props.value)
: props.defaultValue
? String(props.defaultValue)
: ""
);
delete props.defaultValue;
@@ -163,6 +169,11 @@ export default function Input<KeyType extends string>({
}
}, [value]);
React.useEffect(() => {
if (!props.value) return;
setValue(String(props.value));
}, [props.value]);
const targetComponent = istextarea ? (
<textarea
{...props}
@@ -189,7 +200,10 @@ export default function Input<KeyType extends string>({
<input
{...props}
className={twMerge(
"w-full outline-none bg-transparent",
"w-full outline-none bg-transparent border-none",
"hover:border-none hover:outline-none focus:border-none focus:outline-none",
"dark:bg-transparent dark:outline-none dark:border-none",
"p-0",
"twui-input",
props.className
)}
@@ -220,7 +234,7 @@ export default function Input<KeyType extends string>({
: "border-slate-300 dark:border-white/20",
focus && isValid
? "outline-slate-700 dark:outline-white/50"
: "outline-transparent",
: "outline-slate-300 dark:outline-white/20",
variant == "warning" &&
isValid &&
"border-yellow-500 dark:border-yellow-300 outline-yellow-500 dark:outline-yellow-300",
@@ -246,6 +260,7 @@ export default function Input<KeyType extends string>({
className={twMerge(
"text-xs absolute -top-2.5 left-2 text-slate-500 bg-white px-1.5 rounded-t",
"dark:text-white/60 dark:bg-black",
"twui-input-label",
labelProps?.className
)}
>
+29 -20
View File
@@ -16,24 +16,7 @@ type SelectOptionObject = {
default?: boolean;
};
type SelectOption = SelectOptionObject | SelectOptionObject[];
/**
* # Select Element
* @className twui-select-wrapper
* @className twui-select
* @className twui-select-dropdown-icon
*/
export default function Select({
label,
options,
componentRef,
labelProps,
wrapperProps,
showLabel,
iconProps,
...props
}: DetailedHTMLProps<
type SelectProps = DetailedHTMLProps<
SelectHTMLAttributes<HTMLSelectElement>,
HTMLSelectElement
> & {
@@ -50,7 +33,26 @@ export default function Select({
>;
componentRef?: RefObject<HTMLSelectElement>;
iconProps?: LucideProps;
}) {
changeHandler?: (value: SelectProps["options"][number]["value"]) => void;
};
/**
* # Select Element
* @className twui-select-wrapper
* @className twui-select
* @className twui-select-dropdown-icon
*/
export default function Select({
label,
options,
componentRef,
labelProps,
wrapperProps,
showLabel,
iconProps,
changeHandler,
...props
}: SelectProps) {
return (
<div
{...wrapperProps}
@@ -64,8 +66,9 @@ export default function Select({
htmlFor={props.name}
{...labelProps}
className={twMerge(
"text-xs absolute -top-2 left-4 text-slate-600 bg-white px-2",
"text-xs absolute -top-2.5 left-2 text-slate-500 bg-white px-1.5 rounded-t",
"dark:text-white/60 dark:bg-black",
"twui-input-label",
labelProps?.className
)}
>
@@ -90,6 +93,12 @@ export default function Select({
options.flat().find((opt) => opt.default)?.value ||
undefined
}
onChange={(e) => {
changeHandler?.(
e.target.value as (typeof options)[number]["value"]
);
props.onChange?.(e);
}}
>
{options.flat().map((option, index) => {
return (