@drawnagency/primitives 0.1.95 → 0.1.97

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 (86) hide show
  1. package/dist/{chunk-ZKGMLLUQ.js → chunk-5BFPJWIO.js} +5 -5
  2. package/dist/chunk-EUSWEVOA.js +29 -0
  3. package/dist/{chunk-CI624HRS.js → chunk-F2337B35.js} +1 -1
  4. package/dist/{chunk-QQBBYQYD.js → chunk-FOEZNEF5.js} +9 -9
  5. package/dist/chunk-HJSE6SK5.js +27 -0
  6. package/dist/{chunk-YUUUCDXN.js → chunk-II3X7GLJ.js} +1 -1
  7. package/dist/{chunk-DJAJRBPD.js → chunk-KPP2CFW6.js} +2 -2
  8. package/dist/{chunk-ABV7OZB3.js → chunk-QEHPGA5N.js} +26 -8
  9. package/dist/{chunk-SOILPZ7U.js → chunk-S4L3ZFKM.js} +1 -1
  10. package/dist/{chunk-RQPHPAT2.js → chunk-YDXBJR74.js} +2 -2
  11. package/dist/chunk-ZD6XGRQM.js +85 -0
  12. package/dist/collab/rebase.d.ts +20 -0
  13. package/dist/collab/rebase.d.ts.map +1 -1
  14. package/dist/collab/rebase.js +17 -0
  15. package/dist/components/editor/DropEdgeIndicator.d.ts +6 -1
  16. package/dist/components/editor/DropEdgeIndicator.d.ts.map +1 -1
  17. package/dist/components/editor/NavGroupRow.d.ts +21 -0
  18. package/dist/components/editor/NavGroupRow.d.ts.map +1 -0
  19. package/dist/components/editor/PagesModal.d.ts +7 -1
  20. package/dist/components/editor/PagesModal.d.ts.map +1 -1
  21. package/dist/components/editor/index.js +4 -4
  22. package/dist/components/primitives/index.js +7 -7
  23. package/dist/components/sections/brand-guide.js +6 -6
  24. package/dist/components/sections/register-schemas.js +10 -10
  25. package/dist/components/sections/register.js +10 -10
  26. package/dist/components/shared/Navigation.d.ts.map +1 -1
  27. package/dist/components/shell/EditorShell.d.ts.map +1 -1
  28. package/dist/hooks/useSortableNavRow.d.ts +27 -0
  29. package/dist/hooks/useSortableNavRow.d.ts.map +1 -0
  30. package/dist/index.js +60 -38
  31. package/dist/lib/dexie.d.ts.map +1 -1
  32. package/dist/lib/dexie.js +3 -1
  33. package/dist/lib/index-ops.d.ts +77 -0
  34. package/dist/lib/index-ops.d.ts.map +1 -0
  35. package/dist/lib/index-ops.js +223 -0
  36. package/dist/lib/index.d.ts +1 -0
  37. package/dist/lib/index.d.ts.map +1 -1
  38. package/dist/lib/index.js +17 -6
  39. package/dist/lib/loader.d.ts +2 -2
  40. package/dist/lib/loader.d.ts.map +1 -1
  41. package/dist/lib/nav-tree.d.ts +63 -0
  42. package/dist/lib/nav-tree.d.ts.map +1 -0
  43. package/dist/lib/nav.d.ts +13 -2
  44. package/dist/lib/nav.d.ts.map +1 -1
  45. package/dist/lib/pages.d.ts +0 -1
  46. package/dist/lib/pages.d.ts.map +1 -1
  47. package/dist/lib/reorder.d.ts +24 -0
  48. package/dist/lib/reorder.d.ts.map +1 -1
  49. package/dist/media/index.js +2 -2
  50. package/dist/schemas/index.d.ts +1 -0
  51. package/dist/schemas/index.d.ts.map +1 -1
  52. package/dist/schemas/index.js +8 -2
  53. package/dist/schemas/nav.d.ts +40 -0
  54. package/dist/schemas/nav.d.ts.map +1 -0
  55. package/dist/schemas/site-config.d.ts +11 -1
  56. package/dist/schemas/site-config.d.ts.map +1 -1
  57. package/dist/storage/index.d.ts +1 -1
  58. package/dist/storage/index.d.ts.map +1 -1
  59. package/dist/storage/index.js +9 -3
  60. package/dist/storage/types.d.ts +44 -0
  61. package/dist/storage/types.d.ts.map +1 -1
  62. package/package.json +5 -1
  63. package/src/collab/rebase.ts +35 -0
  64. package/src/components/editor/DropEdgeIndicator.tsx +15 -8
  65. package/src/components/editor/NavGroupRow.tsx +126 -0
  66. package/src/components/editor/PagesModal.tsx +150 -29
  67. package/src/components/shared/Navigation.tsx +51 -13
  68. package/src/components/shell/EditorShell.tsx +40 -10
  69. package/src/hooks/useSortableNavRow.ts +139 -0
  70. package/src/lib/dexie.ts +6 -1
  71. package/src/lib/index-ops.ts +309 -0
  72. package/src/lib/index.ts +1 -0
  73. package/src/lib/loader.ts +31 -4
  74. package/src/lib/nav-tree.ts +192 -0
  75. package/src/lib/nav.ts +43 -10
  76. package/src/lib/pages.ts +14 -11
  77. package/src/lib/reorder.ts +56 -0
  78. package/src/schemas/index.ts +1 -0
  79. package/src/schemas/nav.ts +36 -0
  80. package/src/schemas/site-config.ts +9 -1
  81. package/src/storage/index.ts +1 -1
  82. package/src/storage/types.ts +55 -0
  83. package/dist/chunk-VAOW4WXQ.js +0 -15
  84. package/dist/chunk-YBVK254P.js +0 -14
  85. /package/dist/{chunk-53DKVAB6.js → chunk-72CG6AA2.js} +0 -0
  86. /package/dist/{chunk-3HJDMFTB.js → chunk-XYCCXKVC.js} +0 -0
@@ -9,13 +9,13 @@ import {
9
9
  MediaBlock,
10
10
  containerGridClass,
11
11
  useEditableCollection
12
- } from "./chunk-DJAJRBPD.js";
12
+ } from "./chunk-KPP2CFW6.js";
13
13
  import {
14
14
  AddIcon,
15
15
  DeleteIcon,
16
16
  DragHandle,
17
17
  IconButton
18
- } from "./chunk-CI624HRS.js";
18
+ } from "./chunk-F2337B35.js";
19
19
  import {
20
20
  DEFAULT_LINK,
21
21
  LinkValueSchema
@@ -27,13 +27,13 @@ import {
27
27
  import {
28
28
  cn
29
29
  } from "./chunk-7EOSDFS3.js";
30
+ import {
31
+ defineSection
32
+ } from "./chunk-VKAGMEKE.js";
30
33
  import {
31
34
  HexColorSchema,
32
35
  SingleMediaReferenceSchema
33
36
  } from "./chunk-RHWWQV3J.js";
34
- import {
35
- defineSection
36
- } from "./chunk-VKAGMEKE.js";
37
37
 
38
38
  // src/components/sections/Colors/index.tsx
39
39
  import { z as z2 } from "zod";
@@ -0,0 +1,29 @@
1
+ // src/storage/types.ts
2
+ var StorageConflictError = class extends Error {
3
+ constructor(currentVersion) {
4
+ super("Draft has been modified since it was loaded");
5
+ this.currentVersion = currentVersion;
6
+ this.name = "StorageConflictError";
7
+ }
8
+ currentVersion;
9
+ };
10
+ var IDEMPOTENCY_TRAILER = "Idempotency-Key";
11
+ var IDEMPOTENCY_KEY_RE = /^[A-Za-z0-9._:-]{8,200}$/;
12
+ function withIdempotencyTrailer(subject, key) {
13
+ if (!key) return subject;
14
+ if (!IDEMPOTENCY_KEY_RE.test(key)) {
15
+ throw new Error("Invalid idempotency key: expected 8-200 chars of A-Za-z0-9._:-");
16
+ }
17
+ return `${subject}
18
+
19
+ ${IDEMPOTENCY_TRAILER}: ${key}`;
20
+ }
21
+ var ASSET_CACHE_CONTROL = "max-age=31536000, immutable";
22
+
23
+ export {
24
+ StorageConflictError,
25
+ IDEMPOTENCY_TRAILER,
26
+ IDEMPOTENCY_KEY_RE,
27
+ withIdempotencyTrailer,
28
+ ASSET_CACHE_CONTROL
29
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getMediaProvider
3
- } from "./chunk-SOILPZ7U.js";
3
+ } from "./chunk-S4L3ZFKM.js";
4
4
  import {
5
5
  cn
6
6
  } from "./chunk-7EOSDFS3.js";
@@ -3,7 +3,7 @@ import {
3
3
  pluralize,
4
4
  stripHtmlToPlainText,
5
5
  truncate
6
- } from "./chunk-ZKGMLLUQ.js";
6
+ } from "./chunk-5BFPJWIO.js";
7
7
  import {
8
8
  DeleteButton,
9
9
  DragHandle,
@@ -17,11 +17,11 @@ import {
17
17
  buildBlockDropData,
18
18
  canDropBlock,
19
19
  isBlockDragData
20
- } from "./chunk-YUUUCDXN.js";
20
+ } from "./chunk-II3X7GLJ.js";
21
21
  import {
22
22
  EditableRichText,
23
23
  defineHeadingSection
24
- } from "./chunk-RQPHPAT2.js";
24
+ } from "./chunk-YDXBJR74.js";
25
25
  import {
26
26
  EditablePlainText,
27
27
  ImageDropZone,
@@ -31,11 +31,11 @@ import {
31
31
  containerGridClass,
32
32
  masonryColumnsClass,
33
33
  spacerHiddenClass
34
- } from "./chunk-DJAJRBPD.js";
34
+ } from "./chunk-KPP2CFW6.js";
35
35
  import {
36
36
  useMediaLibrary,
37
37
  useResolvedMedia
38
- } from "./chunk-CI624HRS.js";
38
+ } from "./chunk-F2337B35.js";
39
39
  import {
40
40
  embedUrl
41
41
  } from "./chunk-Y4JQGO6G.js";
@@ -45,20 +45,20 @@ import {
45
45
  } from "./chunk-PZJL2S3Z.js";
46
46
  import {
47
47
  sanitizeHtml
48
- } from "./chunk-53DKVAB6.js";
48
+ } from "./chunk-72CG6AA2.js";
49
49
  import {
50
50
  cn
51
51
  } from "./chunk-7EOSDFS3.js";
52
52
  import {
53
53
  getSectionSchema
54
54
  } from "./chunk-TZQPOR5A.js";
55
- import {
56
- SingleMediaReferenceSchema
57
- } from "./chunk-RHWWQV3J.js";
58
55
  import {
59
56
  defineSection,
60
57
  getSection
61
58
  } from "./chunk-VKAGMEKE.js";
59
+ import {
60
+ SingleMediaReferenceSchema
61
+ } from "./chunk-RHWWQV3J.js";
62
62
 
63
63
  // src/components/sections/LinkHeading/index.tsx
64
64
  import { Heading1 } from "lucide-react";
@@ -0,0 +1,27 @@
1
+ // src/schemas/nav.ts
2
+ import { z } from "zod";
3
+ var NavEntrySchema = z.discriminatedUnion("kind", [
4
+ z.object({
5
+ kind: z.literal("page"),
6
+ pageId: z.string().min(1)
7
+ }),
8
+ z.object({
9
+ kind: z.literal("group"),
10
+ id: z.string().min(1),
11
+ /** May be blank — agent-authored files can omit it; UI falls back to "Untitled group". */
12
+ label: z.string().default(""),
13
+ startCollapsed: z.boolean().default(false),
14
+ // Everything but `id` defaults: NavFileSchema is all-or-nothing, and the
15
+ // loader degrades a failed parse to a flat nav — so one agent-authored group
16
+ // missing a key would silently discard every group on the site.
17
+ pageIds: z.array(z.string().min(1)).default([])
18
+ })
19
+ ]);
20
+ var NavFileSchema = z.object({
21
+ entries: z.array(NavEntrySchema)
22
+ });
23
+
24
+ export {
25
+ NavEntrySchema,
26
+ NavFileSchema
27
+ };
@@ -14,7 +14,7 @@ import {
14
14
  SettingsIcon,
15
15
  useMediaLibrary,
16
16
  useResolvedMedia
17
- } from "./chunk-CI624HRS.js";
17
+ } from "./chunk-F2337B35.js";
18
18
  import {
19
19
  cn
20
20
  } from "./chunk-7EOSDFS3.js";
@@ -6,10 +6,10 @@ import {
6
6
  SettingsIcon,
7
7
  useMediaLibrary,
8
8
  useResolvedMedia
9
- } from "./chunk-CI624HRS.js";
9
+ } from "./chunk-F2337B35.js";
10
10
  import {
11
11
  rebindImageRef
12
- } from "./chunk-SOILPZ7U.js";
12
+ } from "./chunk-S4L3ZFKM.js";
13
13
  import {
14
14
  cn
15
15
  } from "./chunk-7EOSDFS3.js";
@@ -4,15 +4,18 @@ import {
4
4
  import {
5
5
  upgradeLegacySection
6
6
  } from "./chunk-5BM2Y3NJ.js";
7
+ import {
8
+ NavFileSchema
9
+ } from "./chunk-HJSE6SK5.js";
7
10
  import {
8
11
  getSectionSchema
9
12
  } from "./chunk-TZQPOR5A.js";
10
- import {
11
- IndexSchema
12
- } from "./chunk-RHWWQV3J.js";
13
13
  import {
14
14
  getAllSchemas
15
15
  } from "./chunk-VKAGMEKE.js";
16
+ import {
17
+ IndexSchema
18
+ } from "./chunk-RHWWQV3J.js";
16
19
  import {
17
20
  MAX_BLOCK_DEPTH,
18
21
  blockDepth
@@ -149,7 +152,16 @@ function safeRedirect(url, fallback) {
149
152
  }
150
153
 
151
154
  // src/lib/loader.ts
152
- function mergeSiteContent(index, sectionFiles) {
155
+ function parseNavFile(navFile) {
156
+ if (!navFile) return [];
157
+ const result = NavFileSchema.safeParse(navFile);
158
+ if (!result.success) {
159
+ console.warn("Invalid nav.json, falling back to a flat navigation");
160
+ return [];
161
+ }
162
+ return result.data.entries;
163
+ }
164
+ function mergeSiteContent(index, sectionFiles, navFile) {
153
165
  const sections = [];
154
166
  const canValidate = getAllSchemas().length >= 2;
155
167
  const schema = canValidate ? getSectionSchema() : null;
@@ -180,16 +192,16 @@ function mergeSiteContent(index, sectionFiles) {
180
192
  sections.push({ section: raw, meta });
181
193
  }
182
194
  }
183
- return { sections, index };
195
+ return { sections, index: { ...index, nav: parseNavFile(navFile) } };
184
196
  }
185
- function loadStaticSiteContent(index, sectionGlob) {
197
+ function loadStaticSiteContent(index, sectionGlob, navFile) {
186
198
  const sectionFiles = {};
187
199
  for (const [path, data] of Object.entries(sectionGlob)) {
188
200
  const filename = path.split("/").pop();
189
201
  const id = filename.replace(".json", "");
190
202
  sectionFiles[id] = data;
191
203
  }
192
- return mergeSiteContent(index, sectionFiles);
204
+ return mergeSiteContent(index, sectionFiles, navFile);
193
205
  }
194
206
  async function loadSiteContent(contentDir) {
195
207
  const fs = await import("fs/promises");
@@ -202,7 +214,13 @@ async function loadSiteContent(contentDir) {
202
214
  const sectionPath = path.join(contentDir, "sections", `${id}.json`);
203
215
  sectionFiles[id] = JSON.parse(await fs.readFile(sectionPath, "utf-8"));
204
216
  }
205
- return mergeSiteContent(index, sectionFiles);
217
+ let navFile;
218
+ try {
219
+ navFile = JSON.parse(await fs.readFile(path.join(contentDir, "nav.json"), "utf-8"));
220
+ } catch {
221
+ navFile = void 0;
222
+ }
223
+ return mergeSiteContent(index, sectionFiles, navFile);
206
224
  }
207
225
 
208
226
  export {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  slugifyPageSlug
3
- } from "./chunk-YBVK254P.js";
3
+ } from "./chunk-ZD6XGRQM.js";
4
4
 
5
5
  // src/media/utils.ts
6
6
  async function hashFileBuffer(buffer) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  EditablePlainText
3
- } from "./chunk-DJAJRBPD.js";
3
+ } from "./chunk-KPP2CFW6.js";
4
4
  import {
5
5
  Button,
6
6
  usePages
@@ -8,7 +8,7 @@ import {
8
8
  import {
9
9
  sanitizeHtml,
10
10
  toSectionId
11
- } from "./chunk-53DKVAB6.js";
11
+ } from "./chunk-72CG6AA2.js";
12
12
  import {
13
13
  cn
14
14
  } from "./chunk-7EOSDFS3.js";
@@ -0,0 +1,85 @@
1
+ // src/lib/nav-tree.ts
2
+ function reconcileNav(entries, pages) {
3
+ const entryList = Array.isArray(entries) ? entries : [];
4
+ const pageList = Array.isArray(pages) ? pages : [];
5
+ const validIds = /* @__PURE__ */ new Set();
6
+ for (const p of pageList) {
7
+ if (p?.id) validIds.add(p.id);
8
+ }
9
+ const placed = /* @__PURE__ */ new Set();
10
+ const seenGroupIds = /* @__PURE__ */ new Set();
11
+ const result = [];
12
+ for (const entry of entryList) {
13
+ if (entry?.kind === "page") {
14
+ if (!validIds.has(entry.pageId) || placed.has(entry.pageId)) continue;
15
+ placed.add(entry.pageId);
16
+ result.push({ ...entry });
17
+ continue;
18
+ }
19
+ if (entry?.kind !== "group") continue;
20
+ if (seenGroupIds.has(entry.id)) continue;
21
+ seenGroupIds.add(entry.id);
22
+ const claimed = Array.isArray(entry.pageIds) ? entry.pageIds : [];
23
+ const pageIds = claimed.filter((id) => {
24
+ if (!validIds.has(id) || placed.has(id)) return false;
25
+ placed.add(id);
26
+ return true;
27
+ });
28
+ const group = { ...entry, pageIds };
29
+ result.push(group);
30
+ }
31
+ for (const p of pageList) {
32
+ if (!p?.id || placed.has(p.id)) continue;
33
+ placed.add(p.id);
34
+ result.push({ kind: "page", pageId: p.id });
35
+ }
36
+ return result;
37
+ }
38
+ function navEntries(index) {
39
+ return reconcileNav(index.nav ?? [], index.pages);
40
+ }
41
+ function pagesInNavOrder(index) {
42
+ const byId = new Map(index.pages.map((p) => [p.id, p]));
43
+ const out = [];
44
+ for (const entry of navEntries(index)) {
45
+ if (entry.kind === "page") {
46
+ const p = byId.get(entry.pageId);
47
+ if (p) out.push(p);
48
+ } else {
49
+ for (const id of entry.pageIds) {
50
+ const p = byId.get(id);
51
+ if (p) out.push(p);
52
+ }
53
+ }
54
+ }
55
+ return out;
56
+ }
57
+ function groupOfPage(index, pageId) {
58
+ for (const entry of navEntries(index)) {
59
+ if (entry.kind === "group" && entry.pageIds.includes(pageId)) return entry;
60
+ }
61
+ return null;
62
+ }
63
+ function groupDisplayLabel(label) {
64
+ return label || "Untitled group";
65
+ }
66
+
67
+ // src/lib/pages.ts
68
+ function slugifyPageSlug(input) {
69
+ return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
70
+ }
71
+ function audiencePasses(access, audience) {
72
+ if (access.length === 0) return true;
73
+ if (!audience) return true;
74
+ return access.includes(audience);
75
+ }
76
+
77
+ export {
78
+ reconcileNav,
79
+ navEntries,
80
+ pagesInNavOrder,
81
+ groupOfPage,
82
+ groupDisplayLabel,
83
+ slugifyPageSlug,
84
+ audiencePasses
85
+ };
@@ -56,5 +56,25 @@ export interface RebaseResult {
56
56
  * caller-computed id set, is deliberate: it makes passing the loaded-bodies set
57
57
  * (the original bug) unrepresentable. Neither input is mutated. */
58
58
  export declare function reconcileRemoteIndex(remoteIndex: SiteIndex, localIndex: SiteIndex): SiteIndex;
59
+ /** Parse a peer's raw live-index broadcast and fold it under ours — the whole
60
+ * `onRemoteIndexUpdate` transform, kept here rather than in the handler so the
61
+ * nav-preservation step below cannot be lost to a future refactor of the shell.
62
+ * Returns null when the payload is not a valid index (caller ignores the
63
+ * message).
64
+ *
65
+ * The `nav` lift is load-bearing and mirrors content-ops' write path.
66
+ * `IndexSchema` STRIPS unknown keys — that strip is what guarantees nav never
67
+ * reaches index.json — so parsing a peer's index without lifting nav off first
68
+ * yields a nav-less index. Installing that flattens the local sidebar, and
69
+ * since every structural mutation materializes a full nav from `navEntries()`,
70
+ * the next local page/group edit would save a flat nav.json and delete every
71
+ * group on the site. Silent, and reachable from an ordinary two-editor session.
72
+ *
73
+ * Nav entries address PAGES, which `reconcileRemoteIndex`'s section-id prune
74
+ * never touches, so the peer's nav transfers whole; readers go through
75
+ * `navEntries()` → `reconcileNav`, which repairs any drift against the
76
+ * resulting page set. A peer that sends no nav (an older client) leaves ours
77
+ * intact rather than flattening it. */
78
+ export declare function applyRemoteIndexUpdate(rawRemoteIndex: unknown, localIndex: SiteIndex): SiteIndex | null;
59
79
  export declare function rebaseContent(args: RebaseArgs): RebaseResult;
60
80
  //# sourceMappingURL=rebase.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rebase.d.ts","sourceRoot":"","sources":["../../src/collab/rebase.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,aAAa,EAAE,CAAC;IAC/B,UAAU,EAAE,SAAS,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B;;;;;+EAK2E;IAC3E,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,iBAAiB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,WAAW,EAAE,SAAS,CAAC;IAKvB,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,KAAK,EAAE,SAAS,CAAC;IAIjB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;;;;;;qEAUqE;AACrE;;;;;;;;;;;;;;;;;;;;;oEAqBoE;AACpE,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,GAAG,SAAS,CAS7F;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,YAAY,CA2F5D"}
1
+ {"version":3,"file":"rebase.d.ts","sourceRoot":"","sources":["../../src/collab/rebase.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAIxD,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,aAAa,EAAE,CAAC;IAC/B,UAAU,EAAE,SAAS,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B;;;;;+EAK2E;IAC3E,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,iBAAiB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,WAAW,EAAE,SAAS,CAAC;IAKvB,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,KAAK,EAAE,SAAS,CAAC;IAIjB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;;;;;;qEAUqE;AACrE;;;;;;;;;;;;;;;;;;;;;oEAqBoE;AACpE,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,GAAG,SAAS,CAS7F;AAED;;;;;;;;;;;;;;;;;;wCAkBwC;AACxC,wBAAgB,sBAAsB,CAAC,cAAc,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,GAAG,SAAS,GAAG,IAAI,CAYvG;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,YAAY,CA2F5D"}
@@ -1,3 +1,10 @@
1
+ import {
2
+ NavFileSchema
3
+ } from "../chunk-HJSE6SK5.js";
4
+ import {
5
+ IndexSchema
6
+ } from "../chunk-RHWWQV3J.js";
7
+ import "../chunk-FM4M4Q2W.js";
1
8
  import "../chunk-JSBRDJBE.js";
2
9
 
3
10
  // src/collab/rebase.ts
@@ -11,6 +18,15 @@ function reconcileRemoteIndex(remoteIndex, localIndex) {
11
18
  )
12
19
  };
13
20
  }
21
+ function applyRemoteIndexUpdate(rawRemoteIndex, localIndex) {
22
+ const rawNav = rawRemoteIndex?.nav;
23
+ const parsed = IndexSchema.safeParse(rawRemoteIndex);
24
+ if (!parsed.success) return null;
25
+ const parsedNav = rawNav === void 0 ? null : NavFileSchema.safeParse({ entries: rawNav });
26
+ const nav = parsedNav?.success ? parsedNav.data.entries : localIndex.nav;
27
+ const reconciled = reconcileRemoteIndex(parsed.data, localIndex);
28
+ return nav !== void 0 ? { ...reconciled, nav } : reconciled;
29
+ }
14
30
  function rebaseContent(args) {
15
31
  const localById = new Map(args.localSections.map((s) => [s.section.id, s]));
16
32
  const remoteIds = new Set(args.remoteSections.map((s) => s.section.id));
@@ -70,6 +86,7 @@ function rebaseContent(args) {
70
86
  return { sections: merged, index, conflictIds };
71
87
  }
72
88
  export {
89
+ applyRemoteIndexUpdate,
73
90
  rebaseContent,
74
91
  reconcileRemoteIndex
75
92
  };
@@ -1,8 +1,13 @@
1
1
  /**
2
2
  * The horizontal insertion line shown at the top or bottom edge of a row during
3
3
  * a closest-edge drag-to-reorder, paired with `useSortableRow`'s `closestEdge`.
4
+ *
5
+ * `inset` starts the line at the nested-row indent, which is the ONLY thing
6
+ * distinguishing "drop inside this group" from "drop before this group" — and
7
+ * a group's last member slot from the top-level slot that follows it.
4
8
  */
5
- export declare function DropEdgeIndicator({ edge }: {
9
+ export declare function DropEdgeIndicator({ edge, inset }: {
6
10
  edge: "top" | "bottom" | null;
11
+ inset?: boolean;
7
12
  }): import("react/jsx-runtime").JSX.Element | null;
8
13
  //# sourceMappingURL=DropEdgeIndicator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DropEdgeIndicator.d.ts","sourceRoot":"","sources":["../../../src/components/editor/DropEdgeIndicator.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,IAAI,CAAA;CAAE,kDAQ5E"}
1
+ {"version":3,"file":"DropEdgeIndicator.d.ts","sourceRoot":"","sources":["../../../src/components/editor/DropEdgeIndicator.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,IAAI,EAAE,KAAa,EAAE,EAAE;IAAE,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,kDAW5G"}
@@ -0,0 +1,21 @@
1
+ import type { NavGroupEntry } from "../../schemas/nav";
2
+ import type { NavLocation } from "../../lib/nav-tree";
3
+ interface Props {
4
+ group: NavGroupEntry;
5
+ entryIndex: number;
6
+ memberCount: number;
7
+ /** Opens the settings panel on mount. The `+ Add group` flow sets this so a
8
+ * brand-new group lands with its label input focused. */
9
+ autoOpenSettings?: boolean;
10
+ onRename: (label: string) => void;
11
+ onSetStartCollapsed: (v: boolean) => void;
12
+ onDelete: () => void;
13
+ onMove: (from: NavLocation, to: NavLocation) => void;
14
+ /** Fires when THIS group starts/stops being dragged, so the modal can collapse
15
+ * it for the duration. Without that, its members stay rendered in place and
16
+ * the drag reads as moving only the header. */
17
+ onDragStateChange?: (dragging: boolean) => void;
18
+ }
19
+ export declare function NavGroupRow({ group, entryIndex, memberCount, autoOpenSettings, onRename, onSetStartCollapsed, onDelete, onMove, onDragStateChange, }: Props): import("react/jsx-runtime").JSX.Element;
20
+ export {};
21
+ //# sourceMappingURL=NavGroupRow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NavGroupRow.d.ts","sourceRoot":"","sources":["../../../src/components/editor/NavGroupRow.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAWtD,UAAU,KAAK;IACb,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB;8DAC0D;IAC1D,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,mBAAmB,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1C,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,WAAW,KAAK,IAAI,CAAC;IACrD;;oDAEgD;IAChD,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;CACjD;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAwB,EACxD,QAAQ,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,EAAE,iBAAiB,GACnE,EAAE,KAAK,2CA2FP"}
@@ -1,12 +1,18 @@
1
1
  import type { SiteIndex, Page } from "../../schemas/site-config";
2
2
  import type { Audience } from "../../auth/types";
3
3
  import type { DocumentOptions } from "../../document/engine/settings";
4
+ import { type NavLocation } from "../../lib/nav-tree";
4
5
  export interface PagesModalProps {
5
6
  index: SiteIndex;
6
7
  audiences: Audience[];
7
- onReorder: (fromIndex: number, toIndex: number) => void;
8
8
  /** Creates the page and returns its id so the modal can expand the new row. */
9
9
  onAddPage: () => string;
10
+ /** Creates the group and returns its id so the modal can open its settings. */
11
+ onAddGroup: () => string;
12
+ onRenameGroup: (groupId: string, label: string) => void;
13
+ onSetGroupStartCollapsed: (groupId: string, v: boolean) => void;
14
+ onDeleteGroup: (groupId: string) => void;
15
+ onMoveNavEntry: (from: NavLocation, to: NavLocation) => void;
10
16
  onSetHome: (pageId: string) => void;
11
17
  onSetArchived: (pageId: string, archived: boolean) => void;
12
18
  onSetFields: (pageId: string, patch: Partial<Pick<Page, "title" | "slug" | "showInNav">>) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"PagesModal.d.ts","sourceRoot":"","sources":["../../../src/components/editor/PagesModal.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAIjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAatE,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,SAAS,CAAC;IACjB,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,SAAS,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD,+EAA+E;IAC/E,SAAS,EAAE,MAAM,MAAM,CAAC;IACxB,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3D,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,WAAW,CAAC,CAAC,KAAK,IAAI,CAAC;IAClG,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC1D,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;IACzE,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,2CA4EhD"}
1
+ {"version":3,"file":"PagesModal.d.ts","sourceRoot":"","sources":["../../../src/components/editor/PagesModal.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAIjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAQtE,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAOlE,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,SAAS,CAAC;IACjB,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,+EAA+E;IAC/E,SAAS,EAAE,MAAM,MAAM,CAAC;IACxB,+EAA+E;IAC/E,UAAU,EAAE,MAAM,MAAM,CAAC;IACzB,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD,wBAAwB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAChE,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,cAAc,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,WAAW,KAAK,IAAI,CAAC;IAC7D,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3D,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,WAAW,CAAC,CAAC,KAAK,IAAI,CAAC;IAClG,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC1D,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;IACzE,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,2CAgJhD"}
@@ -11,19 +11,19 @@ import {
11
11
  buildBlockDropData,
12
12
  canDropBlock,
13
13
  isBlockDragData
14
- } from "../../chunk-YUUUCDXN.js";
14
+ } from "../../chunk-II3X7GLJ.js";
15
15
  import "../../chunk-5THS4K5D.js";
16
16
  import "../../chunk-ZSPCE6MZ.js";
17
17
  import {
18
18
  AddIcon,
19
19
  IconButton
20
- } from "../../chunk-CI624HRS.js";
21
- import "../../chunk-SOILPZ7U.js";
20
+ } from "../../chunk-F2337B35.js";
21
+ import "../../chunk-S4L3ZFKM.js";
22
22
  import "../../chunk-PTOLUMGV.js";
23
23
  import {
24
24
  cn
25
25
  } from "../../chunk-7EOSDFS3.js";
26
- import "../../chunk-YBVK254P.js";
26
+ import "../../chunk-ZD6XGRQM.js";
27
27
  import "../../chunk-RHWWQV3J.js";
28
28
  import "../../chunk-FM4M4Q2W.js";
29
29
  import "../../chunk-JSBRDJBE.js";
@@ -2,7 +2,7 @@ import {
2
2
  EditableRichText,
3
3
  LinkPopover,
4
4
  defineHeadingSection
5
- } from "../../chunk-RQPHPAT2.js";
5
+ } from "../../chunk-YDXBJR74.js";
6
6
  import {
7
7
  EditableGrid,
8
8
  EditablePlainText,
@@ -10,21 +10,21 @@ import {
10
10
  MediaBlock,
11
11
  ResolvedMedia,
12
12
  useEditableCollection
13
- } from "../../chunk-DJAJRBPD.js";
13
+ } from "../../chunk-KPP2CFW6.js";
14
14
  import "../../chunk-ZSPCE6MZ.js";
15
15
  import {
16
16
  DeleteIcon,
17
17
  DragHandle,
18
18
  IconButton
19
- } from "../../chunk-CI624HRS.js";
20
- import "../../chunk-SOILPZ7U.js";
21
- import "../../chunk-53DKVAB6.js";
19
+ } from "../../chunk-F2337B35.js";
20
+ import "../../chunk-S4L3ZFKM.js";
21
+ import "../../chunk-72CG6AA2.js";
22
22
  import {
23
23
  cn
24
24
  } from "../../chunk-7EOSDFS3.js";
25
- import "../../chunk-YBVK254P.js";
26
- import "../../chunk-RHWWQV3J.js";
25
+ import "../../chunk-ZD6XGRQM.js";
27
26
  import "../../chunk-VKAGMEKE.js";
27
+ import "../../chunk-RHWWQV3J.js";
28
28
  import "../../chunk-FM4M4Q2W.js";
29
29
  import "../../chunk-JSBRDJBE.js";
30
30
 
@@ -2,17 +2,17 @@ import {
2
2
  ColorItemSchema,
3
3
  ColorSpaceSchema,
4
4
  brandGuideSectionDefs
5
- } from "../../chunk-ZKGMLLUQ.js";
5
+ } from "../../chunk-5BFPJWIO.js";
6
6
  import "../../chunk-5THS4K5D.js";
7
- import "../../chunk-DJAJRBPD.js";
8
- import "../../chunk-CI624HRS.js";
9
- import "../../chunk-SOILPZ7U.js";
7
+ import "../../chunk-KPP2CFW6.js";
8
+ import "../../chunk-F2337B35.js";
9
+ import "../../chunk-S4L3ZFKM.js";
10
10
  import "../../chunk-PZJL2S3Z.js";
11
11
  import "../../chunk-WDSVHKAH.js";
12
12
  import "../../chunk-7EOSDFS3.js";
13
- import "../../chunk-YBVK254P.js";
14
- import "../../chunk-RHWWQV3J.js";
13
+ import "../../chunk-ZD6XGRQM.js";
15
14
  import "../../chunk-VKAGMEKE.js";
15
+ import "../../chunk-RHWWQV3J.js";
16
16
  import "../../chunk-FM4M4Q2W.js";
17
17
  import "../../chunk-JSBRDJBE.js";
18
18
  export {
@@ -1,26 +1,26 @@
1
1
  import {
2
2
  allSectionDefs
3
- } from "../../chunk-QQBBYQYD.js";
4
- import "../../chunk-ZKGMLLUQ.js";
5
- import "../../chunk-YUUUCDXN.js";
3
+ } from "../../chunk-FOEZNEF5.js";
4
+ import "../../chunk-5BFPJWIO.js";
5
+ import "../../chunk-II3X7GLJ.js";
6
6
  import "../../chunk-5THS4K5D.js";
7
- import "../../chunk-RQPHPAT2.js";
8
- import "../../chunk-DJAJRBPD.js";
7
+ import "../../chunk-YDXBJR74.js";
8
+ import "../../chunk-KPP2CFW6.js";
9
9
  import "../../chunk-ZSPCE6MZ.js";
10
- import "../../chunk-CI624HRS.js";
10
+ import "../../chunk-F2337B35.js";
11
11
  import "../../chunk-Y4JQGO6G.js";
12
- import "../../chunk-SOILPZ7U.js";
12
+ import "../../chunk-S4L3ZFKM.js";
13
13
  import "../../chunk-PZJL2S3Z.js";
14
14
  import "../../chunk-WDSVHKAH.js";
15
- import "../../chunk-53DKVAB6.js";
15
+ import "../../chunk-72CG6AA2.js";
16
16
  import "../../chunk-7EOSDFS3.js";
17
- import "../../chunk-YBVK254P.js";
17
+ import "../../chunk-ZD6XGRQM.js";
18
18
  import "../../chunk-TZQPOR5A.js";
19
- import "../../chunk-RHWWQV3J.js";
20
19
  import {
21
20
  registerRichText,
22
21
  registerSchema
23
22
  } from "../../chunk-VKAGMEKE.js";
23
+ import "../../chunk-RHWWQV3J.js";
24
24
  import "../../chunk-FM4M4Q2W.js";
25
25
  import "../../chunk-NSCT3AMV.js";
26
26
  import "../../chunk-JSBRDJBE.js";