refactor: add new editable text component which allow to change group title

This commit is contained in:
moonrailgun 2024-09-16 21:50:22 +08:00
parent 946ecaf9f9
commit e323e104e0
3 changed files with 72 additions and 36 deletions

View File

@ -1,38 +1,46 @@
import { Input } from 'antd';
import clsx from 'clsx';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useWatch } from '../hooks/useWatch'; import { useWatch } from '../hooks/useWatch';
import { Input } from './ui/input';
import { useEvent } from '@/hooks/useEvent';
import { cn } from '@/utils/style';
interface EditableTextProps { interface EditableTextProps {
className?: string; className?: string;
enable?: boolean;
defaultValue: string; defaultValue: string;
onSave: (text: string) => void; onSave: (text: string) => void;
} }
export const EditableText: React.FC<EditableTextProps> = React.memo((props) => { export const EditableText: React.FC<EditableTextProps> = React.memo((props) => {
const [text, setText] = useState(props.defaultValue); 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], () => { useWatch([props.defaultValue], () => {
setText(props.defaultValue); setText(props.defaultValue);
}); });
const handleClick = useEvent(() => {
setEditing(true);
});
return ( return (
<> <div className={cn('cursor-text', props.className)}>
{enable ? ( {editing ? (
<Input <Input
className={clsx( ref={inputRef}
props.className, autoFocus={true}
'rounded-none border-0 p-0 !shadow-none outline-0' type="text"
)} className="h-[1.5em] border-none p-0 text-base shadow-none focus-visible:ring-0"
value={text} value={text}
onChange={(e) => setText(e.target.value)} 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'; EditableText.displayName = 'EditableText';

View File

@ -12,6 +12,7 @@ import { Separator } from '@/components/ui/separator';
import { MonitorPicker } from '../MonitorPicker'; import { MonitorPicker } from '../MonitorPicker';
import { Switch } from '@/components/ui/switch'; import { Switch } from '@/components/ui/switch';
import { set } from 'lodash-es'; import { set } from 'lodash-es';
import { EditableText } from '@/components/EditableText';
export const leafItemSchema = z.object({ export const leafItemSchema = z.object({
key: z.string(), key: z.string(),
@ -90,6 +91,24 @@ export const MonitorStatusPageServiceList: React.FC<MonitorStatusPageServiceList
props.onChange(newList); 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 handleDeleteItem = useEvent((groupKey: string, itemKey: string) => {
const newList = [...props.value]; const newList = [...props.value];
const groupIndex = newList.findIndex((item) => item.key === groupKey); const groupIndex = newList.findIndex((item) => item.key === groupKey);
@ -145,11 +164,14 @@ export const MonitorStatusPageServiceList: React.FC<MonitorStatusPageServiceList
onChange={props.onChange} onChange={props.onChange}
renderGroup={(group, children, level) => ( renderGroup={(group, children, level) => (
<div> <div>
<div className={cn('flex items-center gap-2')}>
<span>{group.title}</span>
{level > 0 && ( {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)}
/>
<Button <Button
className="h-6 w-6" className="h-6 w-6"
variant="outline" variant="outline"
@ -167,9 +189,9 @@ export const MonitorStatusPageServiceList: React.FC<MonitorStatusPageServiceList
Icon={LuTrash} Icon={LuTrash}
onClick={() => handleDeleteGroup(group.key)} onClick={() => handleDeleteGroup(group.key)}
/> />
</>
)}
</div> </div>
)}
<div <div
className={cn(level > 0 && 'border-l-4 border-gray-600 p-2')} className={cn(level > 0 && 'border-l-4 border-gray-600 p-2')}
> >

View File

@ -5,6 +5,7 @@ import {
MonitorStatusPageServiceList, MonitorStatusPageServiceList,
} from '@/components/monitor/StatusPage/ServiceList'; } from '@/components/monitor/StatusPage/ServiceList';
import { useState } from 'react'; import { useState } from 'react';
import { EditableText } from '@/components/EditableText';
export const Route = createFileRoute('/playground')({ export const Route = createFileRoute('/playground')({
beforeLoad: () => { beforeLoad: () => {
@ -45,6 +46,11 @@ function PageComponent() {
return ( return (
<div> <div>
<EditableText
defaultValue="fooooooooo"
onSave={() => console.log('save')}
/>
<MonitorStatusPageServiceList value={list} onChange={setList} /> <MonitorStatusPageServiceList value={list} onChange={setList} />
</div> </div>
); );