refactor: add new editable text component which allow to change group title
This commit is contained in:
parent
946ecaf9f9
commit
e323e104e0
@ -1,38 +1,46 @@
|
||||
import { Input } from 'antd';
|
||||
import clsx from 'clsx';
|
||||
import React, { useState } from 'react';
|
||||
import { useWatch } from '../hooks/useWatch';
|
||||
import { Input } from './ui/input';
|
||||
import { useEvent } from '@/hooks/useEvent';
|
||||
import { cn } from '@/utils/style';
|
||||
|
||||
interface EditableTextProps {
|
||||
className?: string;
|
||||
enable?: boolean;
|
||||
defaultValue: string;
|
||||
onSave: (text: string) => void;
|
||||
}
|
||||
export const EditableText: React.FC<EditableTextProps> = React.memo((props) => {
|
||||
const [text, setText] = useState(props.defaultValue);
|
||||
const enable = props.enable ?? true;
|
||||
const [editing, setEditing] = useState(false);
|
||||
const inputRef = React.useRef<HTMLInputElement>(null);
|
||||
|
||||
useWatch([props.defaultValue], () => {
|
||||
setText(props.defaultValue);
|
||||
});
|
||||
|
||||
const handleClick = useEvent(() => {
|
||||
setEditing(true);
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{enable ? (
|
||||
<div className={cn('cursor-text', props.className)}>
|
||||
{editing ? (
|
||||
<Input
|
||||
className={clsx(
|
||||
props.className,
|
||||
'rounded-none border-0 p-0 !shadow-none outline-0'
|
||||
)}
|
||||
ref={inputRef}
|
||||
autoFocus={true}
|
||||
type="text"
|
||||
className="h-[1.5em] border-none p-0 text-base shadow-none focus-visible:ring-0"
|
||||
value={text}
|
||||
onChange={(e) => setText(e.target.value)}
|
||||
onBlur={(e) => props.onSave(e.target.value)}
|
||||
onBlur={() => {
|
||||
setEditing(false);
|
||||
props.onSave(text);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<span className={props.className}>{text}</span>
|
||||
<span onClick={handleClick}>{text}</span>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
EditableText.displayName = 'EditableText';
|
||||
|
@ -12,6 +12,7 @@ import { Separator } from '@/components/ui/separator';
|
||||
import { MonitorPicker } from '../MonitorPicker';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { set } from 'lodash-es';
|
||||
import { EditableText } from '@/components/EditableText';
|
||||
|
||||
export const leafItemSchema = z.object({
|
||||
key: z.string(),
|
||||
@ -90,6 +91,24 @@ export const MonitorStatusPageServiceList: React.FC<MonitorStatusPageServiceList
|
||||
props.onChange(newList);
|
||||
});
|
||||
|
||||
const handleChangeGroupTitle = useEvent(
|
||||
(groupKey: string, title: string) => {
|
||||
const index = props.value.findIndex((item) => item.key === groupKey);
|
||||
if (index === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newList = [...props.value];
|
||||
if (!('children' in newList[index])) {
|
||||
return;
|
||||
}
|
||||
|
||||
newList[index].title = title;
|
||||
|
||||
props.onChange(newList);
|
||||
}
|
||||
);
|
||||
|
||||
const handleDeleteItem = useEvent((groupKey: string, itemKey: string) => {
|
||||
const newList = [...props.value];
|
||||
const groupIndex = newList.findIndex((item) => item.key === groupKey);
|
||||
@ -145,31 +164,34 @@ export const MonitorStatusPageServiceList: React.FC<MonitorStatusPageServiceList
|
||||
onChange={props.onChange}
|
||||
renderGroup={(group, children, level) => (
|
||||
<div>
|
||||
<div className={cn('flex items-center gap-2')}>
|
||||
<span>{group.title}</span>
|
||||
{level > 0 && (
|
||||
<div className={cn('flex items-center gap-2')}>
|
||||
<EditableText
|
||||
className="flex-1 overflow-hidden text-ellipsis text-nowrap"
|
||||
defaultValue={group.title}
|
||||
onSave={(text) => handleChangeGroupTitle(group.key, text)}
|
||||
/>
|
||||
|
||||
{level > 0 && (
|
||||
<>
|
||||
<Button
|
||||
className="h-6 w-6"
|
||||
variant="outline"
|
||||
size="icon"
|
||||
type="button"
|
||||
Icon={LuPlusCircle}
|
||||
onClick={() => handleAddItem(group.key)}
|
||||
/>
|
||||
<Button
|
||||
className="h-6 w-6"
|
||||
variant="outline"
|
||||
size="icon"
|
||||
type="button"
|
||||
Icon={LuPlusCircle}
|
||||
onClick={() => handleAddItem(group.key)}
|
||||
/>
|
||||
|
||||
<Button
|
||||
className="h-6 w-6"
|
||||
variant="outline"
|
||||
size="icon"
|
||||
type="button"
|
||||
Icon={LuTrash}
|
||||
onClick={() => handleDeleteGroup(group.key)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Button
|
||||
className="h-6 w-6"
|
||||
variant="outline"
|
||||
size="icon"
|
||||
type="button"
|
||||
Icon={LuTrash}
|
||||
onClick={() => handleDeleteGroup(group.key)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={cn(level > 0 && 'border-l-4 border-gray-600 p-2')}
|
||||
>
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
MonitorStatusPageServiceList,
|
||||
} from '@/components/monitor/StatusPage/ServiceList';
|
||||
import { useState } from 'react';
|
||||
import { EditableText } from '@/components/EditableText';
|
||||
|
||||
export const Route = createFileRoute('/playground')({
|
||||
beforeLoad: () => {
|
||||
@ -45,6 +46,11 @@ function PageComponent() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<EditableText
|
||||
defaultValue="fooooooooo"
|
||||
onSave={() => console.log('save')}
|
||||
/>
|
||||
|
||||
<MonitorStatusPageServiceList value={list} onChange={setList} />
|
||||
</div>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user