@drawnagency/primitives 0.1.44 → 0.1.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"IndicatorPill.d.ts","sourceRoot":"","sources":["../../../src/components/editor/IndicatorPill.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAItE,UAAU,MAAM;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,kBAAkB;IAC1B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,0FAA0F;IAC1F,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,YAAY,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,IAAI,KAAK,SAAS,CAAC,CAAC;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,KAAK,EACL,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,eAAe,EACf,SAAS,GACV,EAAE,kBAAkB,2CA0FpB"}
1
+ {"version":3,"file":"IndicatorPill.d.ts","sourceRoot":"","sources":["../../../src/components/editor/IndicatorPill.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAItE,UAAU,MAAM;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,kBAAkB;IAC1B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,0FAA0F;IAC1F,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,YAAY,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,IAAI,KAAK,SAAS,CAAC,CAAC;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,KAAK,EACL,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,eAAe,EACf,SAAS,GACV,EAAE,kBAAkB,2CA6FpB"}
@@ -1,3 +1,3 @@
1
1
  import type { WrapperProps } from "../../lib/registry";
2
- export declare function SectionWrapper({ sectionId, sectionType, status, dirty, index, isLast, definition, options, audiences, access, onAccessChange, onStatusChange, onSectionChange, onReorder, onRequestInsert, onDelete, isDeleted, onUndoDelete, mainStatus, contentDiffersFromMain, isLocalOnly, children, }: WrapperProps): import("react/jsx-runtime").JSX.Element | null;
2
+ export declare function SectionWrapper({ sectionId, sectionType, status, dirty, index, isLast, definition, options, audiences, access, onAccessChange, onStatusChange, onSectionChange, onReorder, onRequestInsert, onDelete, mainStatus, contentDiffersFromMain, isLocalOnly, children, }: WrapperProps): import("react/jsx-runtime").JSX.Element;
3
3
  //# sourceMappingURL=SectionWrapper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SectionWrapper.d.ts","sourceRoot":"","sources":["../../../src/components/editor/SectionWrapper.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIvD,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,WAAW,EACX,MAAM,EACN,KAAK,EACL,KAAK,EACL,MAAM,EACN,UAAU,EACV,OAAO,EACP,SAAS,EACT,MAAM,EACN,cAAc,EACd,cAAc,EACd,eAAe,EACf,SAAS,EACT,eAAe,EACf,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,UAAU,EACV,sBAAsB,EACtB,WAAW,EACX,QAAQ,GACT,EAAE,YAAY,kDA4Sd"}
1
+ {"version":3,"file":"SectionWrapper.d.ts","sourceRoot":"","sources":["../../../src/components/editor/SectionWrapper.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGvD,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,WAAW,EACX,MAAM,EACN,KAAK,EACL,KAAK,EACL,MAAM,EACN,UAAU,EACV,OAAO,EACP,SAAS,EACT,MAAM,EACN,cAAc,EACd,cAAc,EACd,eAAe,EACf,SAAS,EACT,eAAe,EACf,QAAQ,EACR,UAAU,EACV,sBAAsB,EACtB,WAAW,EACX,QAAQ,GACT,EAAE,YAAY,2CAiRd"}
@@ -1 +1 @@
1
- {"version":3,"file":"useEditableRichText.d.ts","sourceRoot":"","sources":["../../../src/components/primitives/useEditableRichText.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,OAAO,EAAW,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE5D,UAAU,0BAA0B;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,MAAM,EAAE,UAAU,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,UAAU,yBAAyB;IACjC,cAAc,EAAE,OAAO,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,QAAQ,EACR,MAAM,EACN,WAAW,GACZ,EAAE,0BAA0B,GAAG,yBAAyB,CAuDxD"}
1
+ {"version":3,"file":"useEditableRichText.d.ts","sourceRoot":"","sources":["../../../src/components/primitives/useEditableRichText.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,OAAO,EAAW,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE5D,UAAU,0BAA0B;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,MAAM,EAAE,UAAU,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,UAAU,yBAAyB;IACjC,cAAc,EAAE,OAAO,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,QAAQ,EACR,MAAM,EACN,WAAW,GACZ,EAAE,0BAA0B,GAAG,yBAAyB,CAmExD"}
@@ -1 +1 @@
1
- {"version":3,"file":"EditorShell.d.ts","sourceRoot":"","sources":["../../../src/components/shell/EditorShell.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAuDjD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAQxD,UAAU,KAAK;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,YAAY,EAAE;QACZ,KAAK,EAAE,OAAO,CAAC;QACf,aAAa,EAAE,OAAO,CAAC;QACvB,YAAY,EAAE,OAAO,CAAC;QACtB,cAAc,EAAE,OAAO,CAAC;QACxB,kBAAkB,EAAE,OAAO,CAAC;QAC5B,cAAc,EAAE,OAAO,CAAC;KACzB,CAAC;IACF,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAA;KAAE,GAAG,IAAI,CAAC;CACjE;AAED,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAClC,OAAO,EACP,MAAM,EACN,SAAS,EAAE,gBAAgB,EAC3B,YAAY,EACZ,WAAW,GACZ,EAAE,KAAK,2CAqpBP"}
1
+ {"version":3,"file":"EditorShell.d.ts","sourceRoot":"","sources":["../../../src/components/shell/EditorShell.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAuDjD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAQxD,UAAU,KAAK;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,YAAY,EAAE;QACZ,KAAK,EAAE,OAAO,CAAC;QACf,aAAa,EAAE,OAAO,CAAC;QACvB,YAAY,EAAE,OAAO,CAAC;QACtB,cAAc,EAAE,OAAO,CAAC;QACxB,kBAAkB,EAAE,OAAO,CAAC;QAC5B,cAAc,EAAE,OAAO,CAAC;KACzB,CAAC;IACF,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAA;KAAE,GAAG,IAAI,CAAC;CACjE;AAED,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAClC,OAAO,EACP,MAAM,EACN,SAAS,EAAE,gBAAgB,EAC3B,YAAY,EACZ,WAAW,GACZ,EAAE,KAAK,2CA0sBP"}
@@ -3,6 +3,7 @@ import type { SiteIndex, SiteConfig } from "../schemas/site-config";
3
3
  export declare function useEditorPersistence(siteIndexRef: React.RefObject<SiteIndex>): {
4
4
  markSectionDirty: (sectionId: string, content: SectionContent) => void;
5
5
  markIndexDirty: () => void;
6
+ removeSection: (sectionId: string) => void;
6
7
  persistConfig: (config: SiteConfig) => Promise<void>;
7
8
  flushNow: () => Promise<void>;
8
9
  cancelPendingFlush: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useEditorPersistence.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditorPersistence.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AASpE,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC;kCAoD7D,MAAM,WAAW,cAAc;;4BAYI,UAAU;;;;;EAwB5D"}
1
+ {"version":3,"file":"useEditorPersistence.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditorPersistence.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AASpE,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC;kCA8E7D,MAAM,WAAW,cAAc;;+BAgBC,MAAM;4BASH,UAAU;;;;;EAyB5D"}
@@ -12,6 +12,8 @@ interface PublishDeps {
12
12
  deletedSectionIds?: string[];
13
13
  onSuccess: () => void;
14
14
  mediaManifest: MediaManifest;
15
+ manifestDirty: boolean;
16
+ clearManifestDirty: () => void;
15
17
  pendingMediaItems: MediaItem[];
16
18
  pendingMediaDeletions: string[];
17
19
  onMediaPublished: (publishedItems: MediaItem[], publishedDeletions: string[]) => void;
@@ -19,7 +21,7 @@ interface PublishDeps {
19
21
  onPublishComplete?: () => void;
20
22
  }
21
23
  export type PublishAction = "idle" | "saving" | "publishing";
22
- export declare function useEditorPublish({ flushNow, cancelPendingFlush, isConfigDirty, clearConfigDirty, siteIndexRef, siteConfig, sections, deletedSectionIds, onSuccess, mediaManifest, pendingMediaItems, pendingMediaDeletions, onMediaPublished, onShasUpdated, onPublishComplete, }: PublishDeps): {
24
+ export declare function useEditorPublish({ flushNow, cancelPendingFlush, isConfigDirty, clearConfigDirty, siteIndexRef, siteConfig, sections, deletedSectionIds, onSuccess, mediaManifest, manifestDirty, clearManifestDirty, pendingMediaItems, pendingMediaDeletions, onMediaPublished, onShasUpdated, onPublishComplete, }: PublishDeps): {
23
25
  publishAction: PublishAction;
24
26
  publishFeedback: string | null;
25
27
  handleSave: () => Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"useEditorPublish.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditorPublish.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAe/D,UAAU,WAAW;IACnB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,aAAa,EAAE,MAAM,OAAO,CAAC;IAC7B,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACzC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,aAAa,EAAE,aAAa,CAAC;IAC7B,iBAAiB,EAAE,SAAS,EAAE,CAAC;IAC/B,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,gBAAgB,EAAE,CAAC,cAAc,EAAE,SAAS,EAAE,EAAE,kBAAkB,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACtF,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACzE,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;CAChC;AAQD,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,QAAQ,GAAG,YAAY,CAAC;AAE7D,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,iBAAiB,EACjB,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,qBAAqB,EACrB,gBAAgB,EAChB,aAAa,EACb,iBAAiB,GAClB,EAAE,WAAW;;;;;;EA4Qb"}
1
+ {"version":3,"file":"useEditorPublish.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditorPublish.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAe/D,UAAU,WAAW;IACnB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,aAAa,EAAE,MAAM,OAAO,CAAC;IAC7B,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACzC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,aAAa,EAAE,aAAa,CAAC;IAC7B,aAAa,EAAE,OAAO,CAAC;IACvB,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,iBAAiB,EAAE,SAAS,EAAE,CAAC;IAC/B,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,gBAAgB,EAAE,CAAC,cAAc,EAAE,SAAS,EAAE,EAAE,kBAAkB,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACtF,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACzE,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;CAChC;AAQD,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,QAAQ,GAAG,YAAY,CAAC;AAE7D,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,iBAAiB,EACjB,SAAS,EACT,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,gBAAgB,EAChB,aAAa,EACb,iBAAiB,GAClB,EAAE,WAAW;;;;;;EAwRb"}
@@ -54,6 +54,8 @@ export declare function useMediaPipeline({ siteConfig, mediaManifest, setMediaMa
54
54
  setPendingLocalUrls: import("react").Dispatch<import("react").SetStateAction<Record<string, string>>>;
55
55
  pendingDeletions: string[];
56
56
  setPendingDeletions: import("react").Dispatch<import("react").SetStateAction<string[]>>;
57
+ manifestDirty: boolean;
58
+ setManifestDirty: import("react").Dispatch<import("react").SetStateAction<boolean>>;
57
59
  handleMediaUpload: (files: File[]) => Promise<void>;
58
60
  handleMediaDelete: (ids: string[]) => Promise<void>;
59
61
  handleMediaAltChange: (id: string, alt: string) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useMediaPipeline.d.ts","sourceRoot":"","sources":["../../src/hooks/useMediaPipeline.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,SAAS,EAAmB,MAAM,gBAAgB,CAAC;AAClF,OAAO,KAAK,EAAE,aAAa,EAAiC,MAAM,gBAAgB,CAAC;AACnF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,yCAAyC,CAAC;AA0BxF,UAAU,qBAAqB;IAC7B,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,aAAa,CAAC;IAC7B,gBAAgB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC,CAAC;IACtE,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;IACnE,oBAAoB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACpE,kBAAkB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACtE,gBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;CACxE;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,QAAQ,EACR,WAAW,EACX,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,GACjB,EAAE,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BA6H8B,IAAI,EAAE;6BAyBR,MAAM,EAAE;+BA+CZ,MAAM,OAAO,MAAM;;;wBA+B1B,IAAI,eAAe,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI;EA2EpF"}
1
+ {"version":3,"file":"useMediaPipeline.d.ts","sourceRoot":"","sources":["../../src/hooks/useMediaPipeline.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,SAAS,EAAmB,MAAM,gBAAgB,CAAC;AAClF,OAAO,KAAK,EAAE,aAAa,EAAiC,MAAM,gBAAgB,CAAC;AACnF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,yCAAyC,CAAC;AA0BxF,UAAU,qBAAqB;IAC7B,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,aAAa,CAAC;IAC7B,gBAAgB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC,CAAC;IACtE,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;IACnE,oBAAoB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACpE,kBAAkB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACtE,gBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;CACxE;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,QAAQ,EACR,WAAW,EACX,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,GACjB,EAAE,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BAoI8B,IAAI,EAAE;6BAyBR,MAAM,EAAE;+BA+CZ,MAAM,OAAO,MAAM;;;wBAkC1B,IAAI,eAAe,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI;EA6EpF"}
@@ -20,6 +20,33 @@ export declare function getDirtySections(): Promise<{
20
20
  sectionId: string;
21
21
  content: SectionContent;
22
22
  }[]>;
23
+ /**
24
+ * Like getDirtySections but includes each row's updatedAt, so callers can later
25
+ * clear only the rows they actually saved without clobbering edits made during
26
+ * an in-flight save (compare-and-clear on updatedAt).
27
+ */
28
+ export declare function getDirtySectionRows(): Promise<{
29
+ sectionId: string;
30
+ content: SectionContent;
31
+ updatedAt: string;
32
+ }[]>;
33
+ /**
34
+ * Remove section content rows (used when a section is deleted, so a dirty row
35
+ * for a section no longer in the index can't be sent to /api/save and rejected).
36
+ */
37
+ export declare function deleteSectionRows(ids: string[]): Promise<void>;
38
+ /**
39
+ * Post-save cleanup that preserves edits made WHILE the save was in flight.
40
+ * Section rows are cleared only when their updatedAt still matches what was sent
41
+ * (i.e. they weren't re-edited during the request). The index/meta/config rows
42
+ * are cleared wholesale (the save persisted them upstream), and contentCache is
43
+ * cleared so a subsequent reload re-fetches the saved-branch content instead of
44
+ * serving the stale pre-save snapshot keyed at the production SHA.
45
+ */
46
+ export declare function discardSavedChanges(savedSections: {
47
+ sectionId: string;
48
+ updatedAt: string;
49
+ }[]): Promise<void>;
23
50
  export declare function persistAll(sections: {
24
51
  sectionId: string;
25
52
  content: SectionContent;
@@ -1 +1 @@
1
- {"version":3,"file":"dexie.d.ts","sourceRoot":"","sources":["../../src/lib/dexie.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dexie.d.ts","sourceRoot":"","sources":["../../src/lib/dexie.ts"],"names":[],"mappings":"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"}
package/dist/lib/dexie.js CHANGED
@@ -157,6 +157,33 @@ async function getDirtySections() {
157
157
  const rows = await getDb().sections.filter((row) => row.dirty).toArray();
158
158
  return rows.map((row) => ({ sectionId: row.sectionId, content: row.content }));
159
159
  }
160
+ async function getDirtySectionRows() {
161
+ const rows = await getDb().sections.filter((row) => row.dirty).toArray();
162
+ return rows.map((row) => ({ sectionId: row.sectionId, content: row.content, updatedAt: row.updatedAt }));
163
+ }
164
+ async function deleteSectionRows(ids) {
165
+ if (ids.length === 0) return;
166
+ await getDb().sections.bulkDelete(ids);
167
+ }
168
+ async function discardSavedChanges(savedSections) {
169
+ const database = getDb();
170
+ await database.transaction(
171
+ "rw",
172
+ [database.sections, database.siteIndex, database.meta, database.siteConfig, database.contentCache],
173
+ async () => {
174
+ for (const { sectionId, updatedAt } of savedSections) {
175
+ const row = await database.sections.get(sectionId);
176
+ if (row && row.updatedAt === updatedAt) {
177
+ await database.sections.delete(sectionId);
178
+ }
179
+ }
180
+ await database.siteIndex.clear();
181
+ await database.meta.clear();
182
+ await database.siteConfig.clear();
183
+ await database.contentCache.clear();
184
+ }
185
+ );
186
+ }
160
187
  async function persistAll(sections, siteIndex, deletedSectionIds, siteConfig) {
161
188
  const now = (/* @__PURE__ */ new Date()).toISOString();
162
189
  const database = getDb();
@@ -294,10 +321,13 @@ export {
294
321
  cacheContent,
295
322
  checkForLocalChanges,
296
323
  clearPendingMedia,
324
+ deleteSectionRows,
297
325
  discardLocalChanges,
326
+ discardSavedChanges,
298
327
  getBranchShas,
299
328
  getCachedContent,
300
329
  getDeletedSections,
330
+ getDirtySectionRows,
301
331
  getDirtySections,
302
332
  getMediaManifest,
303
333
  getPendingMediaBlobs,
@@ -72,8 +72,6 @@ export interface WrapperProps {
72
72
  onReorder?: (fromIndex: number, toIndex: number) => void;
73
73
  onRequestInsert?: (index: number) => void;
74
74
  onDelete?: () => void;
75
- isDeleted?: boolean;
76
- onUndoDelete?: () => void;
77
75
  mainStatus?: string | null;
78
76
  contentDiffersFromMain?: boolean;
79
77
  isLocalOnly?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/lib/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/lib/registry.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drawnagency/primitives",
3
- "version": "0.1.44",
3
+ "version": "0.1.46",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./package.json": "./package.json",
@@ -76,7 +76,10 @@ export function IndicatorPill({
76
76
  aria-expanded={clickContent ? clickOpen : undefined}
77
77
  aria-label={ariaLabel}
78
78
  className={cn(
79
- "cursor-pointer inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium",
79
+ // align-middle keeps the inline-flex pill centred in its line box regardless of
80
+ // whether it leads with a status/audience dot — without it, the dot-less variant's
81
+ // text baseline sits ~2px lower than the dotted variant, misaligning the two pills.
82
+ "cursor-pointer inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium align-middle",
80
83
  "border border-base-200 hover:bg-base-accent",
81
84
  buttonClassName,
82
85
  )}
@@ -11,7 +11,6 @@ import { useEditorContext } from "../shell/EditorContext";
11
11
  import { useEditorModal } from "../shell/EditorModalContext";
12
12
  import type { WrapperProps } from "../../lib/registry";
13
13
  import { cn } from "../../lib/cn";
14
- import { Button } from "../shared/Button";
15
14
 
16
15
  export function SectionWrapper({
17
16
  sectionId,
@@ -30,8 +29,6 @@ export function SectionWrapper({
30
29
  onReorder,
31
30
  onRequestInsert,
32
31
  onDelete,
33
- isDeleted,
34
- onUndoDelete,
35
32
  mainStatus,
36
33
  contentDiffersFromMain,
37
34
  isLocalOnly,
@@ -180,33 +177,6 @@ export function SectionWrapper({
180
177
  }
181
178
  }
182
179
 
183
- if (isDeleted && isEditMode) {
184
- return (
185
- <div
186
- ref={blockRef}
187
- className="relative opacity-30 pointer-events-none"
188
- data-section-id={sectionId}
189
- data-section-type={sectionType}
190
- >
191
- <div className="pointer-events-auto absolute right-0 bottom-full z-30 mb-1">
192
- <Button
193
- variant="secondary"
194
- size="sm"
195
- onClick={onUndoDelete}
196
- className="pointer-events-auto"
197
- >
198
- Undo delete
199
- </Button>
200
- </div>
201
- {children}
202
- </div>
203
- );
204
- }
205
-
206
- if (isDeleted) {
207
- return null;
208
- }
209
-
210
180
  if (!isEditMode) {
211
181
  if (status && status !== "live") {
212
182
  return (
@@ -46,6 +46,18 @@ export function useEditableRichText({
46
46
  const ed = new Editor({
47
47
  extensions,
48
48
  content: valueRef.current,
49
+ // Commit edits to onChange on every transaction, not only on deactivate().
50
+ // Without this, content lives only inside TipTap until blur; clicking a
51
+ // Save button while the editor is still focused flushes persistence before
52
+ // the (150ms-delayed) blur->deactivate commit fires, silently dropping the
53
+ // in-progress edit. Live-committing keeps persistence in sync continuously.
54
+ onUpdate: ({ editor: updated }) => {
55
+ const html = updated.getHTML();
56
+ if (html !== valueRef.current) {
57
+ valueRef.current = html;
58
+ onChangeRef.current(html);
59
+ }
60
+ },
49
61
  });
50
62
  editorRef.current = ed;
51
63
  setEditor(ed);
@@ -103,6 +103,7 @@ export default function EditorShell({
103
103
  const [mediaModalMode, setMediaModalMode] = useState<"select" | "manage">("manage");
104
104
  const [mediaSelectCallback, setMediaSelectCallback] = useState<((id: string) => void) | null>(null);
105
105
  const [deletedSections, setDeletedSections] = useState<Set<string>>(new Set());
106
+ const [pendingDeleteSectionId, setPendingDeleteSectionId] = useState<string | null>(null);
106
107
  const [savedSha, setSavedSha] = useState<string | null>(null);
107
108
  const [mainSha, setMainSha] = useState<string | null>(null);
108
109
  const [changedSectionIds, setChangedSectionIds] = useState<Set<string>>(new Set());
@@ -114,6 +115,10 @@ export default function EditorShell({
114
115
  const [rejectedUploads, setRejectedUploads] = useState<{ name: string; reason: "size" | "type" }[]>([]);
115
116
 
116
117
  const siteIndexRef = useRef<SiteIndex>({ siteId, order: [], sections: {} });
118
+ // Ids of sections that exist on the remote (loaded from server, or persisted by
119
+ // a prior save). Used so deleting a section that was only ever added locally
120
+ // doesn't enqueue a GitHub file deletion for a path that was never committed.
121
+ const remoteSectionIdsRef = useRef<Set<string>>(new Set());
117
122
  const fontLinkRef = useRef<HTMLLinkElement | null>(null);
118
123
  useEffect(() => { siteIndexRef.current = siteIndex; }, [siteIndex]);
119
124
  useEffect(() => { void ensureSanitizer(); }, []);
@@ -146,8 +151,12 @@ export default function EditorShell({
146
151
  setDirtySectionIds(new Set());
147
152
  setDeletedSections(new Set());
148
153
  setLocalChangesExist(false);
154
+ // Everything in the index now exists remotely (it was just saved).
155
+ remoteSectionIdsRef.current = new Set(siteIndexRef.current.order);
149
156
  },
150
157
  mediaManifest,
158
+ manifestDirty: mediaPipeline.manifestDirty,
159
+ clearManifestDirty: () => mediaPipeline.setManifestDirty(false),
151
160
  pendingMediaItems: mediaPipeline.pendingMediaItems,
152
161
  pendingMediaDeletions: mediaPipeline.pendingDeletions,
153
162
  onMediaPublished: (publishedItems, publishedDeletions) => {
@@ -268,6 +277,7 @@ export default function EditorShell({
268
277
  if (cancelled) return;
269
278
  setSections(loadedSections);
270
279
  setSiteIndex(loadedIndex);
280
+ remoteSectionIdsRef.current = new Set(loadedIndex.order);
271
281
  setSiteConfig(loadedConfig);
272
282
  setMediaManifest(loadedManifest);
273
283
  siteIndexRef.current = loadedIndex;
@@ -330,6 +340,15 @@ export default function EditorShell({
330
340
  }).filter((s): s is LoadedSection => s !== null),
331
341
  );
332
342
  setSiteIndex(restoredIndex);
343
+ // Re-derive pending deletions: any remotely-existing section absent from the
344
+ // restored index was deleted locally before this reload. The deletion intent
345
+ // isn't persisted directly, so reconstruct it here — otherwise the section's
346
+ // GitHub file would be orphaned (index omits it, but it's never deleted).
347
+ const restoredIds = new Set(restoredIndex.order);
348
+ const rediscoveredDeletions = new Set(
349
+ [...remoteSectionIdsRef.current].filter((id) => !restoredIds.has(id)),
350
+ );
351
+ setDeletedSections(rediscoveredDeletions);
333
352
  } else {
334
353
  setSections((prev) =>
335
354
  prev.map((loaded) => {
@@ -360,6 +379,8 @@ export default function EditorShell({
360
379
  await discardLocalChanges();
361
380
  setLocalChangesExist(false);
362
381
  setDirtySectionIds(new Set());
382
+ setDeletedSections(new Set());
383
+ mediaPipeline.setManifestDirty(false);
363
384
  for (const url of Object.values(mediaPipeline.pendingLocalUrls)) {
364
385
  URL.revokeObjectURL(url);
365
386
  }
@@ -371,6 +392,7 @@ export default function EditorShell({
371
392
  setSections(cached.sections);
372
393
  setSiteIndex(cached.index);
373
394
  siteIndexRef.current = cached.index;
395
+ remoteSectionIdsRef.current = new Set(cached.index.order);
374
396
  const parsed = SiteConfigSchema.safeParse(cached.siteConfig);
375
397
  if (parsed.success) {
376
398
  setSiteConfig(parsed.data);
@@ -444,9 +466,28 @@ export default function EditorShell({
444
466
  [persistence],
445
467
  );
446
468
 
447
- const onDeleteSection = useCallback(
469
+ // Runs after the confirmation modal is accepted. Removes the section from the
470
+ // live editor immediately (no ghost/undo), persists the filtered index, and
471
+ // records the id so its JSON file is deleted from GitHub on the next save.
472
+ const performDeleteSection = useCallback(
448
473
  (sectionId: string) => {
449
- setDeletedSections((prev) => new Set(prev).add(sectionId));
474
+ setSections((prev) => prev.filter((loaded) => loaded.section.id !== sectionId));
475
+ setSiteIndex((prev) => {
476
+ const nextSections = { ...prev.sections };
477
+ delete nextSections[sectionId];
478
+ return {
479
+ ...prev,
480
+ order: prev.order.filter((id) => id !== sectionId),
481
+ sections: nextSections,
482
+ };
483
+ });
484
+ // Only schedule a GitHub file deletion if the section exists remotely. A
485
+ // section that was added locally and never saved has no committed file, so
486
+ // sending a deletion for it would target a non-existent path.
487
+ if (remoteSectionIdsRef.current.has(sectionId)) {
488
+ setDeletedSections((prev) => new Set(prev).add(sectionId));
489
+ }
490
+ persistence.removeSection(sectionId);
450
491
  setLocalChangesExist(true);
451
492
  setDirtySectionIds((prev) => {
452
493
  const next = new Set(prev);
@@ -454,16 +495,13 @@ export default function EditorShell({
454
495
  return next;
455
496
  });
456
497
  },
457
- [],
498
+ [persistence],
458
499
  );
459
500
 
460
- const handleUndoDelete = useCallback((sectionId: string) => {
461
- setDeletedSections((prev) => {
462
- const next = new Set(prev);
463
- next.delete(sectionId);
464
- return next;
465
- });
466
- }, []);
501
+ const confirmDeleteSection = useCallback(() => {
502
+ if (pendingDeleteSectionId) performDeleteSection(pendingDeleteSectionId);
503
+ setPendingDeleteSectionId(null);
504
+ }, [pendingDeleteSectionId, performDeleteSection]);
467
505
 
468
506
  const onReorderSections = useCallback(
469
507
  (fromIndex: number, toIndex: number) => {
@@ -655,12 +693,10 @@ export default function EditorShell({
655
693
  sections={sections}
656
694
  audiences={audiences}
657
695
  dirtySectionIds={dirtySectionIds}
658
- deletedSections={deletedSections}
659
696
  isPublishing={publishAction !== "idle"}
660
697
  onSectionChange={onSectionChange}
661
698
  onAddSection={onAddSection}
662
- onDeleteSection={onDeleteSection}
663
- onUndoDelete={handleUndoDelete}
699
+ onDeleteSection={setPendingDeleteSectionId}
664
700
  onReorderSections={onReorderSections}
665
701
  onAccessChange={onAccessChange}
666
702
  onStatusChange={onStatusChange}
@@ -679,6 +715,23 @@ export default function EditorShell({
679
715
  capabilities={capabilities}
680
716
  currentUser={currentUser}
681
717
  />
718
+ <EditorModal
719
+ isOpen={pendingDeleteSectionId !== null}
720
+ onClose={() => setPendingDeleteSectionId(null)}
721
+ title="Delete Section"
722
+ >
723
+ <p className="mb-4 text-sm text-base-contrast-light">
724
+ Delete this section? It will be removed from the page now and deleted permanently when you save or publish.
725
+ </p>
726
+ <div className="flex justify-end gap-3">
727
+ <Button variant="secondary" size="md" onClick={() => setPendingDeleteSectionId(null)}>
728
+ Cancel
729
+ </Button>
730
+ <Button variant="destructive" size="md" onClick={confirmDeleteSection}>
731
+ Delete
732
+ </Button>
733
+ </div>
734
+ </EditorModal>
682
735
  <EditorModal
683
736
  isOpen={showDiscardConfirm}
684
737
  onClose={() => setShowDiscardConfirm(false)}
@@ -860,12 +913,10 @@ function EditorContent({
860
913
  sections,
861
914
  audiences,
862
915
  dirtySectionIds,
863
- deletedSections,
864
916
  isPublishing,
865
917
  onSectionChange,
866
918
  onAddSection,
867
919
  onDeleteSection,
868
- onUndoDelete,
869
920
  onReorderSections,
870
921
  onAccessChange,
871
922
  onStatusChange,
@@ -876,12 +927,10 @@ function EditorContent({
876
927
  sections: LoadedSection[];
877
928
  audiences: Audience[];
878
929
  dirtySectionIds: Set<string>;
879
- deletedSections: Set<string>;
880
930
  isPublishing: boolean;
881
931
  onSectionChange: (sectionId: string, content: SectionContent) => void;
882
932
  onAddSection: (insertIndex: number, type: string) => void;
883
933
  onDeleteSection: (sectionId: string) => void;
884
- onUndoDelete: (sectionId: string) => void;
885
934
  onReorderSections: (fromIndex: number, toIndex: number) => void;
886
935
  onAccessChange: (sectionId: string, access: string[]) => void;
887
936
  onStatusChange: (sectionId: string, status: "draft" | "live" | "archived") => void;
@@ -971,8 +1020,6 @@ function EditorContent({
971
1020
  }}
972
1021
  audiences={audiences}
973
1022
  access={meta.access}
974
- isDeleted={deletedSections.has(section.id)}
975
- onUndoDelete={() => onUndoDelete(section.id)}
976
1023
  onAccessChange={editingEnabled ? (a) => onAccessChange(section.id, a) : undefined}
977
1024
  onStatusChange={editingEnabled ? (s) => onStatusChange(section.id, s) : undefined}
978
1025
  onSectionChange={editingEnabled ? (settingsResult) => {
@@ -1,7 +1,7 @@
1
1
  import { useCallback, useRef, useEffect } from "react";
2
2
  import type { SectionContent } from "../schemas/sections";
3
3
  import type { SiteIndex, SiteConfig } from "../schemas/site-config";
4
- import { persistAll, persistSiteConfig } from "../lib/dexie";
4
+ import { persistAll, persistSiteConfig, deleteSectionRows } from "../lib/dexie";
5
5
 
6
6
  interface PersistenceState {
7
7
  pendingSections: Map<string, SectionContent>;
@@ -60,6 +60,32 @@ export function useEditorPersistence(siteIndexRef: React.RefObject<SiteIndex>) {
60
60
  };
61
61
  }, [flushToDexie]);
62
62
 
63
+ // Flush pending edits when the tab is hidden or unloaded. The unmount cleanup
64
+ // above is fire-and-forget and does not reliably complete during real document
65
+ // teardown (closing the tab / navigating away), so a debounced edit made within
66
+ // the flush window would otherwise be lost before it ever reached Dexie.
67
+ // visibilitychange->hidden is the reliable teardown signal on desktop + mobile;
68
+ // pagehide is a secondary trigger for hard navigations.
69
+ useEffect(() => {
70
+ if (typeof document === "undefined") return;
71
+ const flushOnExit = () => {
72
+ if (flushTimerRef.current) {
73
+ clearTimeout(flushTimerRef.current);
74
+ flushTimerRef.current = null;
75
+ }
76
+ void flushToDexie();
77
+ };
78
+ const onVisibilityChange = () => {
79
+ if (document.visibilityState === "hidden") flushOnExit();
80
+ };
81
+ document.addEventListener("visibilitychange", onVisibilityChange);
82
+ window.addEventListener("pagehide", flushOnExit);
83
+ return () => {
84
+ document.removeEventListener("visibilitychange", onVisibilityChange);
85
+ window.removeEventListener("pagehide", flushOnExit);
86
+ };
87
+ }, [flushToDexie]);
88
+
63
89
  const markSectionDirty = useCallback(
64
90
  (sectionId: string, content: SectionContent) => {
65
91
  state.current.pendingSections.set(sectionId, content);
@@ -73,6 +99,19 @@ export function useEditorPersistence(siteIndexRef: React.RefObject<SiteIndex>) {
73
99
  scheduleFlush();
74
100
  }, [scheduleFlush]);
75
101
 
102
+ // Drop a section from local persistence (used when it is deleted). Removes any
103
+ // pending in-memory edit and the persisted Dexie row so a now-orphaned dirty
104
+ // row can't be sent to /api/save (which would reject it as absent from the
105
+ // index), and marks the index dirty so the filtered order is persisted.
106
+ const removeSection = useCallback((sectionId: string) => {
107
+ state.current.pendingSections.delete(sectionId);
108
+ state.current.indexDirty = true;
109
+ deleteSectionRows([sectionId]).catch((err) => {
110
+ console.error("Failed to delete section row from Dexie:", err);
111
+ });
112
+ scheduleFlush();
113
+ }, [scheduleFlush]);
114
+
76
115
  const persistConfig = useCallback(async (config: SiteConfig) => {
77
116
  state.current.configDirty = true;
78
117
  await persistSiteConfig(config);
@@ -91,6 +130,7 @@ export function useEditorPersistence(siteIndexRef: React.RefObject<SiteIndex>) {
91
130
  return {
92
131
  markSectionDirty,
93
132
  markIndexDirty,
133
+ removeSection,
94
134
  persistConfig,
95
135
  flushNow: flushToDexie,
96
136
  cancelPendingFlush,
@@ -2,7 +2,7 @@ import { useState, useCallback, useRef, useEffect } from "react";
2
2
  import type { SiteIndex, SiteConfig } from "../schemas/site-config";
3
3
  import type { LoadedSection } from "../lib/loader";
4
4
  import type { MediaManifest, MediaItem } from "../media/types";
5
- import { getDirtySections, hasLocalChanges, discardLocalChanges, cacheContent, getPendingMediaBlobs, clearPendingMedia } from "../lib/dexie";
5
+ import { getDirtySectionRows, hasLocalChanges, discardSavedChanges, cacheContent, getPendingMediaBlobs, clearPendingMedia } from "../lib/dexie";
6
6
 
7
7
  function blobToBase64(blob: Blob): Promise<string> {
8
8
  return new Promise((resolve, reject) => {
@@ -27,6 +27,8 @@ interface PublishDeps {
27
27
  deletedSectionIds?: string[];
28
28
  onSuccess: () => void;
29
29
  mediaManifest: MediaManifest;
30
+ manifestDirty: boolean;
31
+ clearManifestDirty: () => void;
30
32
  pendingMediaItems: MediaItem[];
31
33
  pendingMediaDeletions: string[];
32
34
  onMediaPublished: (publishedItems: MediaItem[], publishedDeletions: string[]) => void;
@@ -53,6 +55,8 @@ export function useEditorPublish({
53
55
  deletedSectionIds,
54
56
  onSuccess,
55
57
  mediaManifest,
58
+ manifestDirty,
59
+ clearManifestDirty,
56
60
  pendingMediaItems,
57
61
  pendingMediaDeletions,
58
62
  onMediaPublished,
@@ -80,8 +84,9 @@ export function useEditorPublish({
80
84
  pendingItems: MediaItem[],
81
85
  pendingDeletions: string[],
82
86
  manifest: MediaManifest,
87
+ manifestOnlyDirty: boolean,
83
88
  ): Promise<GatheredMedia> {
84
- const hasMediaChanges = pendingItems.length > 0 || pendingDeletions.length > 0;
89
+ const hasMediaChanges = pendingItems.length > 0 || pendingDeletions.length > 0 || manifestOnlyDirty;
85
90
  const mediaUploads: { item: MediaItem; blobs: { path: string; base64: string }[] }[] = [];
86
91
 
87
92
  const deletionSet = new Set(pendingDeletions);
@@ -134,12 +139,14 @@ export function useEditorPublish({
134
139
  pendingMediaItems: MediaItem[];
135
140
  pendingMediaDeletions: string[];
136
141
  mediaManifest: MediaManifest;
137
- }): Promise<{ sha: string }> {
138
- const dirty = await getDirtySections();
142
+ manifestDirty: boolean;
143
+ }): Promise<{ sha: string; savedSections: { sectionId: string; updatedAt: string }[] }> {
144
+ const dirty = await getDirtySectionRows();
139
145
  const gathered = await gatherMediaPayload(
140
146
  args.pendingMediaItems,
141
147
  args.pendingMediaDeletions,
142
148
  args.mediaManifest,
149
+ args.manifestDirty,
143
150
  );
144
151
 
145
152
  let siteIndex = args.siteIndexRef.current;
@@ -189,7 +196,10 @@ export function useEditorPublish({
189
196
  if (!responseData?.sha) {
190
197
  throw new Error("Save response missing SHA");
191
198
  }
192
- return responseData;
199
+ return {
200
+ sha: responseData.sha as string,
201
+ savedSections: dirty.map(({ sectionId, updatedAt }) => ({ sectionId, updatedAt })),
202
+ };
193
203
  }
194
204
 
195
205
  const handleSave = useCallback(async () => {
@@ -204,21 +214,25 @@ export function useEditorPublish({
204
214
  await flushNow();
205
215
 
206
216
  const hasChanges = await hasLocalChanges();
207
- const hasMediaChanges = pendingMediaItems.length > 0 || pendingMediaDeletions.length > 0;
217
+ const hasMediaChanges = pendingMediaItems.length > 0 || pendingMediaDeletions.length > 0 || manifestDirty;
208
218
  const hasDeletedSections = (deletedSectionIds?.length ?? 0) > 0;
209
219
  if (!hasChanges && !isConfigDirty() && !hasMediaChanges && !hasDeletedSections) {
210
220
  setPublishAction("idle");
211
221
  return;
212
222
  }
213
223
 
214
- const { sha } = await performSave({
224
+ const { sha, savedSections } = await performSave({
215
225
  siteConfig, siteIndexRef, deletedSectionIds,
216
- isConfigDirty, pendingMediaItems, pendingMediaDeletions, mediaManifest,
226
+ isConfigDirty, pendingMediaItems, pendingMediaDeletions, mediaManifest, manifestDirty,
217
227
  });
218
228
 
219
- await discardLocalChanges();
229
+ // Clears only the section rows we actually sent (preserving edits typed
230
+ // during the request) and invalidates contentCache so a reload reflects
231
+ // the just-saved content instead of showing the stale pre-save snapshot.
232
+ await discardSavedChanges(savedSections);
220
233
  await clearPendingMedia();
221
234
  clearConfigDirty();
235
+ clearManifestDirty();
222
236
  onSuccess();
223
237
  onMediaPublished(pendingMediaItems, pendingMediaDeletions);
224
238
  onShasUpdated(sha, null);
@@ -231,7 +245,7 @@ export function useEditorPublish({
231
245
  inFlightRef.current = false;
232
246
  setPublishAction("idle");
233
247
  }
234
- }, [flushNow, cancelPendingFlush, isConfigDirty, clearConfigDirty, siteIndexRef, siteConfig, deletedSectionIds, onSuccess, mediaManifest, pendingMediaItems, pendingMediaDeletions, onMediaPublished, onShasUpdated, showFeedback]);
248
+ }, [flushNow, cancelPendingFlush, isConfigDirty, clearConfigDirty, siteIndexRef, siteConfig, deletedSectionIds, onSuccess, mediaManifest, manifestDirty, clearManifestDirty, pendingMediaItems, pendingMediaDeletions, onMediaPublished, onShasUpdated, showFeedback]);
235
249
 
236
250
  const handlePublish = useCallback(async () => {
237
251
  setPublishAction("publishing");
@@ -276,15 +290,16 @@ export function useEditorPublish({
276
290
  await flushNow();
277
291
 
278
292
  const hasChanges = await hasLocalChanges();
279
- const hasMediaChanges = pendingMediaItems.length > 0 || pendingMediaDeletions.length > 0;
293
+ const hasMediaChanges = pendingMediaItems.length > 0 || pendingMediaDeletions.length > 0 || manifestDirty;
280
294
  const hasDeletedSections = (deletedSectionIds?.length ?? 0) > 0;
281
295
  const hasLocalEdits = hasChanges || isConfigDirty() || hasMediaChanges || hasDeletedSections;
282
296
 
297
+ let savedSections: { sectionId: string; updatedAt: string }[] = [];
283
298
  if (hasLocalEdits) {
284
- await performSave({
299
+ ({ savedSections } = await performSave({
285
300
  siteConfig, siteIndexRef, deletedSectionIds,
286
- isConfigDirty, pendingMediaItems, pendingMediaDeletions, mediaManifest,
287
- });
301
+ isConfigDirty, pendingMediaItems, pendingMediaDeletions, mediaManifest, manifestDirty,
302
+ }));
288
303
  }
289
304
 
290
305
  setPublishAction("publishing");
@@ -306,10 +321,11 @@ export function useEditorPublish({
306
321
  const { sha } = publishData;
307
322
 
308
323
  if (hasLocalEdits) {
309
- await discardLocalChanges();
324
+ await discardSavedChanges(savedSections);
310
325
  await clearPendingMedia();
311
326
  await cacheContent(sha, sections, siteIndexRef.current, siteConfig);
312
327
  clearConfigDirty();
328
+ clearManifestDirty();
313
329
  onSuccess();
314
330
  onMediaPublished(pendingMediaItems, pendingMediaDeletions);
315
331
  }
@@ -323,7 +339,7 @@ export function useEditorPublish({
323
339
  inFlightRef.current = false;
324
340
  setPublishAction("idle");
325
341
  }
326
- }, [flushNow, cancelPendingFlush, isConfigDirty, clearConfigDirty, siteIndexRef, siteConfig, sections, deletedSectionIds, onSuccess, mediaManifest, pendingMediaItems, pendingMediaDeletions, onMediaPublished, onShasUpdated, showFeedback, onPublishComplete]);
342
+ }, [flushNow, cancelPendingFlush, isConfigDirty, clearConfigDirty, siteIndexRef, siteConfig, sections, deletedSectionIds, onSuccess, mediaManifest, manifestDirty, clearManifestDirty, pendingMediaItems, pendingMediaDeletions, onMediaPublished, onShasUpdated, showFeedback, onPublishComplete]);
327
343
 
328
344
  return { publishAction, publishFeedback, handleSave, handlePublish, handleSaveAndPublish };
329
345
  }
@@ -56,6 +56,13 @@ export function useMediaPipeline({
56
56
  const [pendingMediaItems, setPendingMediaItems] = useState<LibraryMediaItem[]>([]);
57
57
  const [pendingLocalUrls, setPendingLocalUrls] = useState<Record<string, string>>({});
58
58
  const [pendingDeletions, setPendingDeletions] = useState<string[]>([]);
59
+ // True when the manifest holds unsaved edits that produce no upload/deletion —
60
+ // e.g. alt text on an already-published image. Without this the save path's
61
+ // hasMediaChanges check (uploads/deletions only) skips the change and the edit
62
+ // is silently dropped. In-session only (not persisted to Dexie): an unsaved alt
63
+ // edit is lost on reload, same as before this flag existed — but it is no longer
64
+ // dropped when the editor DOES save in the same session.
65
+ const [manifestDirty, setManifestDirty] = useState(false);
59
66
 
60
67
  const queueRef = useRef<ProcessingQueue | null>(null);
61
68
  const uploadCallbacksRef = useRef<Map<string, (imageId: string) => void>>(new Map());
@@ -257,6 +264,9 @@ export function useMediaPipeline({
257
264
  setPendingMediaItems((prev) =>
258
265
  prev.map((item) => (item.id === id ? { ...item, alt } : item)),
259
266
  );
267
+ // Flag the manifest dirty so the save path includes it (alt-only edits on
268
+ // published images produce no upload/deletion and would otherwise be skipped).
269
+ setManifestDirty(true);
260
270
  setLocalChangesExist(true);
261
271
  }, [setMediaManifest, setLocalChangesExist]);
262
272
 
@@ -347,6 +357,8 @@ export function useMediaPipeline({
347
357
  setPendingLocalUrls,
348
358
  pendingDeletions,
349
359
  setPendingDeletions,
360
+ manifestDirty,
361
+ setManifestDirty,
350
362
  handleMediaUpload,
351
363
  handleMediaDelete,
352
364
  handleMediaAltChange,
package/src/lib/dexie.ts CHANGED
@@ -242,6 +242,57 @@ export async function getDirtySections(): Promise<
242
242
  return rows.map((row) => ({ sectionId: row.sectionId, content: row.content }));
243
243
  }
244
244
 
245
+ /**
246
+ * Like getDirtySections but includes each row's updatedAt, so callers can later
247
+ * clear only the rows they actually saved without clobbering edits made during
248
+ * an in-flight save (compare-and-clear on updatedAt).
249
+ */
250
+ export async function getDirtySectionRows(): Promise<
251
+ { sectionId: string; content: SectionContent; updatedAt: string }[]
252
+ > {
253
+ const rows = await getDb().sections.filter((row) => row.dirty).toArray();
254
+ return rows.map((row) => ({ sectionId: row.sectionId, content: row.content, updatedAt: row.updatedAt }));
255
+ }
256
+
257
+ /**
258
+ * Remove section content rows (used when a section is deleted, so a dirty row
259
+ * for a section no longer in the index can't be sent to /api/save and rejected).
260
+ */
261
+ export async function deleteSectionRows(ids: string[]): Promise<void> {
262
+ if (ids.length === 0) return;
263
+ await getDb().sections.bulkDelete(ids);
264
+ }
265
+
266
+ /**
267
+ * Post-save cleanup that preserves edits made WHILE the save was in flight.
268
+ * Section rows are cleared only when their updatedAt still matches what was sent
269
+ * (i.e. they weren't re-edited during the request). The index/meta/config rows
270
+ * are cleared wholesale (the save persisted them upstream), and contentCache is
271
+ * cleared so a subsequent reload re-fetches the saved-branch content instead of
272
+ * serving the stale pre-save snapshot keyed at the production SHA.
273
+ */
274
+ export async function discardSavedChanges(
275
+ savedSections: { sectionId: string; updatedAt: string }[],
276
+ ): Promise<void> {
277
+ const database = getDb();
278
+ await database.transaction(
279
+ "rw",
280
+ [database.sections, database.siteIndex, database.meta, database.siteConfig, database.contentCache],
281
+ async () => {
282
+ for (const { sectionId, updatedAt } of savedSections) {
283
+ const row = await database.sections.get(sectionId);
284
+ if (row && row.updatedAt === updatedAt) {
285
+ await database.sections.delete(sectionId);
286
+ }
287
+ }
288
+ await database.siteIndex.clear();
289
+ await database.meta.clear();
290
+ await database.siteConfig.clear();
291
+ await database.contentCache.clear();
292
+ },
293
+ );
294
+ }
295
+
245
296
  export async function persistAll(
246
297
  sections: { sectionId: string; content: SectionContent }[],
247
298
  siteIndex?: SiteIndex,
@@ -82,8 +82,6 @@ export interface WrapperProps {
82
82
  onReorder?: (fromIndex: number, toIndex: number) => void;
83
83
  onRequestInsert?: (index: number) => void;
84
84
  onDelete?: () => void;
85
- isDeleted?: boolean;
86
- onUndoDelete?: () => void;
87
85
  mainStatus?: string | null;
88
86
  contentDiffersFromMain?: boolean;
89
87
  isLocalOnly?: boolean;