fix: add styleField prop to Field and TypeTag components for flexible styling options
This commit is contained in:
parent
e6bd6ec210
commit
b718aa3227
|
|
@ -70,6 +70,7 @@ export interface FieldProps {
|
||||||
autoRefresh?: boolean;
|
autoRefresh?: boolean;
|
||||||
forceDisabled?: boolean;
|
forceDisabled?: boolean;
|
||||||
description?: string | (() => any);
|
description?: string | (() => any);
|
||||||
|
styleField?: string | null;
|
||||||
}
|
}
|
||||||
export const Field: React.FC<FieldProps> = ({
|
export const Field: React.FC<FieldProps> = ({
|
||||||
fm,
|
fm,
|
||||||
|
|
@ -103,6 +104,7 @@ export const Field: React.FC<FieldProps> = ({
|
||||||
autoRefresh = false,
|
autoRefresh = false,
|
||||||
forceDisabled,
|
forceDisabled,
|
||||||
description,
|
description,
|
||||||
|
styleField,
|
||||||
}) => {
|
}) => {
|
||||||
let result = null;
|
let result = null;
|
||||||
const field = useLocal({
|
const field = useLocal({
|
||||||
|
|
@ -458,6 +460,7 @@ export const Field: React.FC<FieldProps> = ({
|
||||||
) : ["tag"].includes(type) ? (
|
) : ["tag"].includes(type) ? (
|
||||||
<>
|
<>
|
||||||
<TypeTag
|
<TypeTag
|
||||||
|
styleField={styleField}
|
||||||
fm={fm}
|
fm={fm}
|
||||||
fields={initField}
|
fields={initField}
|
||||||
name={name}
|
name={name}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
import { useRef, useState } from "react";
|
import { cva } from "class-variance-authority";
|
||||||
|
import { useRef, useState, useEffect } from "react";
|
||||||
|
import { Checkbox } from "../../ui/checkbox";
|
||||||
|
import { X } from "lucide-react";
|
||||||
|
import { IoIosRadioButtonOff } from "react-icons/io";
|
||||||
|
|
||||||
export const TypeTag: React.FC<any> = ({
|
export const TypeTag: React.FC<any> = ({
|
||||||
name,
|
name,
|
||||||
|
|
@ -9,6 +13,7 @@ export const TypeTag: React.FC<any> = ({
|
||||||
type,
|
type,
|
||||||
field,
|
field,
|
||||||
onChange,
|
onChange,
|
||||||
|
styleField,
|
||||||
}) => {
|
}) => {
|
||||||
const [tags, setTags] = useState<string[]>(fm.data?.[name] || []);
|
const [tags, setTags] = useState<string[]>(fm.data?.[name] || []);
|
||||||
const [inputValue, setInputValue] = useState("");
|
const [inputValue, setInputValue] = useState("");
|
||||||
|
|
@ -16,8 +21,15 @@ export const TypeTag: React.FC<any> = ({
|
||||||
const [tempValue, setTempValue] = useState<string>(""); // Nilai sementara untuk pengeditan
|
const [tempValue, setTempValue] = useState<string>(""); // Nilai sementara untuk pengeditan
|
||||||
const tagRefs = useRef<(HTMLDivElement | null)[]>([]);
|
const tagRefs = useRef<(HTMLDivElement | null)[]>([]);
|
||||||
const val = fm?.data?.[name];
|
const val = fm?.data?.[name];
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (editingIndex !== null && tagRefs.current[editingIndex]) {
|
||||||
|
tagRefs.current[editingIndex]?.focus();
|
||||||
|
}
|
||||||
|
}, [editingIndex]);
|
||||||
|
|
||||||
const handleSaveEdit = (index: number) => {
|
const handleSaveEdit = (index: number) => {
|
||||||
if (!disabled) return;
|
if (disabled) return;
|
||||||
const updatedTags = [...tags];
|
const updatedTags = [...tags];
|
||||||
updatedTags[index] = tempValue.trim(); // Update nilai tag
|
updatedTags[index] = tempValue.trim(); // Update nilai tag
|
||||||
setTags(updatedTags);
|
setTags(updatedTags);
|
||||||
|
|
@ -30,6 +42,7 @@ export const TypeTag: React.FC<any> = ({
|
||||||
onChange(tags);
|
onChange(tags);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
@ -50,44 +63,88 @@ export const TypeTag: React.FC<any> = ({
|
||||||
setTags(tags.slice(0, -1));
|
setTags(tags.slice(0, -1));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFocusTag = (index: number) => {
|
const handleFocusTag = (index: number) => {
|
||||||
if (disabled) return;
|
if (disabled) return;
|
||||||
setEditingIndex(index); // Masuk ke mode edit
|
setEditingIndex(index); // Masuk ke mode edit
|
||||||
setTempValue(tags[index]); // Isi nilai sementara dengan nilai tag
|
setTempValue(tags[index]); // Isi nilai sementara dengan nilai tag
|
||||||
setTimeout(() => {
|
|
||||||
tagRefs.current[index]?.focus(); // Fokus pada elemen yang diedit
|
|
||||||
}, 0);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeTag = (index: number) => {
|
const removeTag = (index: number) => {
|
||||||
if (disabled) return;
|
if (disabled) return;
|
||||||
setTags(tags.filter((_, i) => i !== index));
|
setTags(tags.filter((_, i) => i !== index));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const buttonVariants = cva(
|
||||||
|
"flex flex-row items-center rounded-full text-sm p-1",
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: "bg-blue-100 text-blue-800 m-1",
|
||||||
|
moe: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const stylingGroup = ["checkbox", "radio", "order"];
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cx(
|
className={cx(
|
||||||
"flex flex-wrap items-center rounded-md flex-grow ",
|
"flex rounded-md flex-grow ",
|
||||||
|
stylingGroup.includes(styleField)
|
||||||
|
? "flex-wrap flex-col"
|
||||||
|
: "items-center flex-wrap",
|
||||||
disabled && !tags?.length ? "h-9" : ""
|
disabled && !tags?.length ? "h-9" : ""
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{tags.map((tag, index) => (
|
{tags.map((tag, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className="flex flex-row items-center bg-blue-100 text-blue-800 rounded-full m-1 text-sm"
|
className={cx(
|
||||||
|
buttonVariants({ variant: styleField ? styleField : "default" }),
|
||||||
|
editingIndex === index
|
||||||
|
? styleField
|
||||||
|
? "border-b border-gray-500 rounded-none"
|
||||||
|
: "bg-transparent border border-gray-500 rounded-full text-gray-900"
|
||||||
|
: ""
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
|
{styleField === "checkbox" ? (
|
||||||
|
<>
|
||||||
|
<Checkbox
|
||||||
|
className="border border-primary"
|
||||||
|
checked={false}
|
||||||
|
onClick={(e) => {}}
|
||||||
|
/>{" "}
|
||||||
|
</>
|
||||||
|
) : styleField === "radio" ? (
|
||||||
|
<>
|
||||||
|
<IoIosRadioButtonOff />{" "}
|
||||||
|
</>
|
||||||
|
) : styleField === "order" ? (
|
||||||
|
<>
|
||||||
|
{index + 1}
|
||||||
|
{". "}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
{disabled ? (
|
{disabled ? (
|
||||||
<div className="px-2">{tag}</div>
|
<div className="px-2">{tag}</div>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
|
ref={(el) => {
|
||||||
|
if (el) tagRefs.current[index] = el;
|
||||||
|
}}
|
||||||
className={cx(
|
className={cx(
|
||||||
"px-3 py-1 pr-0 flex-grow focus:shadow-none focus:ring-0 focus:border-none focus:outline-none",
|
"px-3 py-1 pr-0 flex-grow focus:shadow-none focus:ring-0 focus:border-none focus:outline-none",
|
||||||
editingIndex! !== index && "cursor-pointer"
|
editingIndex !== index && "cursor-pointer"
|
||||||
)}
|
)}
|
||||||
contentEditable={editingIndex === index}
|
contentEditable={editingIndex === index}
|
||||||
suppressContentEditableWarning
|
suppressContentEditableWarning
|
||||||
onBlur={() => handleSaveEdit(index)}
|
onBlur={() => handleSaveEdit(index)}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (!disabled) return;
|
if (disabled) return;
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
@ -97,9 +154,7 @@ export const TypeTag: React.FC<any> = ({
|
||||||
setEditingIndex(null);
|
setEditingIndex(null);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => handleFocusTag(index)}
|
||||||
handleFocusTag(index);
|
|
||||||
}}
|
|
||||||
onInput={(e) =>
|
onInput={(e) =>
|
||||||
setTempValue((e.target as HTMLDivElement).innerText)
|
setTempValue((e.target as HTMLDivElement).innerText)
|
||||||
}
|
}
|
||||||
|
|
@ -112,9 +167,9 @@ export const TypeTag: React.FC<any> = ({
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => removeTag(index)}
|
onClick={() => removeTag(index)}
|
||||||
className="ml-2 text-blue-500 hover:text-blue-700 pr-2"
|
className="ml-2 text-red-500 pr-2"
|
||||||
>
|
>
|
||||||
×
|
<X size={16} />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue