prepare editable content component.

This commit is contained in:
Vixalie 2025-03-09 22:14:05 +08:00
parent de1275e2d8
commit 32d6e0c875
2 changed files with 78 additions and 0 deletions

View File

@ -0,0 +1,17 @@
@layer components {
.editable_layout {
width: 100%;
min-width: 0;
display: flex;
flex-direction: row;
align-items: center;
gap: calc(var(--spacing) * 2);
line-height: 1.3em;
input {
flex: 1 0;
}
.placeholder {
color: color-mix(in oklch, var(--color-on-surface) 38%, transparent);
}
}
}

View File

@ -0,0 +1,61 @@
import { Icon } from '@iconify/react/dist/iconify.js';
import cx from 'clsx';
import { FC, ReactHTMLElement, useCallback, useRef, useState } from 'react';
import styles from './EditableContent.module.css';
type EditableContentProps = {
as?: keyof ReactHTMLElement;
value?: string | null;
onChange?: (value: string) => void;
placeholder?: string;
additionalClassName?: HTMLElement['className'];
};
const EditableContent: FC<EditableContentProps> = ({
as: Tag,
value,
onChange,
placeholder,
additionalClassName,
}) => {
const [isEditing, setEditing] = useState(false);
const formRef = useRef<HTMLFormElement | null>(null);
const cancelEdit = useCallback(() => {
setEditing(false);
formRef.current?.reset();
}, []);
const handleSubmit = useCallback(
(data: FormData) => {
const newValue = data.get('value') as string;
if (newValue.length > 0 && newValue !== value) {
onChange?.(newValue);
}
cancelEdit();
},
[value],
);
return isEditing ? (
<form
className={cx(styles.editable_layout, additionalClassName)}
action={handleSubmit}
ref={formRef}>
<input type="text" name="value" defaultValue={value} placeholder={placeholder} />
<button type="submit" className="icon">
<Icon icon="material-symbols-light:check" />
</button>
<button type="button" className="icon" onClick={cancelEdit}>
<Icon icon="material-symbols-light:close" />
</button>
</form>
) : (
<div className={cx(styles.editable_layout, additionalClassName)}>
<Tag>{value ?? <span className={styles.placeholder}>{placeholder}</span>}</Tag>
<button onClick={() => setEditing(true)} className="icon">
<Icon icon="material-symbols-light:edit-square-outline" />
</button>
</div>
);
};
export default EditableContent;