@drawnagency/primitives 0.1.109 → 0.1.110

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.
Files changed (205) hide show
  1. package/dist/auth/cookies.d.ts +8 -0
  2. package/dist/auth/cookies.d.ts.map +1 -1
  3. package/dist/auth/index.d.ts +1 -1
  4. package/dist/auth/index.d.ts.map +1 -1
  5. package/dist/auth/index.js +3 -1
  6. package/dist/auth/types.d.ts +11 -4
  7. package/dist/auth/types.d.ts.map +1 -1
  8. package/dist/{chunk-WXBHP4JY.js → chunk-3GAG6ZXB.js} +55 -46
  9. package/dist/{chunk-FM4M4Q2W.js → chunk-4TZJZU2T.js} +23 -3
  10. package/dist/{chunk-5PVRACZY.js → chunk-7MI3HCOF.js} +60 -23
  11. package/dist/{chunk-WBDPDGFA.js → chunk-7WQJ57XG.js} +6 -31
  12. package/dist/{chunk-LQHYVPBS.js → chunk-ALMEC3XN.js} +11 -12
  13. package/dist/{chunk-TZQPOR5A.js → chunk-DMCGN5AS.js} +10 -3
  14. package/dist/{chunk-ZKVKNUJC.js → chunk-ELQ4C677.js} +1 -1
  15. package/dist/{chunk-5BM2Y3NJ.js → chunk-FRVO75DK.js} +14 -2
  16. package/dist/{chunk-VKAGMEKE.js → chunk-FTPETWXE.js} +1 -0
  17. package/dist/{chunk-3TO4RRHY.js → chunk-GPPVYLEI.js} +7 -0
  18. package/dist/{chunk-NLQ5F3RQ.js → chunk-HBULBDGP.js} +1 -1
  19. package/dist/{chunk-67ZOQCUD.js → chunk-NXGIHSL5.js} +67 -50
  20. package/dist/{chunk-CPTFFLK2.js → chunk-OTDA6KWL.js} +10 -3
  21. package/dist/{chunk-XIDE4TDF.js → chunk-OUYB2GCW.js} +1 -1
  22. package/dist/{chunk-72CG6AA2.js → chunk-RA5IOFPY.js} +10 -2
  23. package/dist/{chunk-GEENI3OC.js → chunk-SW6PCQQD.js} +4 -0
  24. package/dist/{chunk-BOZUEKWL.js → chunk-UVIYI4J6.js} +1 -1
  25. package/dist/{chunk-AB3XVXI3.js → chunk-VCCNKTFD.js} +37 -29
  26. package/dist/{chunk-XBYJQ5RS.js → chunk-XQMDWXD6.js} +21 -6
  27. package/dist/collab/rebase.d.ts +6 -0
  28. package/dist/collab/rebase.d.ts.map +1 -1
  29. package/dist/collab/rebase.js +12 -3
  30. package/dist/collab/recovery.d.ts +0 -20
  31. package/dist/collab/recovery.d.ts.map +1 -1
  32. package/dist/components/brandguide/ColorSwatchSettings.d.ts.map +1 -1
  33. package/dist/components/brandguide/ColorsView.d.ts.map +1 -1
  34. package/dist/components/brandguide/colors-shared.d.ts +10 -1
  35. package/dist/components/brandguide/colors-shared.d.ts.map +1 -1
  36. package/dist/components/chat/ChatPanel.d.ts.map +1 -1
  37. package/dist/components/docfile/DocFilePane.d.ts.map +1 -1
  38. package/dist/components/docfile/PdfCanvasViewer.d.ts.map +1 -1
  39. package/dist/components/docfile/doc-file-state.d.ts.map +1 -1
  40. package/dist/components/editor/IndicatorPill.d.ts.map +1 -1
  41. package/dist/components/editor/NavGroupRow.d.ts +7 -2
  42. package/dist/components/editor/NavGroupRow.d.ts.map +1 -1
  43. package/dist/components/editor/PagesModal.d.ts.map +1 -1
  44. package/dist/components/editor/index.js +13 -12
  45. package/dist/components/primitives/EditableRichText.d.ts.map +1 -1
  46. package/dist/components/primitives/LinkPopover.d.ts.map +1 -1
  47. package/dist/components/primitives/index.js +14 -12
  48. package/dist/components/primitives/useEditableCollection.d.ts.map +1 -1
  49. package/dist/components/primitives/useEditablePlainText.d.ts.map +1 -1
  50. package/dist/components/sections/IconList/index.d.ts.map +1 -1
  51. package/dist/components/sections/Prose/Prose.d.ts.map +1 -1
  52. package/dist/components/sections/brand-guide.js +8 -8
  53. package/dist/components/sections/register-schemas.js +14 -14
  54. package/dist/components/sections/register.js +14 -14
  55. package/dist/components/shared/FontPicker.d.ts.map +1 -1
  56. package/dist/components/shared/HistoryChangesModal.d.ts.map +1 -1
  57. package/dist/components/shared/HistoryPopover.d.ts.map +1 -1
  58. package/dist/components/shared/Navigation.d.ts.map +1 -1
  59. package/dist/components/shared/Popover.d.ts.map +1 -1
  60. package/dist/components/shell/AudienceAddForm.d.ts +1 -5
  61. package/dist/components/shell/AudienceAddForm.d.ts.map +1 -1
  62. package/dist/components/shell/AudienceRow.d.ts +2 -3
  63. package/dist/components/shell/AudienceRow.d.ts.map +1 -1
  64. package/dist/components/shell/BugReportFAB.d.ts.map +1 -1
  65. package/dist/components/shell/EditorShell.d.ts.map +1 -1
  66. package/dist/components/shell/MediaLibraryModal.d.ts.map +1 -1
  67. package/dist/components/shell/SiteSettingsUsers.d.ts.map +1 -1
  68. package/dist/components/shell/SiteSettingsViewerAccess.d.ts.map +1 -1
  69. package/dist/components/shell/view-branch.d.ts.map +1 -1
  70. package/dist/document/components/DocRail.d.ts.map +1 -1
  71. package/dist/document/components/DocViewer.d.ts.map +1 -1
  72. package/dist/document/components/measure.d.ts.map +1 -1
  73. package/dist/document/components/useDocPages.d.ts.map +1 -1
  74. package/dist/document/engine/blocks.d.ts.map +1 -1
  75. package/dist/document/engine/masonry.d.ts.map +1 -1
  76. package/dist/document/engine/paginate.d.ts.map +1 -1
  77. package/dist/document/engine/settings.d.ts +3 -0
  78. package/dist/document/engine/settings.d.ts.map +1 -1
  79. package/dist/document/index.js +79 -28
  80. package/dist/hooks/useBuildStatus.d.ts.map +1 -1
  81. package/dist/hooks/useDocumentUploads.d.ts +1 -0
  82. package/dist/hooks/useDocumentUploads.d.ts.map +1 -1
  83. package/dist/hooks/useEditorPersistence.d.ts.map +1 -1
  84. package/dist/hooks/useEditorPublish.d.ts.map +1 -1
  85. package/dist/hooks/useFocusTrap.d.ts +6 -0
  86. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  87. package/dist/hooks/useMediaPipeline.d.ts +3 -2
  88. package/dist/hooks/useMediaPipeline.d.ts.map +1 -1
  89. package/dist/hooks/useSanitizedHtml.d.ts +12 -0
  90. package/dist/hooks/useSanitizedHtml.d.ts.map +1 -0
  91. package/dist/index.js +19 -13
  92. package/dist/lib/block-move.d.ts.map +1 -1
  93. package/dist/lib/contrast.d.ts.map +1 -1
  94. package/dist/lib/dexie.d.ts +2 -8
  95. package/dist/lib/dexie.d.ts.map +1 -1
  96. package/dist/lib/dexie.js +21 -49
  97. package/dist/lib/index-ops.d.ts.map +1 -1
  98. package/dist/lib/index-ops.js +43 -23
  99. package/dist/lib/index.js +8 -8
  100. package/dist/lib/loader.d.ts.map +1 -1
  101. package/dist/lib/media-folders.d.ts +12 -4
  102. package/dist/lib/media-folders.d.ts.map +1 -1
  103. package/dist/lib/media-folders.js +12 -2
  104. package/dist/lib/migrate-sections-transform.js +1 -1
  105. package/dist/lib/nav-tree.d.ts.map +1 -1
  106. package/dist/lib/nav.d.ts.map +1 -1
  107. package/dist/lib/pages.d.ts.map +1 -1
  108. package/dist/lib/registry.d.ts.map +1 -1
  109. package/dist/lib/registry.js +1 -1
  110. package/dist/lib/sanitize.d.ts +6 -0
  111. package/dist/lib/sanitize.d.ts.map +1 -1
  112. package/dist/lib/timestamp.d.ts.map +1 -1
  113. package/dist/media/index.js +4 -4
  114. package/dist/media/queue.d.ts.map +1 -1
  115. package/dist/media/resolve.d.ts.map +1 -1
  116. package/dist/media/utils.d.ts.map +1 -1
  117. package/dist/media/videoPoster.d.ts.map +1 -1
  118. package/dist/schemas/audience.d.ts +5 -1
  119. package/dist/schemas/audience.d.ts.map +1 -1
  120. package/dist/schemas/audience.js +1 -1
  121. package/dist/schemas/index.js +8 -6
  122. package/dist/schemas/sections.d.ts +12 -0
  123. package/dist/schemas/sections.d.ts.map +1 -1
  124. package/dist/storage/index.d.ts +1 -1
  125. package/dist/storage/index.d.ts.map +1 -1
  126. package/dist/storage/index.js +3 -1
  127. package/dist/storage/types.d.ts +9 -0
  128. package/dist/storage/types.d.ts.map +1 -1
  129. package/dist/types/database.d.ts +0 -3
  130. package/dist/types/database.d.ts.map +1 -1
  131. package/package.json +1 -1
  132. package/src/auth/cookies.ts +11 -0
  133. package/src/auth/index.ts +1 -1
  134. package/src/auth/types.ts +18 -4
  135. package/src/collab/rebase.ts +26 -1
  136. package/src/collab/recovery.ts +29 -3
  137. package/src/components/brandguide/ColorSwatchSettings.tsx +40 -13
  138. package/src/components/brandguide/ColorsEditable.tsx +7 -9
  139. package/src/components/brandguide/ColorsView.tsx +12 -11
  140. package/src/components/brandguide/colors-shared.ts +17 -1
  141. package/src/components/chat/ChatPanel.tsx +19 -0
  142. package/src/components/docfile/DocFilePane.tsx +11 -0
  143. package/src/components/docfile/PdfCanvasViewer.tsx +46 -5
  144. package/src/components/docfile/doc-file-state.ts +7 -0
  145. package/src/components/editor/IndicatorPill.tsx +5 -1
  146. package/src/components/editor/NavGroupRow.tsx +8 -3
  147. package/src/components/editor/PagesModal.tsx +10 -2
  148. package/src/components/primitives/EditableList.tsx +10 -2
  149. package/src/components/primitives/EditableRichText.tsx +4 -3
  150. package/src/components/primitives/LinkPopover.tsx +23 -1
  151. package/src/components/primitives/useEditableCollection.ts +61 -41
  152. package/src/components/primitives/useEditablePlainText.ts +24 -3
  153. package/src/components/sections/IconList/index.tsx +8 -1
  154. package/src/components/sections/Prose/Prose.tsx +4 -2
  155. package/src/components/shared/FontPicker.tsx +16 -4
  156. package/src/components/shared/HistoryChangesModal.tsx +12 -1
  157. package/src/components/shared/HistoryPopover.tsx +18 -4
  158. package/src/components/shared/Navigation.tsx +20 -2
  159. package/src/components/shared/Popover.tsx +9 -5
  160. package/src/components/shell/AudienceAddForm.tsx +6 -26
  161. package/src/components/shell/AudienceRow.tsx +29 -39
  162. package/src/components/shell/BugReportFAB.tsx +20 -2
  163. package/src/components/shell/EditorShell.tsx +200 -50
  164. package/src/components/shell/MediaLibraryModal.tsx +52 -10
  165. package/src/components/shell/SiteSettingsUsers.tsx +3 -0
  166. package/src/components/shell/SiteSettingsViewerAccess.tsx +21 -16
  167. package/src/components/shell/view-branch.ts +4 -1
  168. package/src/document/components/DocRail.tsx +27 -2
  169. package/src/document/components/DocViewer.tsx +5 -1
  170. package/src/document/components/measure.tsx +22 -6
  171. package/src/document/components/useDocPages.ts +13 -3
  172. package/src/document/engine/blocks.ts +33 -4
  173. package/src/document/engine/masonry.ts +8 -2
  174. package/src/document/engine/paginate.ts +4 -1
  175. package/src/document/engine/settings.ts +40 -3
  176. package/src/hooks/useBuildStatus.ts +6 -0
  177. package/src/hooks/useDocumentUploads.ts +46 -3
  178. package/src/hooks/useEditorPersistence.ts +33 -19
  179. package/src/hooks/useEditorPublish.ts +83 -34
  180. package/src/hooks/useFocusTrap.ts +18 -0
  181. package/src/hooks/useMediaPipeline.ts +111 -38
  182. package/src/hooks/useSanitizedHtml.ts +29 -0
  183. package/src/lib/audience-secret.ts +1 -0
  184. package/src/lib/block-move.ts +13 -2
  185. package/src/lib/contrast.ts +14 -14
  186. package/src/lib/dexie.ts +46 -49
  187. package/src/lib/index-ops.ts +63 -20
  188. package/src/lib/loader.ts +41 -12
  189. package/src/lib/media-folders.ts +31 -5
  190. package/src/lib/migrate-sections-transform.ts +22 -2
  191. package/src/lib/nav-tree.ts +16 -2
  192. package/src/lib/nav.ts +10 -1
  193. package/src/lib/pages.ts +24 -6
  194. package/src/lib/registry.ts +3 -0
  195. package/src/lib/sanitize.ts +9 -0
  196. package/src/lib/timestamp.ts +5 -0
  197. package/src/media/queue.ts +4 -0
  198. package/src/media/resolve.ts +14 -1
  199. package/src/media/utils.ts +3 -1
  200. package/src/media/videoPoster.ts +14 -3
  201. package/src/schemas/audience.ts +10 -2
  202. package/src/schemas/sections.ts +23 -1
  203. package/src/storage/index.ts +1 -1
  204. package/src/storage/types.ts +13 -0
  205. package/src/types/database.ts +0 -3
@@ -12,15 +12,20 @@ export function formatDate(iso: string): string {
12
12
 
13
13
  export function formatDateTime(iso: string): string {
14
14
  const date = new Date(iso);
15
+ // UTC-pinned like its two siblings: without it the server (UTC) and the client
16
+ // (local) render different values for the same timestamp, which is a hydration
17
+ // mismatch wherever this reaches SSR output.
15
18
  const datePart = date.toLocaleDateString("en-US", {
16
19
  month: "short",
17
20
  day: "numeric",
18
21
  year: "numeric",
22
+ timeZone: "UTC",
19
23
  });
20
24
  const timePart = date.toLocaleTimeString("en-US", {
21
25
  hour: "numeric",
22
26
  minute: "2-digit",
23
27
  hour12: true,
28
+ timeZone: "UTC",
24
29
  });
25
30
  return `${datePart} | ${timePart}`;
26
31
  }
@@ -118,6 +118,10 @@ export class ProcessingQueue {
118
118
  height: msg.height,
119
119
  };
120
120
  this.options.onEvent({ type: "complete", item: { ...item } });
121
+ // The event above carries the only reference anyone reads. Holding ours
122
+ // pinned every variant Blob of every completed upload — the full decoded
123
+ // output of the whole session — for the queue's lifetime.
124
+ delete item.result;
121
125
  this.cleanupWorker(id, worker);
122
126
  this.processNext();
123
127
  } else if (msg.type === "error") {
@@ -37,6 +37,19 @@ export function resolveManifestReferences(
37
37
  if (typeof obj.imageId === "string") {
38
38
  const manifestItem = manifest.images[obj.imageId];
39
39
  const resolved = resolveMedia({ imageId: obj.imageId }, manifest, sizes, provider);
40
+ // Recurse into this object's own values first. Returning straight from
41
+ // here left any ref nested INSIDE a ref-carrying object unresolved.
42
+ const base: Record<string, unknown> = {};
43
+ for (const [key, value] of Object.entries(obj)) {
44
+ base[key] = resolveManifestReferences(value, manifest, sizes, provider);
45
+ }
46
+ if (!resolved) {
47
+ // The item is gone from the manifest. Drop the baked fields instead of
48
+ // leaving the previous item's `src` pointing at an asset that no longer
49
+ // exists — a deleted image kept rendering until someone hit the 404.
50
+ for (const key of BAKED_MEDIA_KEYS) delete base[key];
51
+ return { ...base, alt: manifestItem?.alt ?? "" };
52
+ }
40
53
  const patch: Record<string, unknown> = {
41
54
  alt: manifestItem?.alt ?? "",
42
55
  };
@@ -55,7 +68,7 @@ export function resolveManifestReferences(
55
68
  patch.width = resolved.width;
56
69
  patch.height = resolved.height;
57
70
  }
58
- return { ...obj, ...patch };
71
+ return { ...base, ...patch };
59
72
  }
60
73
 
61
74
  // Recurse into all values
@@ -57,7 +57,9 @@ export function displayFilename(originalName: string, mimeType: string): string
57
57
  const ext = MIME_TO_EXT[mimeType];
58
58
  if (!ext) return originalName;
59
59
  const suffix = `.${ext}`;
60
- if (originalName.endsWith(suffix)) return originalName;
60
+ // Case-insensitively: extensions come off the user's filesystem, so a
61
+ // case-sensitive check rendered "Logo.PNG" as "Logo.PNG.png".
62
+ if (originalName.toLowerCase().endsWith(suffix)) return originalName;
61
63
  return `${originalName}${suffix}`;
62
64
  }
63
65
 
@@ -34,7 +34,7 @@ export function generateVideoPoster(
34
34
  video.src = url;
35
35
 
36
36
  video.addEventListener("loadeddata", () => {
37
- video.addEventListener("seeked", () => {
37
+ const capture = () => {
38
38
  if (settled) return;
39
39
  try {
40
40
  const w = video.videoWidth;
@@ -67,8 +67,19 @@ export function generateVideoPoster(
67
67
  } catch (err) {
68
68
  safeReject(err instanceof Error ? err : new Error(String(err)));
69
69
  }
70
- }, { once: true });
71
- video.currentTime = isFinite(video.duration) ? Math.min(0.1, video.duration / 2) : 0;
70
+ };
71
+
72
+ const target = isFinite(video.duration) ? Math.min(0.1, video.duration / 2) : 0;
73
+ // Assigning currentTime a value it ALREADY holds fires no `seeked` — the
74
+ // common case for a 0-duration or already-at-0 decode. Waiting for the
75
+ // event then stalled the full 10s timeout, and the rejection that followed
76
+ // is what produced a 0x0 media item.
77
+ if (video.currentTime === target) {
78
+ capture();
79
+ return;
80
+ }
81
+ video.addEventListener("seeked", capture, { once: true });
82
+ video.currentTime = target;
72
83
  }, { once: true });
73
84
  });
74
85
  }
@@ -70,11 +70,19 @@ export type ViewerCredential = z.infer<typeof ViewerCredentialSchema>;
70
70
  /**
71
71
  * Convert a friendly display string into an audience slug.
72
72
  * Lowercases, replaces non-alphanumeric runs with single dashes,
73
- * strips leading/trailing dashes. Result must pass AudienceNameSchema.
73
+ * strips leading/trailing dashes, truncates to the schema's 32-char max.
74
+ * Result must pass AudienceNameSchema.
75
+ *
76
+ * Kept byte-for-byte equivalent to @drawnagency/platform's copy
77
+ * (src/slugify.ts) — change both together.
74
78
  */
75
79
  export function slugifyAudienceName(input: string): string {
76
80
  return input
77
81
  .toLowerCase()
78
82
  .replace(/[^a-z0-9]+/g, "-")
79
- .replace(/^-+|-+$/g, "");
83
+ .replace(/^-+|-+$/g, "")
84
+ // Trim the trailing separator again: slicing can land mid-word and leave
85
+ // one, which AudienceNameSchema forbids as a final character.
86
+ .slice(0, 32)
87
+ .replace(/-+$/g, "");
80
88
  }
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { getAllSchemas } from "../lib/registry";
2
+ import { getAllSchemas, getSchema } from "../lib/registry";
3
3
  import { LayoutEnvelopeSchema, type LayoutEnvelope } from "./block";
4
4
 
5
5
  export interface SectionContent<C = Record<string, unknown>> {
@@ -26,3 +26,25 @@ export function getSectionSchema(): z.ZodType<Section> {
26
26
  .object({ id: z.string(), layout: LayoutEnvelopeSchema.optional() })
27
27
  .and(getSectionContentSchema()) as z.ZodType<Section>;
28
28
  }
29
+
30
+ /**
31
+ * The single-type equivalent of `getSectionSchema()`, for callers that already
32
+ * know a section's `type`. Returns null for an unregistered type — the same
33
+ * outcome the union produces, since no member would match.
34
+ *
35
+ * Prefer this in loops. The union in `getSectionContentSchema()` validates its
36
+ * members in order and fully validates every miss, so parsing N sections
37
+ * against M registered types costs O(N x M) object validations; every section
38
+ * schema pins `type: z.literal(...)`, so a registry lookup selects exactly the
39
+ * member the union would have matched.
40
+ */
41
+ export function getSectionSchemaForType(type: string): z.ZodType<Section> | null {
42
+ const schema = getSchema(type);
43
+ if (!schema) return null;
44
+ // `getSchema` is typed as a bare ZodType, so the intersection doesn't overlap
45
+ // Section structurally — same widening `getSectionSchema` gets for free from
46
+ // getSectionContentSchema's annotated return.
47
+ return z
48
+ .object({ id: z.string(), layout: LayoutEnvelopeSchema.optional() })
49
+ .and(schema) as unknown as z.ZodType<Section>;
50
+ }
@@ -1,2 +1,2 @@
1
1
  export type { StorageProvider, FileWrite, AssetStore, DocumentStore } from "./types";
2
- export { StorageConflictError, IdempotencyLookupUnavailableError, ASSET_CACHE_CONTROL, DOCUMENT_CACHE_CONTROL, IDEMPOTENCY_TRAILER, IDEMPOTENCY_KEY_RE, withIdempotencyTrailer } from "./types";
2
+ export { StorageConflictError, NothingToPublishError, IdempotencyLookupUnavailableError, ASSET_CACHE_CONTROL, DOCUMENT_CACHE_CONTROL, IDEMPOTENCY_TRAILER, IDEMPOTENCY_KEY_RE, withIdempotencyTrailer } from "./types";
@@ -11,6 +11,19 @@ export class StorageConflictError extends Error {
11
11
  }
12
12
  }
13
13
 
14
+ /**
15
+ * Thrown by `promoteDraft` when there is no draft to publish. Typed rather than
16
+ * a bare Error because it is the ordinary outcome of publishing twice, and a
17
+ * caller that cannot tell it apart from a real failure reports "publish failed"
18
+ * for a site that is already fully published.
19
+ */
20
+ export class NothingToPublishError extends Error {
21
+ constructor() {
22
+ super("No saved branch to publish");
23
+ this.name = "NothingToPublishError";
24
+ }
25
+ }
26
+
14
27
  export interface StorageProvider {
15
28
  writeFiles(
16
29
  files: FileWrite[],
@@ -674,7 +674,6 @@ export type Database = {
674
674
  id: string
675
675
  is_default: boolean
676
676
  name: string
677
- password_hash: string
678
677
  site_id: string
679
678
  }
680
679
  Insert: {
@@ -684,7 +683,6 @@ export type Database = {
684
683
  id?: string
685
684
  is_default?: boolean
686
685
  name: string
687
- password_hash: string
688
686
  site_id: string
689
687
  }
690
688
  Update: {
@@ -694,7 +692,6 @@ export type Database = {
694
692
  id?: string
695
693
  is_default?: boolean
696
694
  name?: string
697
- password_hash?: string
698
695
  site_id?: string
699
696
  }
700
697
  Relationships: [