feat : improve extra section
This commit is contained in:
@@ -1,18 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
ArrowDownIcon,
|
||||
ArrowLeftIcon,
|
||||
ArrowRightIcon,
|
||||
ArrowUpIcon,
|
||||
Columns3Icon,
|
||||
GripHorizontalIcon,
|
||||
GripVerticalIcon,
|
||||
PlusIcon,
|
||||
PencilIcon,
|
||||
PaletteIcon,
|
||||
Redo2Icon,
|
||||
Rows3Icon,
|
||||
Trash2Icon,
|
||||
Undo2Icon,
|
||||
} from "lucide-react";
|
||||
@@ -57,23 +51,12 @@ import {
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Field, FieldGroup, FieldLabel } from "@/components/ui/field";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Kbd } from "@/components/ui/kbd";
|
||||
import {
|
||||
addExtraSheetColumn,
|
||||
addExtraSheetRow,
|
||||
deleteExtraSheetColumn,
|
||||
deleteExtraSheetRow,
|
||||
extraSheetToMatrix,
|
||||
matrixToExtraSheet,
|
||||
moveExtraSheetColumn,
|
||||
@@ -92,7 +75,6 @@ import {
|
||||
} from "@/lib/rich-text";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type DeleteTarget = "column" | "row" | null;
|
||||
interface SheetHistory {
|
||||
items: ExtraSheet[];
|
||||
index: number;
|
||||
@@ -132,20 +114,36 @@ function LiteralDataViewer({ cell }: { cell?: { value?: unknown; backgroundColor
|
||||
);
|
||||
}
|
||||
|
||||
function DialogDataEditor({
|
||||
function InlineDataEditor({
|
||||
cell,
|
||||
row,
|
||||
column,
|
||||
exitEditMode,
|
||||
onEdit,
|
||||
}: DataEditorProps<{ value: string }> & {
|
||||
onEdit: (point: Point, value: string) => void;
|
||||
}) {
|
||||
onChange,
|
||||
}: DataEditorProps<{ value: string }>) {
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const text = useMemo(() => {
|
||||
const document = new DOMParser().parseFromString(
|
||||
normalizeExtraRichText(String(cell?.value ?? "")),
|
||||
"text/html",
|
||||
);
|
||||
document.querySelectorAll("br").forEach((br) => br.replaceWith("\n"));
|
||||
document.querySelectorAll("p + p").forEach((p) => p.prepend("\n"));
|
||||
return document.body.textContent ?? "";
|
||||
}, [cell?.value]);
|
||||
useEffect(() => {
|
||||
onEdit({ row, column }, String(cell?.value ?? ""));
|
||||
exitEditMode();
|
||||
}, [cell?.value, column, exitEditMode, onEdit, row]);
|
||||
return <LiteralDataViewer cell={cell} />;
|
||||
const input = inputRef.current;
|
||||
input?.focus();
|
||||
input?.setSelectionRange(input.value.length, input.value.length);
|
||||
}, []);
|
||||
return (
|
||||
<div className="Spreadsheet__data-editor">
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
aria-label="แก้ไขข้อความเซลล์"
|
||||
value={text}
|
||||
onChange={(event) => onChange({ ...cell, value: event.target.value })}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function EditableColumnIndicator({
|
||||
@@ -244,7 +242,6 @@ export function ExtraSheetEditor({
|
||||
const [labelDialogOpen, setLabelDialogOpen] = useState(false);
|
||||
const [renaming, setRenaming] = useState(false);
|
||||
const [columnLabel, setColumnLabel] = useState("");
|
||||
const [deleteTarget, setDeleteTarget] = useState<DeleteTarget>(null);
|
||||
const [removeOpen, setRemoveOpen] = useState(false);
|
||||
const [cellDialogOpen, setCellDialogOpen] = useState(false);
|
||||
const [cellDraft, setCellDraft] = useState("");
|
||||
@@ -411,9 +408,6 @@ export function ExtraSheetEditor({
|
||||
const rowIndicator = useCallback((props: RowIndicatorProps) => (
|
||||
<SortableRowIndicator {...props} id={rowDragId(value.rows[props.row].id)} />
|
||||
), [value.rows]);
|
||||
const dataEditor = useCallback((props: DataEditorProps<{ value: string }>) => (
|
||||
<DialogDataEditor {...props} onEdit={openCellEditorAt} />
|
||||
), [openCellEditorAt]);
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -494,92 +488,27 @@ export function ExtraSheetEditor({
|
||||
>
|
||||
ล้างสีพื้นหลัง
|
||||
</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger
|
||||
render={<Button type="button" variant="outline" size="sm" />}
|
||||
>
|
||||
<Rows3Icon data-icon="inline-start" />
|
||||
แถว {active.row + 1}
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>จัดการแถว {active.row + 1}</DropdownMenuLabel>
|
||||
<DropdownMenuItem
|
||||
disabled={!activeRow || active.row === 0}
|
||||
onClick={() => {
|
||||
moveRow(active.row, active.row - 1);
|
||||
}}
|
||||
>
|
||||
<ArrowUpIcon />ย้ายขึ้น
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
disabled={!activeRow || active.row === value.rows.length - 1}
|
||||
onClick={() => {
|
||||
moveRow(active.row, active.row + 1);
|
||||
}}
|
||||
>
|
||||
<ArrowDownIcon />ย้ายลง
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem
|
||||
variant="destructive"
|
||||
disabled={value.rows.length === 1}
|
||||
onClick={() => setDeleteTarget("row")}
|
||||
>
|
||||
<Trash2Icon />ลบแถว
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger
|
||||
render={<Button type="button" variant="outline" size="sm" />}
|
||||
>
|
||||
<Columns3Icon data-icon="inline-start" />
|
||||
{activeColumn?.label ?? "คอลัมน์"}
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>{activeColumn?.label}</DropdownMenuLabel>
|
||||
<DropdownMenuItem onClick={() => openRenameColumn()}>แก้ไขชื่อ</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
disabled={!activeColumn || active.column === 0}
|
||||
onClick={() => {
|
||||
moveColumn(active.column, active.column - 1);
|
||||
}}
|
||||
>
|
||||
<ArrowLeftIcon />ย้ายไปทางซ้าย
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
disabled={!activeColumn || active.column === value.columns.length - 1}
|
||||
onClick={() => {
|
||||
moveColumn(active.column, active.column + 1);
|
||||
}}
|
||||
>
|
||||
<ArrowRightIcon />ย้ายไปทางขวา
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem
|
||||
variant="destructive"
|
||||
disabled={value.columns.length === 1}
|
||||
onClick={() => setDeleteTarget("column")}
|
||||
>
|
||||
<Trash2Icon />ลบคอลัมน์
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<Button type="button" variant="ghost" size="sm" onClick={() => setRemoveOpen(true)}>
|
||||
<Trash2Icon data-icon="inline-start" />
|
||||
ลบตาราง
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="overflow-x-auto rounded-lg border">
|
||||
<div
|
||||
className="overflow-x-auto rounded-lg border"
|
||||
onClickCapture={(event) => {
|
||||
if ((event.target as HTMLElement).closest(".Spreadsheet__active-cell--view")) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
}}
|
||||
onDoubleClickCapture={(event) => {
|
||||
if ((event.target as HTMLElement).closest(".Spreadsheet__cell, .Spreadsheet__active-cell")) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
openCellEditorAt(active);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DndContext
|
||||
sensors={sensors}
|
||||
collisionDetection={sameAxisCollision}
|
||||
@@ -594,7 +523,7 @@ export function ExtraSheetEditor({
|
||||
ColumnIndicator={columnIndicator}
|
||||
RowIndicator={rowIndicator}
|
||||
DataViewer={LiteralDataViewer}
|
||||
DataEditor={dataEditor}
|
||||
DataEditor={InlineDataEditor}
|
||||
onActivate={(point) => {
|
||||
setActive(point);
|
||||
setSelectedCount(1);
|
||||
@@ -682,23 +611,6 @@ export function ExtraSheetEditor({
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
<DeleteConfirmationDialog
|
||||
open={deleteTarget !== null}
|
||||
onOpenChange={(open) => { if (!open) setDeleteTarget(null); }}
|
||||
title={deleteTarget === "column" ? `ลบ ${activeColumn?.label}?` : `ลบแถว ${active.row + 1}?`}
|
||||
description="ข้อมูลในรายการนี้จะถูกลบออกจากตาราง"
|
||||
showSuccessToast={false}
|
||||
onConfirm={() => {
|
||||
if (deleteTarget === "column") {
|
||||
commitSheet(deleteExtraSheetColumn(value, active.column));
|
||||
activateOnly({ ...active, column: Math.max(0, active.column - 1) });
|
||||
} else if (deleteTarget === "row") {
|
||||
commitSheet(deleteExtraSheetRow(value, active.row));
|
||||
activateOnly({ ...active, row: Math.max(0, active.row - 1) });
|
||||
}
|
||||
setDeleteTarget(null);
|
||||
}}
|
||||
/>
|
||||
<DeleteConfirmationDialog
|
||||
open={removeOpen}
|
||||
onOpenChange={setRemoveOpen}
|
||||
|
||||
Reference in New Issue
Block a user