MCPcopy Index your code
hub / github.com/srcbookdev/srcbook / EditableH1

Function EditableH1

packages/components/src/components/ui/heading.tsx:18–99  ·  view source on GitHub ↗
(props: {
  text: string;
  className?: string;
  onUpdated: (text: string) => void;
})

Source from the content-addressed store, hash-verified

16}
17
18export function EditableH1(props: {
19 text: string;
20 className?: string;
21 onUpdated: (text: string) => void;
22}) {
23 const ref = useRef<HTMLHeadingElement>(null);
24 const timeoutRef = useRef<number | null>(null);
25
26 const [error, _setError] = useState<string | null>(null);
27
28 function clearError() {
29 _setError(null);
30 if (timeoutRef.current) {
31 clearTimeout(timeoutRef.current);
32 }
33 }
34
35 function setError(error: string) {
36 if (timeoutRef.current) {
37 clearTimeout(timeoutRef.current);
38 }
39 _setError(error);
40 timeoutRef.current = setTimeout(() => {
41 _setError(null);
42 }, 3000) as unknown as number;
43 }
44
45 return (
46 <div>
47 <h1
48 // eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role -- messy fix should be reworked
49 role="textbox"
50 aria-multiline="true"
51 tabIndex={0}
52 className={cn(className, props.className)}
53 ref={ref}
54 contentEditable
55 suppressContentEditableWarning={true}
56 onBlur={(e) => {
57 const result = TitleCellUpdateAttrsSchema.safeParse({ text: e.currentTarget.innerHTML });
58
59 if (result.success) {
60 props.onUpdated(result.data.text);
61 } else {
62 setError(result.error.errors[0]?.message ?? 'Unknown error');
63 if (ref.current) {
64 ref.current.innerText = props.text;
65 }
66 }
67 }}
68 onKeyDown={(e) => {
69 if (!ref.current) {
70 return;
71 }
72
73 if (isCharacterKey(e)) {
74 const result = TitleCellUpdateAttrsSchema.safeParse({
75 text: ref.current.innerText + e.key,

Callers

nothing calls this directly

Calls 4

setErrorFunction · 0.70
isCharacterKeyFunction · 0.70
clearErrorFunction · 0.70
cnFunction · 0.50

Tested by

no test coverage detected