camox 0.40.0 → 0.41.1

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 (108) hide show
  1. package/dist/components/PlatformLabel.js +62 -0
  2. package/dist/core/components/lexical/GradientNode.js +126 -0
  3. package/dist/core/components/lexical/InlineLexicalEditor.js +37 -56
  4. package/dist/core/components/lexical/InlineStylesPlugin.js +183 -0
  5. package/dist/core/components/lexical/SelectionBroadcaster.js +49 -46
  6. package/dist/core/components/lexical/SidebarLexicalEditor.js +197 -151
  7. package/dist/core/components/lexical/editorConfig.js +25 -7
  8. package/dist/core/components/lexical/selectTextLink.js +21 -0
  9. package/dist/core/createApp.d.ts +30 -17
  10. package/dist/core/createApp.js +14 -3
  11. package/dist/core/createBlock.d.ts +2 -2
  12. package/dist/core/createBlock.js +17 -28
  13. package/dist/core/createLayout.d.ts +48 -4
  14. package/dist/core/createLayout.js +51 -23
  15. package/dist/core/derivedRoutes.js +36 -0
  16. package/dist/core/editing/BlockEditingRuntime.js +4 -4
  17. package/dist/core/editing/CompleteBlockEditingRuntime.js +5 -5
  18. package/dist/core/editing/createEditableBlock.d.ts +9 -8
  19. package/dist/core/editing/createEditableBlock.js +265 -403
  20. package/dist/core/hooks/useIsEditable.js +4 -7
  21. package/dist/core/hooks/useRequireDraftSource.js +7 -11
  22. package/dist/core/lib/lexicalReact.d.ts +1 -26
  23. package/dist/core/lib/lexicalReact.js +46 -60
  24. package/dist/core/lib/lexicalState.js +164 -81
  25. package/dist/core/lib/modifierFormats.js +4 -15
  26. package/dist/core/lib/textStyles.d.ts +27 -0
  27. package/dist/core/lib/textStyles.js +47 -0
  28. package/dist/features/navigation/navigation.d.ts +2 -0
  29. package/dist/features/navigation/navigation.js +51 -46
  30. package/dist/features/page/DerivedPageContent.js +61 -0
  31. package/dist/features/page/PublishedPageContent.js +52 -83
  32. package/dist/features/page/SharedLayoutContent.js +66 -0
  33. package/dist/features/preview/CamoxPreview.d.ts +16 -1
  34. package/dist/features/preview/CamoxPreview.js +246 -290
  35. package/dist/features/preview/DerivedPreview.js +134 -0
  36. package/dist/features/preview/EditablePageExperience.js +25 -8
  37. package/dist/features/preview/components/AddBlockSidebar.js +43 -33
  38. package/dist/features/preview/components/AssetLightbox.js +1 -1
  39. package/dist/features/preview/components/BlockActionsPopover.js +8 -8
  40. package/dist/features/preview/components/BlockThumbnail.js +192 -0
  41. package/dist/features/preview/components/CreatePageModal.js +123 -115
  42. package/dist/features/preview/components/DerivedLayoutDialog.js +100 -0
  43. package/dist/features/preview/components/DerivedLayoutSidebar.d.ts +5 -0
  44. package/dist/features/preview/components/DerivedLayoutSidebar.js +160 -0
  45. package/dist/features/preview/components/DerivedPageInfoSidebar.js +57 -0
  46. package/dist/features/preview/components/FieldToolbar.js +42 -20
  47. package/dist/features/preview/components/Frame.js +133 -140
  48. package/dist/features/preview/components/LeftSidebar.js +42 -38
  49. package/dist/features/preview/components/LinkFieldEditor.js +3 -4
  50. package/dist/features/preview/components/MobilePreviewDrawer.js +4 -4
  51. package/dist/features/preview/components/Overlays.js +59 -47
  52. package/dist/features/preview/components/PageEditorSidebar.js +194 -203
  53. package/dist/features/preview/components/PageInfoSidebar.js +63 -55
  54. package/dist/features/preview/components/PageNavigatorSidebar.js +34 -483
  55. package/dist/features/preview/components/PagePicker.js +205 -153
  56. package/dist/features/preview/components/PageTree.js +366 -340
  57. package/dist/features/preview/components/PreviewActivation.js +78 -0
  58. package/dist/features/preview/components/PreviewPanel.js +98 -68
  59. package/dist/features/preview/components/PreviewToolbar.js +224 -241
  60. package/dist/features/preview/components/PreviewToolbarSpacer.js +43 -0
  61. package/dist/features/preview/components/PublicationRow.js +425 -0
  62. package/dist/features/preview/components/PublishDialog.js +180 -97
  63. package/dist/features/preview/components/RightSidebar.js +19 -34
  64. package/dist/features/preview/components/previewStyles.js +8 -0
  65. package/dist/features/preview/components/useUpdateBlockPosition.js +7 -13
  66. package/dist/features/preview/previewConstants.js +8 -0
  67. package/dist/features/preview/previewStore.js +18 -39
  68. package/dist/features/preview/publication.js +71 -0
  69. package/dist/features/provider/AuthenticatedCamoxProvider.js +2 -1
  70. package/dist/features/provider/CoreCamoxProvider.js +11 -2
  71. package/dist/features/provider/LocalhostPreviewProvider.js +6 -7
  72. package/dist/features/provider/useAdminShortcuts.js +5 -4
  73. package/dist/features/routes/pageRuntime.d.ts +10 -0
  74. package/dist/features/routes/pageRuntime.js +7 -9
  75. package/dist/features/runtime/PreviewDocumentContext.js +7 -0
  76. package/dist/features/runtime/RuntimeChrome.js +149 -0
  77. package/dist/features/runtime/SharedChromeContext.js +7 -0
  78. package/dist/features/runtime/navigationRequest.js +21 -0
  79. package/dist/features/runtime/navigationTarget.js +23 -0
  80. package/dist/features/runtime/pageApp.js +196 -121
  81. package/dist/features/runtime/pageNavigation.js +79 -130
  82. package/dist/features/runtime/runtime.d.ts +11 -0
  83. package/dist/features/runtime/runtime.js +183 -47
  84. package/dist/features/runtime/studioApp.d.ts +2 -11
  85. package/dist/features/runtime/studioApp.js +14 -177
  86. package/dist/features/studio/CamoxStudio.js +27 -13
  87. package/dist/features/studio/components/Navbar.js +80 -74
  88. package/dist/features/studio/components/UserButton.js +4 -4
  89. package/dist/features/studio/studioTheme.js +25 -0
  90. package/dist/features/studio/useTheme.js +94 -109
  91. package/dist/features/vite/appGeneration.js +12 -3
  92. package/dist/features/vite/definitionsSync.js +4 -2
  93. package/dist/features/vite/layoutGeneration.js +38 -0
  94. package/dist/features/vite/runtimeDev.js +3 -1
  95. package/dist/lib/auth.js +15 -13
  96. package/dist/lib/normalized-data.js +4 -4
  97. package/dist/lib/platform.js +13 -0
  98. package/dist/lib/utils.js +90 -38
  99. package/dist/studio-overlays.css +5 -40
  100. package/dist/studio.css +1 -1
  101. package/package.json +8 -4
  102. package/skills/camox/SKILL.md +2 -0
  103. package/skills/camox/references/block-definitions.md +31 -12
  104. package/skills/camox/references/layout-definitions.md +2 -0
  105. package/dist/core/lib/modifiers.js +0 -24
  106. package/dist/features/preview/components/DraftSwitchDialog.js +0 -66
  107. package/dist/features/preview/previewQueryFns.js +0 -23
  108. package/dist/features/runtime/studioNavigation.js +0 -120
@@ -1,5 +1,5 @@
1
1
  import { EmbedURL, FileValue, ImageValue, LinkValue } from "./lib/contentType.js";
2
- import { MarkdownInlineComponents } from "./lib/lexicalReact.js";
2
+ import { InlineTextStyles } from "./lib/textStyles.js";
3
3
  import { BlockComponentProps, PeekItem, RepeatableItemSeed } from "./editing/createEditableBlock.js";
4
4
  import { Block } from "./createBlock.js";
5
5
  import { Layout, LayoutBlockData, OgImageParams } from "./createLayout.js";
@@ -30,11 +30,11 @@ declare function createApp({
30
30
  }) => React.JSX.Element;
31
31
  Field: <K extends never>({
32
32
  name,
33
- components,
33
+ textStyle,
34
+ linkStyle,
34
35
  children
35
- }: {
36
+ }: InlineTextStyles & {
36
37
  name: K;
37
- components?: MarkdownInlineComponents;
38
38
  children: (props: {
39
39
  children: React.ReactNode;
40
40
  } & {
@@ -136,9 +136,8 @@ declare function createApp({
136
136
  }: {
137
137
  name: K;
138
138
  children: (item: {
139
- Field: <F extends keyof { [F_1 in keyof ({}[K] extends (infer U)[] ? U : never) as ({}[K] extends (infer U)[] ? U : never)[F_1] extends string ? F_1 : never]: ({}[K] extends (infer U)[] ? U : never)[F_1] }>(props: {
139
+ Field: <F extends keyof { [F_1 in keyof ({}[K] extends (infer U)[] ? U : never) as ({}[K] extends (infer U)[] ? U : never)[F_1] extends string ? F_1 : never]: ({}[K] extends (infer U)[] ? U : never)[F_1] }>(props: InlineTextStyles & {
140
140
  name: F;
141
- components?: MarkdownInlineComponents;
142
141
  children: (props: {
143
142
  children: React.ReactNode;
144
143
  } & {
@@ -261,9 +260,8 @@ declare function createApp({
261
260
  Repeater: <F extends keyof { [F_1 in keyof ({}[K] extends (infer U)[] ? U : never) as ({}[K] extends (infer U)[] ? U : never)[F_1] extends (infer U_1)[] ? ImageValue extends U_1 ? never : FileValue extends U_1 ? never : F_1 : never]: ({}[K] extends (infer U)[] ? U : never)[F_1] }>(props: {
262
261
  name: F;
263
262
  children: (item: {
264
- Field: (props: {
263
+ Field: (props: InlineTextStyles & {
265
264
  name: string;
266
- components?: MarkdownInlineComponents;
267
265
  children: (props: {
268
266
  children: React.ReactNode;
269
267
  } & {
@@ -386,6 +384,7 @@ declare function createApp({
386
384
  required: string[];
387
385
  } | undefined;
388
386
  layoutOnly: boolean;
387
+ synced: boolean;
389
388
  getInitialBundle: () => {
390
389
  content: Record<string, unknown>;
391
390
  settings: {
@@ -432,11 +431,11 @@ declare function createApp({
432
431
  }) => React.JSX.Element;
433
432
  Field: <K extends never>({
434
433
  name,
435
- components,
434
+ textStyle,
435
+ linkStyle,
436
436
  children
437
- }: {
437
+ }: InlineTextStyles & {
438
438
  name: K;
439
- components?: MarkdownInlineComponents;
440
439
  children: (props: {
441
440
  children: React.ReactNode;
442
441
  } & {
@@ -538,9 +537,8 @@ declare function createApp({
538
537
  }: {
539
538
  name: K;
540
539
  children: (item: {
541
- Field: <F extends keyof { [F_1 in keyof ({}[K] extends (infer U)[] ? U : never) as ({}[K] extends (infer U)[] ? U : never)[F_1] extends string ? F_1 : never]: ({}[K] extends (infer U)[] ? U : never)[F_1] }>(props: {
540
+ Field: <F extends keyof { [F_1 in keyof ({}[K] extends (infer U)[] ? U : never) as ({}[K] extends (infer U)[] ? U : never)[F_1] extends string ? F_1 : never]: ({}[K] extends (infer U)[] ? U : never)[F_1] }>(props: InlineTextStyles & {
542
541
  name: F;
543
- components?: MarkdownInlineComponents;
544
542
  children: (props: {
545
543
  children: React.ReactNode;
546
544
  } & {
@@ -663,9 +661,8 @@ declare function createApp({
663
661
  Repeater: <F extends keyof { [F_1 in keyof ({}[K] extends (infer U)[] ? U : never) as ({}[K] extends (infer U)[] ? U : never)[F_1] extends (infer U_1)[] ? ImageValue extends U_1 ? never : FileValue extends U_1 ? never : F_1 : never]: ({}[K] extends (infer U)[] ? U : never)[F_1] }>(props: {
664
662
  name: F;
665
663
  children: (item: {
666
- Field: (props: {
664
+ Field: (props: InlineTextStyles & {
667
665
  name: string;
668
- components?: MarkdownInlineComponents;
669
666
  children: (props: {
670
667
  children: React.ReactNode;
671
668
  } & {
@@ -788,6 +785,7 @@ declare function createApp({
788
785
  required: string[];
789
786
  } | undefined;
790
787
  layoutOnly: boolean;
788
+ synced: boolean;
791
789
  getInitialBundle: () => {
792
790
  content: Record<string, unknown>;
793
791
  settings: {
@@ -829,8 +827,13 @@ declare function createApp({
829
827
  (): _$react_jsx_runtime0.JSX.Element;
830
828
  displayName: string;
831
829
  };
830
+ useData(): unknown;
832
831
  _internal: {
833
832
  id: string;
833
+ kind: "curated" | "derived";
834
+ loader: ((context: {
835
+ params: Record<string, string>;
836
+ }) => unknown) | undefined;
834
837
  title: string;
835
838
  description: string;
836
839
  buildMetaTitle: (params: {
@@ -881,10 +884,12 @@ declare function createApp({
881
884
  }>;
882
885
  Provider: ({
883
886
  layoutBlocks,
884
- children
887
+ children,
888
+ data
885
889
  }: {
886
890
  layoutBlocks: Record<string, LayoutBlockData>;
887
891
  children: React.ReactNode;
892
+ data?: unknown;
888
893
  }) => _$react_jsx_runtime0.JSX.Element;
889
894
  };
890
895
  }[];
@@ -897,8 +902,13 @@ declare function createApp({
897
902
  (): _$react_jsx_runtime0.JSX.Element;
898
903
  displayName: string;
899
904
  };
905
+ useData(): unknown;
900
906
  _internal: {
901
907
  id: string;
908
+ kind: "curated" | "derived";
909
+ loader: ((context: {
910
+ params: Record<string, string>;
911
+ }) => unknown) | undefined;
902
912
  title: string;
903
913
  description: string;
904
914
  buildMetaTitle: (params: {
@@ -949,10 +959,12 @@ declare function createApp({
949
959
  }>;
950
960
  Provider: ({
951
961
  layoutBlocks,
952
- children
962
+ children,
963
+ data
953
964
  }: {
954
965
  layoutBlocks: Record<string, LayoutBlockData>;
955
966
  children: React.ReactNode;
967
+ data?: unknown;
956
968
  }) => _$react_jsx_runtime0.JSX.Element;
957
969
  };
958
970
  } | undefined;
@@ -974,6 +986,7 @@ declare function createApp({
974
986
  required: string[];
975
987
  } | undefined;
976
988
  layoutOnly: true | undefined;
989
+ synced: boolean;
977
990
  }[];
978
991
  getSerializableLayoutDefinitions(): {
979
992
  layoutId: string;
@@ -3,7 +3,17 @@ function createApp({ blocks, layouts = [] }) {
3
3
  const blocksMap = /* @__PURE__ */ new Map();
4
4
  const layoutsMap = /* @__PURE__ */ new Map();
5
5
  for (const block of blocks) blocksMap.set(block._internal.id, block);
6
- for (const layout of layouts) layoutsMap.set(layout._internal.id, layout);
6
+ const derivedPatterns = /* @__PURE__ */ new Set();
7
+ for (const layout of layouts) {
8
+ const { id, kind } = layout._internal;
9
+ if (layoutsMap.has(id)) throw new Error(`Duplicate layout: ${id}`);
10
+ if (kind === "derived") {
11
+ const pattern = id.split(".").map((segment) => segment.startsWith("$") ? "$" : segment).join(".");
12
+ if (derivedPatterns.has(pattern)) throw new Error(`Equivalent derived route: ${id}`);
13
+ derivedPatterns.add(pattern);
14
+ }
15
+ layoutsMap.set(id, layout);
16
+ }
7
17
  const layoutsWithInitialBlocks = layouts.filter((l) => l._internal.initialBlockBundles);
8
18
  if (layoutsWithInitialBlocks.length > 1) {
9
19
  const ids = layoutsWithInitialBlocks.map((l) => `"${l._internal.id}"`).join(", ");
@@ -29,7 +39,8 @@ function createApp({ blocks, layouts = [] }) {
29
39
  description: block._internal.description,
30
40
  contentSchema: block._internal.contentSchema,
31
41
  settingsSchema: block._internal.settingsSchema,
32
- layoutOnly: block._internal.layoutOnly || void 0
42
+ layoutOnly: block._internal.layoutOnly || void 0,
43
+ synced: block._internal.synced
33
44
  }));
34
45
  },
35
46
  getSerializableLayoutDefinitions() {
@@ -46,7 +57,7 @@ function createApp({ blocks, layouts = [] }) {
46
57
  blocks: layout._internal.initialBlockBundles,
47
58
  hasInitialBlocks: true
48
59
  };
49
- const fallback = layouts[0];
60
+ const fallback = layouts.find((layout) => layout._internal.kind === "curated");
50
61
  if (!fallback) return null;
51
62
  return {
52
63
  layoutId: fallback._internal.id,
@@ -1,5 +1,5 @@
1
1
  import { Type } from "./lib/contentType.js";
2
- import { MarkdownInlineComponents, MarkdownLinkRenderData, MarkdownLinkRenderProps } from "./lib/lexicalReact.js";
2
+ import { InlineStyle, InlineTextStyles, TextLinkStyleData, TextStyleData } from "./lib/textStyles.js";
3
3
  import { BlockComponentProps, PeekItem, RepeatableItemSeed, createEditableBlock } from "./editing/createEditableBlock.js";
4
4
 
5
5
  //#region src/core/createBlock.d.ts
@@ -7,4 +7,4 @@ type EditableCreateBlock = typeof createEditableBlock;
7
7
  declare const createBlock: EditableCreateBlock;
8
8
  type Block = ReturnType<typeof createBlock>;
9
9
  //#endregion
10
- export { Block, type BlockComponentProps, type MarkdownInlineComponents, type MarkdownLinkRenderData, type MarkdownLinkRenderProps, type PeekItem, type RepeatableItemSeed, Type, createBlock };
10
+ export { Block, type BlockComponentProps, type InlineStyle, type InlineTextStyles, type PeekItem, type RepeatableItemSeed, type TextLinkStyleData, type TextStyleData, Type, createBlock };
@@ -122,11 +122,12 @@ function createViewBlock(options) {
122
122
  if (!block) throw new Error("Field must be used within a Block Component");
123
123
  return item ? item.itemContent[name] : block.content[name];
124
124
  }
125
- const Field = ({ name, components, children }) => {
125
+ const Field = ({ name, textStyle, linkStyle, children }) => {
126
126
  const editingRuntime = useBlockEditingRuntime();
127
127
  if (editingRuntime) return editingRuntime.renderPrimitive(options, "Field", {
128
128
  name,
129
- components,
129
+ textStyle,
130
+ linkStyle,
130
131
  children
131
132
  });
132
133
  const value = useValue(name);
@@ -139,7 +140,8 @@ function createViewBlock(options) {
139
140
  return children({ children: markdownToReactNodes(value, {
140
141
  pages,
141
142
  fallbackHref: useLocation({ select: (location) => location.pathname }),
142
- components
143
+ textStyle,
144
+ linkStyle
143
145
  }) }, { text: value });
144
146
  };
145
147
  const Embed = ({ name, children }) => {
@@ -179,9 +181,9 @@ function createViewBlock(options) {
179
181
  };
180
182
  function useAsset(name) {
181
183
  const $ = c(4);
182
- if ($[0] !== "04a637ebd823abadf975e738c0e326acccffcffd1f7360db558a19fce0075982") {
184
+ if ($[0] !== "2482501ae16e686c6c2d84727ab607bf02513a6bcdd7de7e2f7f973cc1690267") {
183
185
  for (let $i = 0; $i < 4; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
184
- $[0] = "04a637ebd823abadf975e738c0e326acccffcffd1f7360db558a19fce0075982";
186
+ $[0] = "2482501ae16e686c6c2d84727ab607bf02513a6bcdd7de7e2f7f973cc1690267";
185
187
  }
186
188
  const block = React.use(Context);
187
189
  const item = React.use(RepeaterContext);
@@ -262,9 +264,9 @@ function createViewBlock(options) {
262
264
  };
263
265
  const ImageList = (props) => {
264
266
  const $ = c(3);
265
- if ($[0] !== "04a637ebd823abadf975e738c0e326acccffcffd1f7360db558a19fce0075982") {
267
+ if ($[0] !== "2482501ae16e686c6c2d84727ab607bf02513a6bcdd7de7e2f7f973cc1690267") {
266
268
  for (let $i = 0; $i < 3; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
267
- $[0] = "04a637ebd823abadf975e738c0e326acccffcffd1f7360db558a19fce0075982";
269
+ $[0] = "2482501ae16e686c6c2d84727ab607bf02513a6bcdd7de7e2f7f973cc1690267";
268
270
  }
269
271
  let t0;
270
272
  if ($[1] !== props) {
@@ -279,9 +281,9 @@ function createViewBlock(options) {
279
281
  };
280
282
  const FileList = (props) => {
281
283
  const $ = c(3);
282
- if ($[0] !== "04a637ebd823abadf975e738c0e326acccffcffd1f7360db558a19fce0075982") {
284
+ if ($[0] !== "2482501ae16e686c6c2d84727ab607bf02513a6bcdd7de7e2f7f973cc1690267") {
283
285
  for (let $i = 0; $i < 3; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
284
- $[0] = "04a637ebd823abadf975e738c0e326acccffcffd1f7360db558a19fce0075982";
286
+ $[0] = "2482501ae16e686c6c2d84727ab607bf02513a6bcdd7de7e2f7f973cc1690267";
285
287
  }
286
288
  let t0;
287
289
  if ($[1] !== props) {
@@ -342,31 +344,17 @@ function createViewBlock(options) {
342
344
  });
343
345
  };
344
346
  const useSetting = (name) => {
345
- const $ = c(4);
346
- if ($[0] !== "04a637ebd823abadf975e738c0e326acccffcffd1f7360db558a19fce0075982") {
347
- for (let $i = 0; $i < 4; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
348
- $[0] = "04a637ebd823abadf975e738c0e326acccffcffd1f7360db558a19fce0075982";
349
- }
350
347
  const editingRuntime = useBlockEditingRuntime();
351
- if (editingRuntime) {
352
- let t0;
353
- if ($[1] !== editingRuntime || $[2] !== name) {
354
- t0 = editingRuntime.getSetting(options, name);
355
- $[1] = editingRuntime;
356
- $[2] = name;
357
- $[3] = t0;
358
- } else t0 = $[3];
359
- return t0;
360
- }
348
+ if (editingRuntime) return editingRuntime.useSetting(options, name);
361
349
  const context = React.use(Context);
362
350
  if (!context) throw new Error("useSetting must be used within a Block Component");
363
351
  return context.settings[name];
364
352
  };
365
353
  const Detached = (t0) => {
366
354
  const $ = c(6);
367
- if ($[0] !== "04a637ebd823abadf975e738c0e326acccffcffd1f7360db558a19fce0075982") {
355
+ if ($[0] !== "2482501ae16e686c6c2d84727ab607bf02513a6bcdd7de7e2f7f973cc1690267") {
368
356
  for (let $i = 0; $i < 6; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
369
- $[0] = "04a637ebd823abadf975e738c0e326acccffcffd1f7360db558a19fce0075982";
357
+ $[0] = "2482501ae16e686c6c2d84727ab607bf02513a6bcdd7de7e2f7f973cc1690267";
370
358
  }
371
359
  const { children } = t0;
372
360
  const editingRuntime = useBlockEditingRuntime();
@@ -396,9 +384,9 @@ function createViewBlock(options) {
396
384
  };
397
385
  const Component = (props) => {
398
386
  const $ = c(23);
399
- if ($[0] !== "04a637ebd823abadf975e738c0e326acccffcffd1f7360db558a19fce0075982") {
387
+ if ($[0] !== "2482501ae16e686c6c2d84727ab607bf02513a6bcdd7de7e2f7f973cc1690267") {
400
388
  for (let $i = 0; $i < 23; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
401
- $[0] = "04a637ebd823abadf975e738c0e326acccffcffd1f7360db558a19fce0075982";
389
+ $[0] = "2482501ae16e686c6c2d84727ab607bf02513a6bcdd7de7e2f7f973cc1690267";
402
390
  }
403
391
  const editingRuntime = useBlockEditingRuntime();
404
392
  if (editingRuntime) {
@@ -547,6 +535,7 @@ function createViewBlock(options) {
547
535
  contentSchema,
548
536
  settingsSchema,
549
537
  layoutOnly: options.layoutOnly ?? false,
538
+ synced: options.synced ?? false,
550
539
  getInitialBundle,
551
540
  getInitialContent: () => {
552
541
  const content = { ...contentDefaults };
@@ -51,6 +51,10 @@ type ValidateLayoutOnlyBlocks<T extends readonly LayoutBlock[]> = { [K in keyof
51
51
  type ValidatePageContentBlocks<T extends readonly LayoutBlock[]> = { [K in keyof T]: T[K] extends LayoutBlock<true> ? "❌ Camox: blocks in `blocks.initial` must NOT be `layoutOnly: true` — `initial` is for page-content blocks. Remove `layoutOnly: true` from this block's `createBlock` options." : T[K] };
52
52
  interface CreateLayoutOptions<TBefore extends readonly LayoutBlock[], TAfter extends readonly LayoutBlock[], TInitial extends readonly LayoutBlock[]> {
53
53
  id: string;
54
+ kind?: "curated" | "derived";
55
+ loader?: (context: {
56
+ params: Record<string, string>;
57
+ }) => unknown;
54
58
  title: string;
55
59
  description: string;
56
60
  blocks: {
@@ -68,7 +72,7 @@ interface CreateLayoutOptions<TBefore extends readonly LayoutBlock[], TAfter ext
68
72
  }) => string;
69
73
  buildOgImage?: (params: OgImageParams) => React.ReactElement;
70
74
  }
71
- declare function createLayout<const TBefore extends readonly LayoutBlock[], const TAfter extends readonly LayoutBlock[], const TInitial extends readonly LayoutBlock[] = []>(options: CreateLayoutOptions<TBefore, TAfter, TInitial>): {
75
+ declare function createLayoutDefinition<const TBefore extends readonly LayoutBlock[], const TAfter extends readonly LayoutBlock[], const TInitial extends readonly LayoutBlock[] = []>(options: CreateLayoutOptions<TBefore, TAfter, TInitial>): {
72
76
  BeforeBlocks: {
73
77
  (): _$react_jsx_runtime0.JSX.Element;
74
78
  displayName: string;
@@ -77,8 +81,13 @@ declare function createLayout<const TBefore extends readonly LayoutBlock[], cons
77
81
  (): _$react_jsx_runtime0.JSX.Element;
78
82
  displayName: string;
79
83
  };
84
+ useData(): unknown;
80
85
  _internal: {
81
86
  id: string;
87
+ kind: "curated" | "derived";
88
+ loader: ((context: {
89
+ params: Record<string, string>;
90
+ }) => unknown) | undefined;
82
91
  title: string;
83
92
  description: string;
84
93
  buildMetaTitle: (params: {
@@ -129,13 +138,48 @@ declare function createLayout<const TBefore extends readonly LayoutBlock[], cons
129
138
  }>;
130
139
  Provider: ({
131
140
  layoutBlocks,
132
- children
141
+ children,
142
+ data
133
143
  }: {
134
144
  layoutBlocks: Record<string, LayoutBlockData>;
135
145
  children: React.ReactNode;
146
+ data?: unknown;
136
147
  }) => _$react_jsx_runtime0.JSX.Element;
137
148
  };
138
149
  };
139
- type Layout = ReturnType<typeof createLayout>;
150
+ type Layout = ReturnType<typeof createLayoutDefinition>;
151
+ interface LayoutFileRoutes {}
152
+ type Params<Id extends string> = Id extends `${infer Head}.${infer Tail}` ? Params<Head> & Params<Tail> : Id extends `$${infer Name}` ? { [K in Name]: string } : {};
153
+ type FileOptions<Id extends string, Data, B extends readonly LayoutBlock[], A extends readonly LayoutBlock[], I extends readonly LayoutBlock[]> = Omit<CreateLayoutOptions<B, A, I>, "id" | "kind" | "loader" | "component"> & ({
154
+ kind: "curated";
155
+ component: React.ComponentType<{
156
+ children: React.ReactNode;
157
+ }>;
158
+ loader?: never;
159
+ } | {
160
+ kind: "derived";
161
+ blocks: {
162
+ before: ValidateLayoutOnlyBlocks<B>;
163
+ after: ValidateLayoutOnlyBlocks<A>;
164
+ initial?: never;
165
+ };
166
+ loader: (context: {
167
+ params: Id extends keyof LayoutFileRoutes ? LayoutFileRoutes[Id] extends {
168
+ params: infer P;
169
+ } ? P : Params<Id> : Params<Id>;
170
+ }) => Data;
171
+ component: React.ComponentType<{
172
+ children?: never;
173
+ }>;
174
+ });
175
+ declare function createLayout<const Id extends string>(id: Id): <Data, const B extends readonly LayoutBlock[], const A extends readonly LayoutBlock[], const I extends readonly LayoutBlock[] = []>(options: FileOptions<Id, Data, B, A, I>) => Omit<Layout, "useData"> & {
176
+ useData: () => Awaited<Data>;
177
+ };
178
+ declare function createLayout<const B extends readonly LayoutBlock[], const A extends readonly LayoutBlock[], const I extends readonly LayoutBlock[] = []>(options: CreateLayoutOptions<B, A, I>): Layout;
179
+ /** Signal a missing derived page; other loader failures remain server errors. */
180
+ declare function notFound(): Error & {
181
+ status: number;
182
+ code: string;
183
+ };
140
184
  //#endregion
141
- export { Layout, LayoutBlockData, OgImageParams, createLayout };
185
+ export { Layout, LayoutBlockData, LayoutFileRoutes, OgImageParams, createLayout, notFound };
@@ -4,16 +4,16 @@ import * as React from "react";
4
4
  import { Fragment, jsx } from "react/jsx-runtime";
5
5
 
6
6
  //#region src/core/createLayout.tsx
7
- function createLayout(options) {
7
+ function createLayoutDefinition(options) {
8
8
  const LayoutContext = React.createContext(null);
9
9
  const beforeBlocks = options.blocks.before;
10
10
  const afterBlocks = options.blocks.after;
11
11
  const initialBlocks = options.blocks.initial;
12
12
  const BeforeBlocks = () => {
13
13
  const $ = c(5);
14
- if ($[0] !== "7133c1370318efe3d17ae04e10ee61f13b2babe8b7bb9f5f91e396facf4493b3") {
14
+ if ($[0] !== "2ae925f72331cad3d35d77334ec5712b5849211fd0dcab4e27af95282e583b7a") {
15
15
  for (let $i = 0; $i < 5; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
16
- $[0] = "7133c1370318efe3d17ae04e10ee61f13b2babe8b7bb9f5f91e396facf4493b3";
16
+ $[0] = "2ae925f72331cad3d35d77334ec5712b5849211fd0dcab4e27af95282e583b7a";
17
17
  }
18
18
  const ctx = React.use(LayoutContext);
19
19
  if (!ctx) throw new Error(`Layout "${options.id}" BeforeBlocks must be rendered inside its Provider`);
@@ -29,7 +29,7 @@ function createLayout(options) {
29
29
  children: /* @__PURE__ */ jsx(block._internal.Component, {
30
30
  blockData,
31
31
  mode: "layout",
32
- showAddBlockBottom: isLastBefore || void 0,
32
+ showAddBlockBottom: options.kind !== "derived" && isLastBefore || void 0,
33
33
  addBlockAfterPosition: isLastBefore ? "" : void 0
34
34
  })
35
35
  }, block._internal.id);
@@ -48,9 +48,9 @@ function createLayout(options) {
48
48
  BeforeBlocks.displayName = `LayoutBeforeBlocks(${options.id})`;
49
49
  const AfterBlocks = () => {
50
50
  const $ = c(5);
51
- if ($[0] !== "7133c1370318efe3d17ae04e10ee61f13b2babe8b7bb9f5f91e396facf4493b3") {
51
+ if ($[0] !== "2ae925f72331cad3d35d77334ec5712b5849211fd0dcab4e27af95282e583b7a") {
52
52
  for (let $i = 0; $i < 5; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
53
- $[0] = "7133c1370318efe3d17ae04e10ee61f13b2babe8b7bb9f5f91e396facf4493b3";
53
+ $[0] = "2ae925f72331cad3d35d77334ec5712b5849211fd0dcab4e27af95282e583b7a";
54
54
  }
55
55
  const ctx = React.use(LayoutContext);
56
56
  if (!ctx) throw new Error(`Layout "${options.id}" AfterBlocks must be rendered inside its Provider`);
@@ -66,7 +66,7 @@ function createLayout(options) {
66
66
  children: /* @__PURE__ */ jsx(block._internal.Component, {
67
67
  blockData,
68
68
  mode: "layout",
69
- showAddBlockTop: isFirstAfter || void 0,
69
+ showAddBlockTop: options.kind !== "derived" && isFirstAfter || void 0,
70
70
  addBlockAfterPosition: isFirstAfter ? null : void 0
71
71
  })
72
72
  }, block._internal.id);
@@ -84,29 +84,33 @@ function createLayout(options) {
84
84
  };
85
85
  AfterBlocks.displayName = `LayoutAfterBlocks(${options.id})`;
86
86
  const Provider = (t0) => {
87
- const $ = c(6);
88
- if ($[0] !== "7133c1370318efe3d17ae04e10ee61f13b2babe8b7bb9f5f91e396facf4493b3") {
89
- for (let $i = 0; $i < 6; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
90
- $[0] = "7133c1370318efe3d17ae04e10ee61f13b2babe8b7bb9f5f91e396facf4493b3";
87
+ const $ = c(7);
88
+ if ($[0] !== "2ae925f72331cad3d35d77334ec5712b5849211fd0dcab4e27af95282e583b7a") {
89
+ for (let $i = 0; $i < 7; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
90
+ $[0] = "2ae925f72331cad3d35d77334ec5712b5849211fd0dcab4e27af95282e583b7a";
91
91
  }
92
- const { layoutBlocks, children } = t0;
92
+ const { layoutBlocks, children, data } = t0;
93
93
  let t1;
94
- if ($[1] !== layoutBlocks) {
95
- t1 = { layoutBlocks };
96
- $[1] = layoutBlocks;
97
- $[2] = t1;
98
- } else t1 = $[2];
94
+ if ($[1] !== data || $[2] !== layoutBlocks) {
95
+ t1 = {
96
+ layoutBlocks,
97
+ data
98
+ };
99
+ $[1] = data;
100
+ $[2] = layoutBlocks;
101
+ $[3] = t1;
102
+ } else t1 = $[3];
99
103
  const value = t1;
100
104
  let t2;
101
- if ($[3] !== children || $[4] !== value) {
105
+ if ($[4] !== children || $[5] !== value) {
102
106
  t2 = /* @__PURE__ */ jsx(LayoutContext.Provider, {
103
107
  value,
104
108
  children
105
109
  });
106
- $[3] = children;
107
- $[4] = value;
108
- $[5] = t2;
109
- } else t2 = $[5];
110
+ $[4] = children;
111
+ $[5] = value;
112
+ $[6] = t2;
113
+ } else t2 = $[6];
110
114
  return t2;
111
115
  };
112
116
  const blockDefinitions = [...beforeBlocks.map((block) => {
@@ -147,8 +151,15 @@ function createLayout(options) {
147
151
  return {
148
152
  BeforeBlocks,
149
153
  AfterBlocks,
154
+ useData() {
155
+ const context = React.use(LayoutContext);
156
+ if (!context) throw new Error(`Layout "${options.id}" useData must be rendered inside its Provider`);
157
+ return context.data;
158
+ },
150
159
  _internal: {
151
160
  id: options.id,
161
+ kind: options.kind ?? "curated",
162
+ loader: options.loader,
152
163
  title: options.title,
153
164
  description: options.description,
154
165
  buildMetaTitle: options.buildMetaTitle,
@@ -160,6 +171,23 @@ function createLayout(options) {
160
171
  }
161
172
  };
162
173
  }
174
+ function createLayout(idOrOptions) {
175
+ if (typeof idOrOptions !== "string") return createLayoutDefinition(idOrOptions);
176
+ return (options) => {
177
+ if (options.kind === "derived" && options.blocks.initial) throw new Error("Derived layouts cannot define initial page blocks");
178
+ return createLayoutDefinition({
179
+ ...options,
180
+ id: idOrOptions
181
+ });
182
+ };
183
+ }
184
+ /** Signal a missing derived page; other loader failures remain server errors. */
185
+ function notFound() {
186
+ return Object.assign(/* @__PURE__ */ new Error("Page not found"), {
187
+ status: 404,
188
+ code: "NOT_FOUND"
189
+ });
190
+ }
163
191
 
164
192
  //#endregion
165
- export { createLayout };
193
+ export { createLayout, notFound };
@@ -0,0 +1,36 @@
1
+ //#region src/core/derivedRoutes.ts
2
+ function routeSegments(id) {
3
+ return id.split(".");
4
+ }
5
+ function matchDerivedLayout(layouts, pathname) {
6
+ const path = pathname.replace(/^\/|\/$/g, "").split("/");
7
+ const candidates = layouts.filter((layout) => layout._internal.kind === "derived").sort((a, b) => routeSegments(a._internal.id).filter((s) => s.startsWith("$")).length - routeSegments(b._internal.id).filter((s) => s.startsWith("$")).length);
8
+ for (const layout of candidates) {
9
+ const segments = routeSegments(layout._internal.id);
10
+ if (segments.length !== path.length) continue;
11
+ const params = {};
12
+ let matches = true;
13
+ for (const [index, segment] of segments.entries()) {
14
+ let value;
15
+ try {
16
+ value = decodeURIComponent(path[index]);
17
+ } catch {
18
+ matches = false;
19
+ break;
20
+ }
21
+ if (segment.startsWith("$") && value && !value.includes("/")) params[segment.slice(1)] = value;
22
+ else if (segment !== value) {
23
+ matches = false;
24
+ break;
25
+ }
26
+ }
27
+ if (matches) return {
28
+ layout,
29
+ params
30
+ };
31
+ }
32
+ return null;
33
+ }
34
+
35
+ //#endregion
36
+ export { matchDerivedLayout, routeSegments };
@@ -6,9 +6,9 @@ import { jsx } from "react/jsx-runtime";
6
6
  const BlockEditingRuntimeContext = React.createContext(null);
7
7
  function BlockEditingRuntimeProvider(t0) {
8
8
  const $ = c(4);
9
- if ($[0] !== "018faf594421b0a35898b0151f09f96da583a27bff230a04b3f1849452dbd5f1") {
9
+ if ($[0] !== "ad4fc9cc5b1b02b16c68794c8ba79d99d7e878328fdbc5bd08fcf7fbaebb83df") {
10
10
  for (let $i = 0; $i < 4; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
11
- $[0] = "018faf594421b0a35898b0151f09f96da583a27bff230a04b3f1849452dbd5f1";
11
+ $[0] = "ad4fc9cc5b1b02b16c68794c8ba79d99d7e878328fdbc5bd08fcf7fbaebb83df";
12
12
  }
13
13
  const { children, runtime } = t0;
14
14
  let t1;
@@ -25,9 +25,9 @@ function BlockEditingRuntimeProvider(t0) {
25
25
  }
26
26
  function useBlockEditingRuntime() {
27
27
  const $ = c(1);
28
- if ($[0] !== "018faf594421b0a35898b0151f09f96da583a27bff230a04b3f1849452dbd5f1") {
28
+ if ($[0] !== "ad4fc9cc5b1b02b16c68794c8ba79d99d7e878328fdbc5bd08fcf7fbaebb83df") {
29
29
  for (let $i = 0; $i < 1; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
30
- $[0] = "018faf594421b0a35898b0151f09f96da583a27bff230a04b3f1849452dbd5f1";
30
+ $[0] = "ad4fc9cc5b1b02b16c68794c8ba79d99d7e878328fdbc5bd08fcf7fbaebb83df";
31
31
  }
32
32
  return React.useContext(BlockEditingRuntimeContext);
33
33
  }
@@ -15,9 +15,9 @@ function getEditableDefinition(options) {
15
15
  }
16
16
  function EditableBlock(t0) {
17
17
  const $ = c(6);
18
- if ($[0] !== "1831c7be6bdb574903d92ed788ce4950eb5e960930a89aedad2e2125bc6edd2a") {
18
+ if ($[0] !== "e1b3ebcb34bc95f5c457074764df3357687300ade86d161e3e1014255268f87d") {
19
19
  for (let $i = 0; $i < 6; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
20
- $[0] = "1831c7be6bdb574903d92ed788ce4950eb5e960930a89aedad2e2125bc6edd2a";
20
+ $[0] = "e1b3ebcb34bc95f5c457074764df3357687300ade86d161e3e1014255268f87d";
21
21
  }
22
22
  const { options, props } = t0;
23
23
  let t1;
@@ -38,7 +38,7 @@ function EditableBlock(t0) {
38
38
  return t3;
39
39
  }
40
40
  const completeEditingRuntime = {
41
- getSetting(options, name) {
41
+ useSetting(options, name) {
42
42
  return getEditableDefinition(options).useSetting(name);
43
43
  },
44
44
  renderBlock(options, props) {
@@ -55,9 +55,9 @@ const completeEditingRuntime = {
55
55
  };
56
56
  function CompleteBlockEditingRuntimeProvider(t0) {
57
57
  const $ = c(3);
58
- if ($[0] !== "1831c7be6bdb574903d92ed788ce4950eb5e960930a89aedad2e2125bc6edd2a") {
58
+ if ($[0] !== "e1b3ebcb34bc95f5c457074764df3357687300ade86d161e3e1014255268f87d") {
59
59
  for (let $i = 0; $i < 3; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
60
- $[0] = "1831c7be6bdb574903d92ed788ce4950eb5e960930a89aedad2e2125bc6edd2a";
60
+ $[0] = "e1b3ebcb34bc95f5c457074764df3357687300ade86d161e3e1014255268f87d";
61
61
  }
62
62
  const { children } = t0;
63
63
  let t1;