We wanted to remove daisyui a long time ago Since renovate updates broke all of the classes somehow we use the opportunity to remove daisyui And will fix all the breakages continously as we work on the features
101 lines
3.1 KiB
TypeScript
101 lines
3.1 KiB
TypeScript
import cx from "classnames";
|
|
import { createMemo, JSX, Show, splitProps } from "solid-js";
|
|
|
|
interface FileInputProps {
|
|
ref: (element: HTMLInputElement) => void;
|
|
name: string;
|
|
value?: File[] | File;
|
|
onInput: JSX.EventHandler<HTMLInputElement, InputEvent>;
|
|
onClick: JSX.EventHandler<HTMLInputElement, Event>;
|
|
onChange: JSX.EventHandler<HTMLInputElement, Event>;
|
|
onBlur: JSX.EventHandler<HTMLInputElement, FocusEvent>;
|
|
accept?: string;
|
|
required?: boolean;
|
|
multiple?: boolean;
|
|
class?: string;
|
|
label?: string;
|
|
error?: string;
|
|
helperText?: string;
|
|
placeholder?: JSX.Element;
|
|
}
|
|
|
|
/**
|
|
* File input field that users can click or drag files into. Various
|
|
* decorations can be displayed in or around the field to communicate the entry
|
|
* requirements.
|
|
*/
|
|
export function FileInput(props: FileInputProps) {
|
|
// Split input element props
|
|
const [, inputProps] = splitProps(props, [
|
|
"class",
|
|
"value",
|
|
"label",
|
|
"error",
|
|
"placeholder",
|
|
]);
|
|
|
|
// Create file list
|
|
const getFiles = createMemo(() =>
|
|
props.value
|
|
? Array.isArray(props.value)
|
|
? props.value
|
|
: [props.value]
|
|
: [],
|
|
);
|
|
|
|
return (
|
|
<div class={cx(" w-full", props.class)}>
|
|
<div class="">
|
|
<span
|
|
class=" block"
|
|
classList={{
|
|
"after:ml-0.5 after:text-primary after:content-['*']":
|
|
props.required,
|
|
}}
|
|
>
|
|
{props.label}
|
|
</span>
|
|
</div>
|
|
<Show when={props.helperText}>
|
|
<span class=" m-1">{props.helperText}</span>
|
|
</Show>
|
|
<div
|
|
class={cx(
|
|
"relative flex min-h-[96px] w-full items-center justify-center rounded-2xl border-[3px] border-dashed p-8 text-center focus-within:ring-4 md:min-h-[112px] md:text-lg lg:min-h-[128px] lg:p-10 lg:text-xl",
|
|
!getFiles().length && "text-slate-500",
|
|
props.error
|
|
? "border-red-500/25 focus-within:border-red-500/50 focus-within:ring-red-500/10 hover:border-red-500/40 dark:border-red-400/25 dark:focus-within:border-red-400/50 dark:focus-within:ring-red-400/10 dark:hover:border-red-400/40"
|
|
: "border-slate-200 focus-within:border-sky-500/50 focus-within:ring-sky-500/10 hover:border-slate-300 dark:border-slate-800 dark:focus-within:border-sky-400/50 dark:focus-within:ring-sky-400/10 dark:hover:border-slate-700",
|
|
)}
|
|
>
|
|
<Show
|
|
when={getFiles().length}
|
|
fallback={
|
|
props.placeholder || (
|
|
<>Click to select file{props.multiple && "s"}</>
|
|
)
|
|
}
|
|
>
|
|
Selected file{props.multiple && "s"}:{" "}
|
|
{getFiles()
|
|
.map(({ name }) => name)
|
|
.join(", ")}
|
|
</Show>
|
|
<input
|
|
{...inputProps}
|
|
// Disable drag n drop
|
|
onDrop={(e) => e.preventDefault()}
|
|
class="absolute size-full cursor-pointer opacity-0"
|
|
type="file"
|
|
id={props.name}
|
|
aria-invalid={!!props.error}
|
|
aria-errormessage={`${props.name}-error`}
|
|
/>
|
|
{props.error && (
|
|
<span class=" font-bold text-error-700">{props.error}</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|