Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/components/ui/input/InputImage.tsx
T

155 lines
5.6 KiB
TypeScript

import { forwardRef, Ref, RefObject, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import InputText from "./InputText";
import UploadDocument from "../uploaders/UploadDocument";
import clsx from "clsx";
import { sanitizeIconSvg } from "~/utils/html-sanitizer";
import { XIcon } from "~/components/ui/icons/vendor";
export interface RefInputImage {
input: RefObject<HTMLInputElement> | RefObject<HTMLTextAreaElement>;
}
type WithDefaultValue = { defaultValue: string | undefined };
type WithValueAndSetValue = { value: string | undefined; setValue: React.Dispatch<React.SetStateAction<string>> };
type Props = (WithDefaultValue | WithValueAndSetValue) & {
name?: string;
title?: string;
disabled?: boolean;
size?: "small" | "medium" | "large";
square?: boolean;
required?: boolean;
hint?: React.ReactNode;
accept?: string;
placeholder?: string;
opened?: boolean;
description?: string;
className?: string;
};
const InputImage = (props: Props, ref: Ref<RefInputImage>) => {
const value = "value" in props ? props.value : undefined;
const setValue = "setValue" in props ? props.setValue : undefined;
const defaultValue = "defaultValue" in props ? props.defaultValue : undefined;
const size = props.size ?? "large";
const square = props.square ?? false;
const { t } = useTranslation();
const [showUploadImage, setShowUploadImage] = useState((props.opened && (!value || defaultValue)) ?? false);
const [image, setImage] = useState(value || defaultValue || "");
useEffect(() => {
if (setValue && value !== image) {
setValue(image);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [image]);
const imageClassName = clsx(
"mx-auto",
square ? "object-cover" : "object-contain",
size === "small" && "h-8",
size === "medium" && "h-16",
size === "large" && "h-32",
square && clsx(size === "small" && "w-8", size === "medium" && "w-16", size === "large" && "w-32")
);
return (
<div className={clsx("space-y-1", props.className)}>
<input name={props.name} type="hidden" value={image} readOnly hidden />
<label htmlFor={props.name} className="flex items-baseline justify-between space-x-2 truncate text-xs font-medium">
<div className="flex shrink-0 items-center space-x-1 truncate">
<div className="flex space-x-1 truncate">
<div className="truncate">{props.title}</div>
{props.required && props.title && <div className="ml-1 text-red-600">*</div>}
</div>
</div>
{props.hint && <div>{props.hint}</div>}
</label>
{/* {!showUploadImage && ( */}
<InputText
name={props.name}
required={props.required}
value={image}
setValue={setImage}
readOnly={image.startsWith("data:image")}
placeholder={props.placeholder ?? t("components.input.image.urlPlaceholder")}
withLabel={false}
button={
<div className="absolute inset-y-0 right-0 flex py-1.5 pr-1.5 ">
<div className="border-border-default text-text-neutral-tertiary bg-surface-neutral-primary inline-flex items-center rounded border px-2 font-sans text-sm font-medium">
{!image ? (
<button type="button" onClick={() => setShowUploadImage(true)}>
{t("shared.upload")}
</button>
) : (
<button
type="button"
disabled={props.disabled}
onClick={() => {
setImage("");
setShowUploadImage(true);
}}
>
{t("shared.remove")}
</button>
)}
</div>
</div>
}
/>
{/* )} */}
{showUploadImage && (
<UploadDocument
name={props.name + "-file"}
disabled={props.disabled}
className="col-span-12"
accept={props.accept || "image/png, image/jpg, image/jpeg"}
// description={t("models.post.image")}
description={props.description}
onDropped={(e) => {
setImage(e);
setShowUploadImage(false);
}}
/>
)}
{!showUploadImage && image && (
<div className="col-span-12">
<div
className={clsx(
"bg-surface-neutral-primary border-border-default relative overflow-hidden rounded-lg border",
!square && "p-4",
square && size === "small" && "w-8",
square && size === "medium" && "w-16",
square && size === "large" && "w-32"
)}
>
{/* <button
type="button"
className="absolute inset-0 transition-colors duration-200"
onClick={() => setShowUploadImage(true)}
>
<div className="flex h-full items-center justify-center text-sm font-medium text-white">{t("shared.upload")}</div>
</button> */}
<button
type="button"
className="absolute right-0 top-0 bg-black/50 p-1 transition-colors duration-200 hover:bg-black/75"
onClick={() => setImage("")}
>
<XIcon className="h-4 w-4 text-white" />
</button>
{image.startsWith("<svg") ? (
<div dangerouslySetInnerHTML={{ __html: sanitizeIconSvg(image, imageClassName) }} />
) : (
<img className={imageClassName} src={image} alt={props.title} />
)}
</div>
</div>
)}
</div>
);
};
export default forwardRef(InputImage);