@@ -6,6 +6,7 @@ import type { PatchOperation } from "../utils/sourcePatcher";
66import { trackStudioEvent } from "../utils/studioTelemetry" ;
77import { saveProjectFilesWithHistory } from "../utils/studioFileHistory" ;
88import { primaryFontFamilyValue } from "../utils/studioFontHelpers" ;
9+ import { createStudioSaveHttpError } from "../utils/studioSaveDiagnostics" ;
910import {
1011 buildDomEditPatchTarget ,
1112 getDomEditTargetKey ,
@@ -31,8 +32,10 @@ import {
3132import { fontFamilyFromAssetPath , type ImportedFontAsset } from "../components/editor/fontAssets" ;
3233import type { DomEditGroupPathOffsetCommit } from "../components/editor/DomEditOverlay" ;
3334import type { EditHistoryKind } from "../utils/editHistory" ;
35+ import { useDomEditPositionPatchCommit } from "./useDomEditPositionPatchCommit" ;
3436import { useDomEditTextCommits } from "./useDomEditTextCommits" ;
3537
38+ // ── Helpers ──
3639type TimelineLike = { getChildren ?: ( nested : boolean ) => Array < { targets ?: ( ) => Element [ ] } > } ;
3740
3841export const GSAP_CSS_FALLBACK_BLOCKED_MESSAGE =
@@ -69,6 +72,8 @@ function isElementGsapTargeted(iframe: HTMLIFrameElement | null, element: HTMLEl
6972 return false ;
7073}
7174
75+ // ── Types ──
76+
7277interface RecordEditInput {
7378 label : string ;
7479 kind : EditHistoryKind ;
@@ -102,6 +107,7 @@ export interface UseDomEditCommitsParams {
102107 projectIdRef : React . MutableRefObject < string | null > ;
103108 reloadPreview : ( ) => void ;
104109
110+ // From useDomSelection
105111 domEditSelection : DomEditSelection | null ;
106112 applyDomSelection : (
107113 selection : DomEditSelection | null ,
@@ -115,6 +121,8 @@ export interface UseDomEditCommitsParams {
115121 ) => Promise < DomEditSelection | null > ;
116122}
117123
124+ // ── Hook ──
125+
118126export function useDomEditCommits ( {
119127 activeCompPath,
120128 previewIframeRef,
@@ -172,7 +180,9 @@ export function useDomEditCommits({
172180 const readResponse = await fetch (
173181 `/api/projects/${ pid } /files/${ encodeURIComponent ( targetPath ) } ` ,
174182 ) ;
175- if ( ! readResponse . ok ) throw new Error ( `Failed to read ${ targetPath } ` ) ;
183+ if ( ! readResponse . ok ) {
184+ throw await createStudioSaveHttpError ( readResponse , `Failed to read ${ targetPath } ` ) ;
185+ }
176186 const readData = ( await readResponse . json ( ) ) as { content ?: string } ;
177187 const originalContent = readData . content ;
178188 if ( typeof originalContent !== "string" ) {
@@ -196,14 +206,15 @@ export function useDomEditCommits({
196206 body : JSON . stringify ( { target : patchTarget , operations } ) ,
197207 } ,
198208 ) ;
199- if ( ! patchResponse . ok ) throw new Error ( `Failed to patch ${ targetPath } ` ) ;
209+ if ( ! patchResponse . ok ) {
210+ throw await createStudioSaveHttpError ( patchResponse , `Failed to patch ${ targetPath } ` ) ;
211+ }
200212
201213 const patchData = ( await patchResponse . json ( ) ) as {
202214 ok ?: boolean ;
203215 changed ?: boolean ;
204216 matched ?: boolean ;
205217 content ?: string ;
206- path ?: string ;
207218 } ;
208219
209220 if ( ! patchData . changed ) {
@@ -243,7 +254,6 @@ export function useDomEditCommits({
243254 coalesceKey : options ?. coalesceKey ,
244255 files : { [ targetPath ] : { before : originalContent , after : finalContent } } ,
245256 } ) ;
246- showToast ( `Updated ${ patchData . path ?? targetPath } ` , "info" ) ;
247257
248258 if ( ! options ?. skipRefresh ) {
249259 reloadPreview ( ) ;
@@ -256,7 +266,6 @@ export function useDomEditCommits({
256266 projectIdRef ,
257267 domEditSaveTimestampRef ,
258268 reloadPreview ,
259- showToast ,
260269 ] ,
261270 ) ;
262271
@@ -282,38 +291,12 @@ export function useDomEditCommits({
282291 resolveImportedFontAsset,
283292 } ) ;
284293
285- // ── Position patch helper ──
286-
287- // fallow-ignore-next-line complexity
288- const commitPositionPatchToHtml = useCallback (
289- (
290- selection : DomEditSelection ,
291- patches : PatchOperation [ ] ,
292- options : { label : string ; coalesceKey : string ; skipRefresh ?: boolean } ,
293- ) => {
294- return queueDomEditSave ( async ( ) => {
295- await persistDomEditOperations ( selection , patches , {
296- label : options . label ,
297- coalesceKey : options . coalesceKey ,
298- skipRefresh : options . skipRefresh ?? true ,
299- } ) ;
300- // fallow-ignore-next-line complexity
301- } ) . catch ( ( error ) => {
302- const message = error instanceof Error ? error . message : "Failed to save position" ;
303- showToast ( message ) ;
304- trackStudioEvent ( "save_failure" , {
305- source : "dom_edit" ,
306- label : options . label ,
307- error_message : message ,
308- target_id : selection . id ?? undefined ,
309- target_selector : selection . selector ?? undefined ,
310- target_source_file : selection . sourceFile ?? undefined ,
311- } ) ;
312- throw error ;
313- } ) ;
314- } ,
315- [ persistDomEditOperations , queueDomEditSave , showToast ] ,
316- ) ;
294+ const commitPositionPatchToHtml = useDomEditPositionPatchCommit ( {
295+ activeCompPath,
296+ persistDomEditOperations,
297+ queueDomEditSave,
298+ showToast,
299+ } ) ;
317300
318301 // ── Position commits ──
319302
@@ -426,7 +409,9 @@ export function useDomEditCommits({
426409 const response = await fetch (
427410 `/api/projects/${ pid } /files/${ encodeURIComponent ( targetPath ) } ` ,
428411 ) ;
429- if ( ! response . ok ) throw new Error ( `Failed to read ${ targetPath } ` ) ;
412+ if ( ! response . ok ) {
413+ throw await createStudioSaveHttpError ( response , `Failed to read ${ targetPath } ` ) ;
414+ }
430415
431416 const data = ( await response . json ( ) ) as { content ?: string } ;
432417 const originalContent = data . content ;
@@ -447,7 +432,12 @@ export function useDomEditCommits({
447432 body : JSON . stringify ( { target : patchTarget } ) ,
448433 } ,
449434 ) ;
450- if ( ! removeResponse . ok ) throw new Error ( `Failed to delete element from ${ targetPath } ` ) ;
435+ if ( ! removeResponse . ok ) {
436+ throw await createStudioSaveHttpError (
437+ removeResponse ,
438+ `Failed to delete element from ${ targetPath } ` ,
439+ ) ;
440+ }
451441
452442 const removeData = ( await removeResponse . json ( ) ) as { changed ?: boolean ; content ?: string } ;
453443 const patchedContent =
0 commit comments