Skip to content

저장 훅

save 옵션은 "완료" 를 눌렀을 때 팝업 안에서 호출되는 훅이다. 서버에 올리고 문서에 넣을 주소를 돌려주는 자리이며, 실패를 조용히 넘기지 않는 것이 이 훅의 핵심 규칙이다.

계약

ts
save?: (png: Blob, data: Drawing) => Promise<string | void>;
설명
png방금 구운 PNG Blob
data도형이 살아 있는 Drawing JSON
반환 string문서에 넣을 주소 등. OpenResult.saved 에 그대로 실린다
반환 void저장은 했지만 돌려줄 값이 없음. savedundefined
throw저장 실패. 팝업은 닫히지 않는다(아래)
ts
const r = await openDrawing({
  background: file,
  save: async (png, data) => {
    const form = new FormData();
    form.append("png", png, "drawing.png");
    form.append("data", new Blob([JSON.stringify(data)], { type: "application/json" }), "drawing.json");
    const res = await fetch("/api/drawings", { method: "POST", body: form });
    if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
    return (await res.json()).url;
  },
});
if (r) img.src = r.saved!;

완료 시 순서

  1. 편집 중이던 글자가 있으면 확정한다.
  2. "완료" 버튼이 "저장 중…" 으로 바뀌고 비활성화된다. 이 동안 취소·그리기는 막힌다.
  3. renderToPng(data) 로 PNG 를 굽는다.
  4. save 가 있으면 await save(png, data).
  5. 팝업을 닫고 { data, png, saved } 를 돌려준다.

실패했을 때

3 또는 4 에서 예외가 나면:

  • window.alert 로 이유를 보인다. 메시지는 saveFailed(reason) — 기본 한국어는 "그림을 저장하지 못했습니다. 다시 시도하거나 취소하세요." 뒤에 Error.message 가 붙는다.
  • 팝업은 열린 채 그대로다. 그린 것은 남아 있다.
  • "완료" 버튼이 다시 살아나 재시도할 수 있고, 취소하면 null 이 돌아간다.
  • openDrawing 의 Promise 는 아직 끝나지 않은 상태다.

즉 훅이 던지면 호출자 쪽에서 별도 재시도 로직을 짤 필요가 없다. 사용자가 팝업 안에서 결정한다.

훅이 없을 때

save 를 주지 않으면 PNG 만 굽고 바로 닫는다. savedundefined. 저장은 호출자가 r.png·r.data 로 직접 한다.

재편집 흐름 — initial

data 를 곁파일로 저장해 두었다면 그것을 initial 로 넘겨 도형째 다시 연다.

ts
// 처음
const r1 = await openDrawing({ background: file, save });
await saveSidecar(r1.saved, r1.data);        // PNG 주소 옆에 JSON 을 둔다

// 나중에 그 그림을 고칠 때
const data = await loadSidecar(src);         // Drawing | null
const r2 = data
  ? await openDrawing({ initial: data, save })
  : await openDrawing({ background: src, save, notice: "도형 데이터 없이 PNG 만으로 열었습니다." });
  • initial 이 있으면 background 는 무시된다. 배경은 initial.background 에서 온다.
  • initial 은 안에서 복제(structuredClone)해 쓰므로 넘긴 객체는 바뀌지 않는다.
  • 곁파일을 잃었다면 PNG 를 background 로 열 수밖에 없다. 이전 도형은 배경에 박혀 있고 새 도형만 얹을 수 있다. notice 로 그 사실을 알려 주는 것이 @newtil/editor 의 방식이다.