@orion-studios/payload-studio 0.6.0-beta.185 → 0.6.0-beta.186

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 (40) hide show
  1. package/README.md +6 -1
  2. package/bin/init.js +329 -0
  3. package/dist/admin/index.d.mts +1 -1
  4. package/dist/admin/index.d.ts +1 -1
  5. package/dist/admin/index.js +61 -20
  6. package/dist/admin/index.mjs +1 -1
  7. package/dist/blocks/index.mjs +1 -2
  8. package/dist/{chunk-NGLIA2OE.mjs → chunk-DTHBPJXU.mjs} +193 -23
  9. package/dist/{chunk-JQAHXYAM.mjs → chunk-KMYMSR7W.mjs} +163 -3
  10. package/dist/{chunk-KHK6RTGC.mjs → chunk-MMJNHBOF.mjs} +61 -20
  11. package/dist/{chunk-ZADL33R6.mjs → chunk-OF6BATTO.mjs} +56 -111
  12. package/dist/chunk-VA545CHJ.mjs +202 -0
  13. package/dist/forms/index.d.mts +25 -0
  14. package/dist/forms/index.d.ts +25 -0
  15. package/dist/forms/index.js +237 -0
  16. package/dist/forms/index.mjs +25 -0
  17. package/dist/forms/server.d.mts +35 -0
  18. package/dist/forms/server.d.ts +35 -0
  19. package/dist/forms/server.js +442 -0
  20. package/dist/forms/server.mjs +228 -0
  21. package/dist/{index-Dv-Alx4h.d.ts → index-0xXWuOuz.d.ts} +35 -5
  22. package/dist/{index-D5zrOdyv.d.mts → index-BU82akSL.d.mts} +35 -5
  23. package/dist/{index-DLfPOqYA.d.mts → index-BbTcimgH.d.mts} +1 -0
  24. package/dist/{index-D8BNfUJb.d.mts → index-Cen-9wcc.d.mts} +17 -5
  25. package/dist/{index-BV0vEGl6.d.ts → index-DV-nW43e.d.ts} +1 -0
  26. package/dist/{index-DD_E2UfJ.d.ts → index-gxcMPpm-.d.ts} +17 -5
  27. package/dist/index.d.mts +3 -3
  28. package/dist/index.d.ts +3 -3
  29. package/dist/index.js +302 -151
  30. package/dist/index.mjs +11 -12
  31. package/dist/nextjs/index.d.mts +1 -1
  32. package/dist/nextjs/index.d.ts +1 -1
  33. package/dist/nextjs/index.js +56 -111
  34. package/dist/nextjs/index.mjs +1 -1
  35. package/dist/studio-pages/index.d.mts +1 -1
  36. package/dist/studio-pages/index.d.ts +1 -1
  37. package/dist/studio-pages/index.js +1802 -20
  38. package/dist/studio-pages/index.mjs +10 -2
  39. package/package.json +18 -2
  40. package/dist/chunk-OQSEJXC4.mjs +0 -166
package/dist/index.js CHANGED
@@ -286,23 +286,33 @@ function configureAdmin(config) {
286
286
  if (cssSources.length === 0) {
287
287
  cssPath = sourceCssPath;
288
288
  } else {
289
- let css = cssSources.map((filePath) => import_fs.default.readFileSync(filePath, "utf-8")).join("\n\n");
290
- css = css.replace(
291
- "--orion-cms-brand-primary-fallback: #3b82f6;",
292
- `--orion-cms-brand-primary-fallback: ${brandPrimary};`
293
- );
294
- css = css.replace(
295
- "--orion-cms-brand-secondary-fallback: #8b5cf6;",
296
- `--orion-cms-brand-secondary-fallback: ${brandSecondary};`
297
- );
298
- const outputBasePath = config.basePath || process.cwd();
299
- const genDir = import_path.default.resolve(outputBasePath, ".generated");
300
- if (!import_fs.default.existsSync(genDir)) {
301
- import_fs.default.mkdirSync(genDir, { recursive: true });
289
+ try {
290
+ let css = cssSources.map((filePath) => import_fs.default.readFileSync(filePath, "utf-8")).join("\n\n");
291
+ css = css.replace(
292
+ "--orion-cms-brand-primary-fallback: #3b82f6;",
293
+ `--orion-cms-brand-primary-fallback: ${brandPrimary};`
294
+ );
295
+ css = css.replace(
296
+ "--orion-cms-brand-secondary-fallback: #8b5cf6;",
297
+ `--orion-cms-brand-secondary-fallback: ${brandSecondary};`
298
+ );
299
+ const outputBasePath = config.basePath || process.cwd();
300
+ const genDir = import_path.default.resolve(outputBasePath, ".generated");
301
+ const genPath = import_path.default.resolve(genDir, "admin.css");
302
+ let existing = null;
303
+ try {
304
+ existing = import_fs.default.readFileSync(genPath, "utf-8");
305
+ } catch {
306
+ existing = null;
307
+ }
308
+ if (existing !== css) {
309
+ import_fs.default.mkdirSync(genDir, { recursive: true });
310
+ import_fs.default.writeFileSync(genPath, css);
311
+ }
312
+ cssPath = genPath;
313
+ } catch {
314
+ cssPath = sourceCssPath;
302
315
  }
303
- const genPath = import_path.default.resolve(genDir, "admin.css");
304
- import_fs.default.writeFileSync(genPath, css);
305
- cssPath = genPath;
306
316
  }
307
317
  const clientPath = "@orion-studios/payload-studio/admin/client";
308
318
  const studioNavClientProps = {
@@ -755,16 +765,47 @@ function configureAdmin(config) {
755
765
  });
756
766
  },
757
767
  wrapGlobals(globals2) {
758
- const labelMap = {
768
+ const defaultLabelMap = {
759
769
  header: { group: "Site Design", label: "Header & Navigation" },
760
770
  footer: { group: "Site Design", label: "Footer" },
761
771
  "site-settings": { group: "Site Design", label: "Website Settings" },
762
772
  "social-media": { group: "Site Design", label: "Social Media" },
763
773
  "contact-form": { group: "Lead Forms", label: "Contact Form" }
764
774
  };
775
+ const configuredBySlug = new Map(
776
+ (config.studio?.globals || []).map((link) => [link.slug, link])
777
+ );
778
+ const attachBreadcrumbToGlobal = (global) => {
779
+ if (!studioEnabled) {
780
+ return global;
781
+ }
782
+ const existingControls = global.admin?.components?.elements?.beforeDocumentControls;
783
+ return {
784
+ ...global,
785
+ admin: {
786
+ ...global.admin,
787
+ components: {
788
+ ...global.admin?.components,
789
+ elements: {
790
+ ...global.admin?.components?.elements,
791
+ beforeDocumentControls: appendComponent(
792
+ existingControls,
793
+ studioBackBreadcrumbComponent,
794
+ "StudioBackBreadcrumb"
795
+ )
796
+ }
797
+ }
798
+ }
799
+ };
800
+ };
765
801
  return globals2.map((global) => {
766
- const mapping = labelMap[global.slug];
767
- if (!mapping) return global;
802
+ const configured = configuredBySlug.get(global.slug);
803
+ const defaults = defaultLabelMap[global.slug];
804
+ const mapping = configured || defaults ? {
805
+ group: configured?.group || defaults?.group,
806
+ label: configured?.label || defaults?.label || global.slug
807
+ } : void 0;
808
+ if (!mapping) return attachBreadcrumbToGlobal(global);
768
809
  const shouldAttachSiteSettingsEditView = studioEnabled && global.slug === "site-settings";
769
810
  const shouldAttachSocialMediaEditView = studioEnabled && global.slug === "social-media";
770
811
  const shouldAttachContactFormRedirect = studioEnabled && global.slug === "contact-form";
@@ -873,7 +914,7 @@ function configureAdmin(config) {
873
914
  ...global,
874
915
  admin: {
875
916
  ...global.admin,
876
- group: mapping.group,
917
+ ...mapping.group ? { group: mapping.group } : {},
877
918
  components: {
878
919
  ...global.admin?.components,
879
920
  elements: {
@@ -3330,12 +3371,15 @@ __export(nextjs_exports, {
3330
3371
 
3331
3372
  // src/nextjs/client/payload.ts
3332
3373
  var import_payload = require("payload");
3333
- var payloadPromise = null;
3334
3374
  var WEBSITE_CONTENT_TAG = "website-content";
3335
3375
  function createPayloadClient(config) {
3376
+ let payloadPromise = null;
3336
3377
  return function getPayloadClient() {
3337
3378
  if (!payloadPromise) {
3338
- payloadPromise = (0, import_payload.getPayload)({ config });
3379
+ payloadPromise = Promise.resolve(config).then((resolvedConfig) => (0, import_payload.getPayload)({ config: resolvedConfig })).catch((error) => {
3380
+ payloadPromise = null;
3381
+ throw error;
3382
+ });
3339
3383
  }
3340
3384
  return payloadPromise;
3341
3385
  };
@@ -4032,7 +4076,7 @@ function normalizePath(segments) {
4032
4076
  const cleaned = segments.map((segment) => segment.trim()).filter(Boolean).join("/");
4033
4077
  return cleaned.length > 0 ? `/${cleaned}` : "/";
4034
4078
  }
4035
- async function queryPageByPath(payload, path2, draft) {
4079
+ async function queryPageByPath(payload, path2, draft, collectionSlug, homeSlug) {
4036
4080
  const pathWhere = {
4037
4081
  path: {
4038
4082
  equals: path2
@@ -4044,7 +4088,7 @@ async function queryPageByPath(payload, path2, draft) {
4044
4088
  }
4045
4089
  };
4046
4090
  const result = await payload.find({
4047
- collection: "pages",
4091
+ collection: collectionSlug,
4048
4092
  depth: 2,
4049
4093
  draft,
4050
4094
  limit: 1,
@@ -4057,11 +4101,11 @@ async function queryPageByPath(payload, path2, draft) {
4057
4101
  if (path2 === "/") {
4058
4102
  const homeWhere = {
4059
4103
  slug: {
4060
- equals: "home"
4104
+ equals: homeSlug
4061
4105
  }
4062
4106
  };
4063
4107
  const homeResult = await payload.find({
4064
- collection: "pages",
4108
+ collection: collectionSlug,
4065
4109
  depth: 2,
4066
4110
  draft,
4067
4111
  limit: 1,
@@ -4072,27 +4116,31 @@ async function queryPageByPath(payload, path2, draft) {
4072
4116
  }
4073
4117
  return null;
4074
4118
  }
4075
- function createPageQueries(getPayloadClient, contentTag = "website-content") {
4119
+ function createPageQueries(getPayloadClient, contentTagOrOptions = "website-content") {
4120
+ const options = typeof contentTagOrOptions === "string" ? { contentTag: contentTagOrOptions } : contentTagOrOptions;
4121
+ const contentTag = options.contentTag || "website-content";
4122
+ const pagesCollectionSlug = options.pagesCollectionSlug || "pages";
4123
+ const homeSlug = options.homeSlug || "home";
4076
4124
  const getPublishedPageByPathCached = (0, import_cache.unstable_cache)(
4077
4125
  async (path2) => {
4078
4126
  const payload = await getPayloadClient();
4079
- return queryPageByPath(payload, path2, false);
4127
+ return queryPageByPath(payload, path2, false, pagesCollectionSlug, homeSlug);
4080
4128
  },
4081
- ["page-by-path", PAGE_QUERY_CACHE_VERSION],
4129
+ ["page-by-path", PAGE_QUERY_CACHE_VERSION, pagesCollectionSlug, homeSlug, contentTag],
4082
4130
  { tags: [contentTag] }
4083
4131
  );
4084
4132
  async function getPageBySegments(segments, draft = false) {
4085
4133
  const path2 = normalizePath(segments);
4086
4134
  const payload = await getPayloadClient();
4087
4135
  if (draft) {
4088
- return queryPageByPath(payload, path2, true);
4136
+ return queryPageByPath(payload, path2, true, pagesCollectionSlug, homeSlug);
4089
4137
  }
4090
4138
  return getPublishedPageByPathCached(path2);
4091
4139
  }
4092
4140
  async function listPublishedPagePaths() {
4093
4141
  const payload = await getPayloadClient();
4094
4142
  const pages = await payload.find({
4095
- collection: "pages",
4143
+ collection: pagesCollectionSlug,
4096
4144
  depth: 0,
4097
4145
  draft: false,
4098
4146
  limit: 1e3,
@@ -4121,108 +4169,46 @@ function createPageQueries(getPayloadClient, contentTag = "website-content") {
4121
4169
 
4122
4170
  // src/nextjs/queries/site.ts
4123
4171
  var import_cache2 = require("next/cache");
4124
- function createSiteQueries(getPayloadClient, contentTag = "website-content") {
4125
- const getSiteSettingsCached = (0, import_cache2.unstable_cache)(
4126
- async () => {
4127
- const payload = await getPayloadClient();
4128
- const settings = await payload.findGlobal({
4129
- slug: "site-settings",
4130
- depth: 1
4131
- });
4132
- return settings;
4133
- },
4134
- ["site-settings-global"],
4135
- { tags: [contentTag] }
4136
- );
4137
- const getHeaderCached = (0, import_cache2.unstable_cache)(
4138
- async () => {
4139
- const payload = await getPayloadClient();
4140
- const header = await payload.findGlobal({
4141
- slug: "header",
4142
- depth: 1
4143
- });
4144
- return header;
4145
- },
4146
- ["header-global"],
4147
- { tags: [contentTag] }
4148
- );
4149
- const getFooterCached = (0, import_cache2.unstable_cache)(
4150
- async () => {
4151
- const payload = await getPayloadClient();
4152
- const footer = await payload.findGlobal({
4153
- slug: "footer",
4154
- depth: 1
4155
- });
4156
- return footer;
4157
- },
4158
- ["footer-global"],
4159
- { tags: [contentTag] }
4160
- );
4161
- const getSocialMediaCached = (0, import_cache2.unstable_cache)(
4162
- async () => {
4163
- const payload = await getPayloadClient();
4164
- const socialMedia = await payload.findGlobal({
4165
- slug: "social-media",
4166
- depth: 1
4167
- });
4168
- return socialMedia;
4169
- },
4170
- ["social-media-global"],
4171
- { tags: [contentTag] }
4172
- );
4173
- async function getSiteSettings(draft = false) {
4174
- if (draft) {
4175
- const payload = await getPayloadClient();
4176
- const settings = await payload.findGlobal({
4177
- slug: "site-settings",
4178
- depth: 1,
4179
- draft: true
4180
- });
4181
- return settings;
4182
- }
4183
- return getSiteSettingsCached();
4184
- }
4185
- async function getHeader(draft = false) {
4186
- if (draft) {
4187
- const payload = await getPayloadClient();
4188
- const header = await payload.findGlobal({
4189
- slug: "header",
4190
- depth: 1,
4191
- draft: true
4192
- });
4193
- return header;
4194
- }
4195
- return getHeaderCached();
4196
- }
4197
- async function getFooter(draft = false) {
4198
- if (draft) {
4199
- const payload = await getPayloadClient();
4200
- const footer = await payload.findGlobal({
4201
- slug: "footer",
4202
- depth: 1,
4203
- draft: true
4204
- });
4205
- return footer;
4206
- }
4207
- return getFooterCached();
4208
- }
4209
- async function getSocialMedia(draft = false) {
4210
- if (draft) {
4211
- const payload = await getPayloadClient();
4212
- const socialMedia = await payload.findGlobal({
4213
- slug: "social-media",
4214
- depth: 1,
4215
- draft: true
4216
- });
4217
- return socialMedia;
4218
- }
4219
- return getSocialMediaCached();
4172
+ function createSiteQueries(getPayloadClient, contentTagOrOptions = "website-content") {
4173
+ const options = typeof contentTagOrOptions === "string" ? { contentTag: contentTagOrOptions } : contentTagOrOptions;
4174
+ const contentTag = options.contentTag || "website-content";
4175
+ const siteSettingsSlug = options.siteSettingsSlug || "site-settings";
4176
+ const headerSlug = options.headerSlug || "header";
4177
+ const footerSlug = options.footerSlug || "footer";
4178
+ const socialMediaSlug = options.socialMediaSlug || "social-media";
4179
+ function createGlobalQuery(slug, cacheKey) {
4180
+ const getCached = (0, import_cache2.unstable_cache)(
4181
+ async () => {
4182
+ const payload = await getPayloadClient();
4183
+ const data = await payload.findGlobal({
4184
+ slug,
4185
+ depth: 1,
4186
+ overrideAccess: false
4187
+ });
4188
+ return data;
4189
+ },
4190
+ [cacheKey, slug, contentTag],
4191
+ { tags: [contentTag] }
4192
+ );
4193
+ return async function getGlobal(draft = false) {
4194
+ if (draft) {
4195
+ const payload = await getPayloadClient();
4196
+ const data = await payload.findGlobal({
4197
+ slug,
4198
+ depth: 1,
4199
+ draft: true,
4200
+ overrideAccess: false
4201
+ });
4202
+ return data;
4203
+ }
4204
+ return getCached();
4205
+ };
4220
4206
  }
4221
4207
  return {
4222
- getSiteSettings,
4223
- getHeader,
4224
- getFooter,
4225
- getSocialMedia
4208
+ getSiteSettings: createGlobalQuery(siteSettingsSlug, "site-settings-global"),
4209
+ getHeader: createGlobalQuery(headerSlug, "header-global"),
4210
+ getFooter: createGlobalQuery(footerSlug, "footer-global"),
4211
+ getSocialMedia: createGlobalQuery(socialMediaSlug, "social-media-global")
4226
4212
  };
4227
4213
  }
4228
4214
 
@@ -4278,9 +4264,13 @@ function resolveSocialMediaLinks(data) {
4278
4264
  // src/studio-pages/index.ts
4279
4265
  var studio_pages_exports = {};
4280
4266
  __export(studio_pages_exports, {
4267
+ DEFAULT_LEGACY_HERO_BACKGROUND_COLORS: () => DEFAULT_LEGACY_HERO_BACKGROUND_COLORS,
4281
4268
  createDefaultStudioDocument: () => createDefaultStudioDocument,
4269
+ createStudioPageFields: () => createStudioPageFields,
4282
4270
  createStudioPageService: () => createStudioPageService,
4271
+ createStudioPagesCollection: () => createStudioPagesCollection,
4283
4272
  defaultBuilderThemeTokens: () => defaultBuilderThemeTokens,
4273
+ defaultRelationshipHydrationMap: () => defaultRelationshipHydrationMap,
4284
4274
  getStudioDocumentFromPage: () => getStudioDocumentFromPage,
4285
4275
  layoutToStudioDocument: () => layoutToStudioDocument,
4286
4276
  pageInspectorPanels: () => pageInspectorPanels,
@@ -4718,6 +4708,13 @@ var inspectorDefinitionByBlockType = {
4718
4708
  };
4719
4709
 
4720
4710
  // src/studio-pages/pageService.ts
4711
+ var defaultRelationshipHydrationMap = {
4712
+ beforeAfter: { arrays: { items: ["media", "beforeMedia", "afterMedia"] } },
4713
+ featureGrid: { arrays: { items: ["media", "beforeMedia", "afterMedia"] } },
4714
+ hero: { fields: ["media"] },
4715
+ logoWall: { arrays: { items: ["media", "beforeMedia", "afterMedia"] } },
4716
+ media: { fields: ["image"] }
4717
+ };
4721
4718
  var isRecord5 = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
4722
4719
  var toRecordArray = (value) => Array.isArray(value) ? value.filter((item) => isRecord5(item)) : [];
4723
4720
  var getRelationID = (value) => {
@@ -4745,7 +4742,7 @@ var hydrateRelationship = (valueFromStudio, valueFromLayout) => {
4745
4742
  }
4746
4743
  return valueFromLayout;
4747
4744
  };
4748
- var hydrateDocumentWithLayoutRelations = (document, layout) => {
4745
+ var hydrateDocumentWithLayoutRelations = (document, layout, hydrationMap = defaultRelationshipHydrationMap) => {
4749
4746
  const nextNodes = document.nodes.map((node, index) => {
4750
4747
  const layoutBlock = layout[index];
4751
4748
  if (!isRecord5(layoutBlock)) {
@@ -4754,17 +4751,18 @@ var hydrateDocumentWithLayoutRelations = (document, layout) => {
4754
4751
  if (typeof layoutBlock.blockType !== "string" || layoutBlock.blockType !== node.type) {
4755
4752
  return node;
4756
4753
  }
4757
- const nextData = { ...node.data };
4758
- if (node.type === "hero") {
4759
- nextData.media = hydrateRelationship(nextData.media, layoutBlock.media);
4754
+ const rule = hydrationMap[node.type];
4755
+ if (!rule) {
4756
+ return node;
4760
4757
  }
4761
- if (node.type === "media") {
4762
- nextData.image = hydrateRelationship(nextData.image, layoutBlock.image);
4758
+ const nextData = { ...node.data };
4759
+ for (const fieldName of rule.fields || []) {
4760
+ nextData[fieldName] = hydrateRelationship(nextData[fieldName], layoutBlock[fieldName]);
4763
4761
  }
4764
- if (node.type === "featureGrid" || node.type === "logoWall" || node.type === "beforeAfter") {
4765
- const studioItems = Array.isArray(nextData.items) ? nextData.items : [];
4766
- const layoutItems = Array.isArray(layoutBlock.items) ? layoutBlock.items : [];
4767
- nextData.items = studioItems.map((rawStudioItem, itemIndex) => {
4762
+ for (const [arrayField, itemFields] of Object.entries(rule.arrays || {})) {
4763
+ const studioItems = Array.isArray(nextData[arrayField]) ? nextData[arrayField] : [];
4764
+ const layoutItems = Array.isArray(layoutBlock[arrayField]) ? layoutBlock[arrayField] : [];
4765
+ nextData[arrayField] = studioItems.map((rawStudioItem, itemIndex) => {
4768
4766
  if (!isRecord5(rawStudioItem)) {
4769
4767
  return rawStudioItem;
4770
4768
  }
@@ -4773,9 +4771,9 @@ var hydrateDocumentWithLayoutRelations = (document, layout) => {
4773
4771
  return rawStudioItem;
4774
4772
  }
4775
4773
  const nextItem = { ...rawStudioItem };
4776
- nextItem.media = hydrateRelationship(nextItem.media, layoutItem.media);
4777
- nextItem.beforeMedia = hydrateRelationship(nextItem.beforeMedia, layoutItem.beforeMedia);
4778
- nextItem.afterMedia = hydrateRelationship(nextItem.afterMedia, layoutItem.afterMedia);
4774
+ for (const itemField of itemFields) {
4775
+ nextItem[itemField] = hydrateRelationship(nextItem[itemField], layoutItem[itemField]);
4776
+ }
4779
4777
  return nextItem;
4780
4778
  });
4781
4779
  }
@@ -4794,7 +4792,12 @@ var normalizeDocument = (document) => ({
4794
4792
  schemaVersion: 1,
4795
4793
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
4796
4794
  });
4797
- var normalizeLegacyHeroDefaults = (document) => {
4795
+ var DEFAULT_LEGACY_HERO_BACKGROUND_COLORS = ["#124a37"];
4796
+ var normalizeLegacyHeroDefaults = (document, legacyColors = DEFAULT_LEGACY_HERO_BACKGROUND_COLORS) => {
4797
+ if (legacyColors.length === 0) {
4798
+ return document;
4799
+ }
4800
+ const normalizedLegacyColors = legacyColors.map((color) => color.trim().toLowerCase());
4798
4801
  const nodes = document.nodes.map((node) => {
4799
4802
  if (node.type !== "hero" || !isRecord5(node.data)) {
4800
4803
  return node;
@@ -4804,7 +4807,7 @@ var normalizeLegacyHeroDefaults = (document) => {
4804
4807
  const sectionBackgroundMode = typeof nextData.sectionBackgroundMode === "string" ? nextData.sectionBackgroundMode : "none";
4805
4808
  const hasBackgroundImageURL = typeof nextData.backgroundImageURL === "string" && nextData.backgroundImageURL.trim().length > 0;
4806
4809
  const mediaRelation = getRelationID(nextData.media);
4807
- if (heroBackgroundColor === "#124a37" && sectionBackgroundMode === "none" && !hasBackgroundImageURL && mediaRelation === null) {
4810
+ if (normalizedLegacyColors.includes(heroBackgroundColor) && sectionBackgroundMode === "none" && !hasBackgroundImageURL && mediaRelation === null) {
4808
4811
  nextData.backgroundColor = "";
4809
4812
  }
4810
4813
  return {
@@ -4823,13 +4826,13 @@ var assertCanPublish = (issues) => {
4823
4826
  throw new Error(`Cannot publish page: ${publishErrors[0].message}`);
4824
4827
  }
4825
4828
  };
4826
- var getStudioDocumentFromPage = (doc) => {
4829
+ var getStudioDocumentFromPage = (doc, relationshipHydration = defaultRelationshipHydrationMap) => {
4827
4830
  const title = typeof doc.title === "string" ? doc.title : void 0;
4828
4831
  const layout = asLayoutArray(doc.layout);
4829
4832
  try {
4830
4833
  const studioDocument = assertStudioDocumentV1(doc.studioDocument);
4831
4834
  if (layout.length > 0) {
4832
- return hydrateDocumentWithLayoutRelations(studioDocument, layout);
4835
+ return hydrateDocumentWithLayoutRelations(studioDocument, layout, relationshipHydration);
4833
4836
  }
4834
4837
  return studioDocument;
4835
4838
  } catch {
@@ -4841,8 +4844,10 @@ var getStudioDocumentFromPage = (doc) => {
4841
4844
  };
4842
4845
  var createStudioPageService = ({
4843
4846
  collectionSlug = "pages",
4847
+ legacyHeroBackgroundColors = DEFAULT_LEGACY_HERO_BACKGROUND_COLORS,
4844
4848
  modules,
4845
4849
  payload,
4850
+ relationshipHydration = defaultRelationshipHydrationMap,
4846
4851
  user
4847
4852
  }) => ({
4848
4853
  getPageForStudio: async (pageID) => {
@@ -4854,7 +4859,7 @@ var createStudioPageService = ({
4854
4859
  overrideAccess: false,
4855
4860
  user
4856
4861
  });
4857
- const studioDocument = getStudioDocumentFromPage(page);
4862
+ const studioDocument = getStudioDocumentFromPage(page, relationshipHydration);
4858
4863
  return {
4859
4864
  id: String(page.id),
4860
4865
  slug: typeof page.slug === "string" ? page.slug : "",
@@ -4864,7 +4869,10 @@ var createStudioPageService = ({
4864
4869
  },
4865
4870
  validateStudioDocument: (document) => validateStudioDocument(document, modules),
4866
4871
  saveDraft: async (pageID, document, _metadata) => {
4867
- const normalizedDocument = normalizeLegacyHeroDefaults(normalizeDocument(document));
4872
+ const normalizedDocument = normalizeLegacyHeroDefaults(
4873
+ normalizeDocument(document),
4874
+ legacyHeroBackgroundColors
4875
+ );
4868
4876
  const compileResult = compileStudioDocument(normalizedDocument, modules);
4869
4877
  await payload.update({
4870
4878
  collection: collectionSlug,
@@ -4885,7 +4893,10 @@ var createStudioPageService = ({
4885
4893
  };
4886
4894
  },
4887
4895
  publish: async (pageID, document, _metadata) => {
4888
- const normalizedDocument = normalizeLegacyHeroDefaults(normalizeDocument(document));
4896
+ const normalizedDocument = normalizeLegacyHeroDefaults(
4897
+ normalizeDocument(document),
4898
+ legacyHeroBackgroundColors
4899
+ );
4889
4900
  const compileResult = compileStudioDocument(normalizedDocument, modules);
4890
4901
  assertCanPublish(compileResult.issues);
4891
4902
  await payload.update({
@@ -4914,6 +4925,146 @@ var toEditorInitialDoc = (payloadPage) => ({
4914
4925
  title: payloadPage.title
4915
4926
  });
4916
4927
 
4928
+ // src/studio-pages/pageFields.ts
4929
+ var formatSlugValue = (value) => {
4930
+ if (typeof value !== "string") return void 0;
4931
+ return value.trim().toLowerCase().replace(/[^a-z0-9/]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
4932
+ };
4933
+ function createStudioPageFields(options = {}) {
4934
+ const {
4935
+ blocks = defaultPageLayoutBlocks,
4936
+ mediaCollectionSlug = "media",
4937
+ additionalFields = []
4938
+ } = options;
4939
+ return [
4940
+ {
4941
+ name: "title",
4942
+ type: "text",
4943
+ required: true
4944
+ },
4945
+ {
4946
+ name: "slug",
4947
+ type: "text",
4948
+ admin: {
4949
+ description: "URL identifier for this page. `home` is served at `/`.",
4950
+ position: "sidebar"
4951
+ },
4952
+ hooks: {
4953
+ beforeValidate: [({ value }) => formatSlugValue(value) ?? value]
4954
+ },
4955
+ index: true,
4956
+ required: true,
4957
+ unique: true
4958
+ },
4959
+ {
4960
+ name: "path",
4961
+ type: "text",
4962
+ admin: {
4963
+ description: "Full public path. Derived from the slug when left empty.",
4964
+ position: "sidebar"
4965
+ },
4966
+ hooks: {
4967
+ beforeValidate: [
4968
+ ({ value, data }) => {
4969
+ if (typeof value === "string" && value.trim().length > 0) {
4970
+ return value.trim();
4971
+ }
4972
+ const slug = formatSlugValue(data?.slug);
4973
+ if (!slug) return value;
4974
+ return slug === "home" ? "/" : `/${slug}`;
4975
+ }
4976
+ ]
4977
+ },
4978
+ index: true,
4979
+ unique: true
4980
+ },
4981
+ {
4982
+ name: "studioDocument",
4983
+ type: "json",
4984
+ admin: {
4985
+ description: "Canonical Studio editor state. Managed by the page builder.",
4986
+ hidden: true
4987
+ }
4988
+ },
4989
+ {
4990
+ name: "studioValidationIssues",
4991
+ type: "json",
4992
+ admin: {
4993
+ description: "Validation issues from the last Studio compile. Managed by the page builder.",
4994
+ hidden: true
4995
+ }
4996
+ },
4997
+ {
4998
+ name: "layout",
4999
+ type: "blocks",
5000
+ admin: {
5001
+ description: "Compiled output only \u2014 edit pages through the Studio builder."
5002
+ },
5003
+ blocks
5004
+ },
5005
+ {
5006
+ name: "seo",
5007
+ type: "group",
5008
+ fields: [
5009
+ { name: "metaTitle", type: "text" },
5010
+ { name: "metaDescription", type: "textarea" },
5011
+ { name: "canonicalUrl", type: "text" },
5012
+ {
5013
+ name: "ogImage",
5014
+ type: "upload",
5015
+ relationTo: mediaCollectionSlug
5016
+ }
5017
+ ]
5018
+ },
5019
+ {
5020
+ name: "noIndex",
5021
+ type: "checkbox",
5022
+ admin: { position: "sidebar" },
5023
+ defaultValue: false
5024
+ },
5025
+ {
5026
+ name: "noFollow",
5027
+ type: "checkbox",
5028
+ admin: { position: "sidebar" },
5029
+ defaultValue: false
5030
+ },
5031
+ ...additionalFields
5032
+ ];
5033
+ }
5034
+ function createStudioPagesCollection(options = {}) {
5035
+ const { slug = "pages", access, overrides, ...fieldOptions } = options;
5036
+ const base = {
5037
+ slug,
5038
+ access: access || {
5039
+ create: ({ req }) => Boolean(req.user),
5040
+ delete: ({ req }) => Boolean(req.user),
5041
+ read: ({ req }) => {
5042
+ if (req.user) return true;
5043
+ return { _status: { equals: "published" } };
5044
+ },
5045
+ update: ({ req }) => Boolean(req.user)
5046
+ },
5047
+ admin: {
5048
+ defaultColumns: ["title", "slug", "_status", "updatedAt"],
5049
+ useAsTitle: "title"
5050
+ },
5051
+ fields: createStudioPageFields(fieldOptions),
5052
+ versions: {
5053
+ drafts: {
5054
+ autosave: false
5055
+ },
5056
+ maxPerDoc: 50
5057
+ }
5058
+ };
5059
+ if (!overrides) return base;
5060
+ return {
5061
+ ...base,
5062
+ ...overrides,
5063
+ admin: { ...base.admin, ...overrides.admin },
5064
+ fields: overrides.fields || base.fields
5065
+ };
5066
+ }
5067
+
4917
5068
  // src/studio-pages/migrations.ts
4918
5069
  var isRecord6 = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
4919
5070
  var assertPageStudioDocumentV1 = (value) => {
package/dist/index.mjs CHANGED
@@ -1,25 +1,24 @@
1
- import {
2
- admin_exports
3
- } from "./chunk-KHK6RTGC.mjs";
4
- import {
5
- blocks_exports
6
- } from "./chunk-JQAHXYAM.mjs";
7
1
  import {
8
2
  nextjs_exports
9
- } from "./chunk-ZADL33R6.mjs";
3
+ } from "./chunk-OF6BATTO.mjs";
4
+ import {
5
+ admin_exports
6
+ } from "./chunk-MMJNHBOF.mjs";
10
7
  import "./chunk-ZTXJG4K5.mjs";
8
+ import {
9
+ admin_app_exports
10
+ } from "./chunk-RKTIFEUY.mjs";
11
+ import "./chunk-W2UOCJDX.mjs";
11
12
  import {
12
13
  studio_pages_exports
13
- } from "./chunk-NGLIA2OE.mjs";
14
- import "./chunk-OQSEJXC4.mjs";
14
+ } from "./chunk-DTHBPJXU.mjs";
15
15
  import "./chunk-7ZMXZRBP.mjs";
16
16
  import {
17
17
  studio_exports
18
18
  } from "./chunk-ADIIWIYL.mjs";
19
19
  import {
20
- admin_app_exports
21
- } from "./chunk-RKTIFEUY.mjs";
22
- import "./chunk-W2UOCJDX.mjs";
20
+ blocks_exports
21
+ } from "./chunk-KMYMSR7W.mjs";
23
22
  import "./chunk-6BWS3CLP.mjs";
24
23
  export {
25
24
  admin_exports as admin,