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 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';
|
||||||
|
@ -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,31 +164,34 @@ 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')}>
|
{level > 0 && (
|
||||||
<span>{group.title}</span>
|
<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"
|
||||||
<Button
|
variant="outline"
|
||||||
className="h-6 w-6"
|
size="icon"
|
||||||
variant="outline"
|
type="button"
|
||||||
size="icon"
|
Icon={LuPlusCircle}
|
||||||
type="button"
|
onClick={() => handleAddItem(group.key)}
|
||||||
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
|
<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')}
|
||||||
>
|
>
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user