@orion-studios/payload-studio 0.6.0-beta.7 → 0.6.0-beta.71

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 (48) hide show
  1. package/dist/admin/client.js +2076 -618
  2. package/dist/admin/client.mjs +2037 -590
  3. package/dist/admin/index.d.mts +2 -2
  4. package/dist/admin/index.d.ts +2 -2
  5. package/dist/admin/index.js +140 -17
  6. package/dist/admin/index.mjs +2 -2
  7. package/dist/admin-app/client.js +11 -4
  8. package/dist/admin-app/client.mjs +1 -1
  9. package/dist/admin-app/index.d.mts +2 -2
  10. package/dist/admin-app/index.d.ts +2 -2
  11. package/dist/admin-app/styles.css +343 -41
  12. package/dist/admin.css +18 -2
  13. package/dist/builder-v2/client.d.mts +18 -0
  14. package/dist/builder-v2/client.d.ts +18 -0
  15. package/dist/builder-v2/client.js +1673 -0
  16. package/dist/builder-v2/client.mjs +1548 -0
  17. package/dist/builder-v2/index.d.mts +241 -0
  18. package/dist/builder-v2/index.d.ts +241 -0
  19. package/dist/builder-v2/index.js +760 -0
  20. package/dist/builder-v2/index.mjs +710 -0
  21. package/dist/builder-v2/styles.css +1524 -0
  22. package/dist/{chunk-XKUTZ7IU.mjs → chunk-276KAPGM.mjs} +56 -5
  23. package/dist/{chunk-KPIX7OSV.mjs → chunk-2XH7X34N.mjs} +11 -4
  24. package/dist/{chunk-PF3EBZXF.mjs → chunk-7ZMXZRBP.mjs} +39 -3
  25. package/dist/{chunk-5FNTVRCR.mjs → chunk-KHK6RTGC.mjs} +143 -20
  26. package/dist/{chunk-OTHERBGX.mjs → chunk-ZADL33R6.mjs} +1 -1
  27. package/dist/{index-QPDAedIX.d.ts → index-BV0vEGl6.d.ts} +4 -2
  28. package/dist/{index-Cv-6qnrw.d.mts → index-D5zrOdyv.d.mts} +3 -1
  29. package/dist/{index-52HdVLQq.d.ts → index-DAdN56fM.d.ts} +1 -1
  30. package/dist/{index-DyMmaRfI.d.mts → index-DLfPOqYA.d.mts} +4 -2
  31. package/dist/{index-Crx_MtPw.d.ts → index-Dv-Alx4h.d.ts} +3 -1
  32. package/dist/{index-DEQC3Dwj.d.mts → index-G_uTNffQ.d.mts} +1 -1
  33. package/dist/index.d.mts +4 -4
  34. package/dist/index.d.ts +4 -4
  35. package/dist/index.js +231 -21
  36. package/dist/index.mjs +10 -10
  37. package/dist/nextjs/index.js +39 -3
  38. package/dist/nextjs/index.mjs +2 -2
  39. package/dist/{sitePreviewTypes-BkHCWxNW.d.mts → sitePreviewTypes-BrJwGzJj.d.mts} +1 -1
  40. package/dist/{sitePreviewTypes-BkHCWxNW.d.ts → sitePreviewTypes-BrJwGzJj.d.ts} +1 -1
  41. package/dist/studio-pages/builder.css +24 -5
  42. package/dist/studio-pages/client.js +574 -64
  43. package/dist/studio-pages/client.mjs +574 -64
  44. package/dist/studio-pages/index.d.mts +1 -1
  45. package/dist/studio-pages/index.d.ts +1 -1
  46. package/dist/studio-pages/index.js +91 -4
  47. package/dist/studio-pages/index.mjs +3 -3
  48. package/package.json +22 -3
@@ -97,7 +97,9 @@ var defaultBuilderBlockSettingsV2 = {
97
97
  },
98
98
  typography: {
99
99
  bodyAlign: "left",
100
+ bodySizePt: null,
100
101
  headingAlign: "left",
102
+ headingSizePt: null,
101
103
  letterSpacingPreset: "normal",
102
104
  lineHeightPreset: "normal",
103
105
  maxTextWidth: "auto"
@@ -126,7 +128,9 @@ var defaultBuilderItemSettingsV2 = {
126
128
  },
127
129
  typography: {
128
130
  bodyAlign: "left",
131
+ bodySizePt: null,
129
132
  headingAlign: "left",
133
+ headingSizePt: null,
130
134
  letterSpacingPreset: "normal",
131
135
  lineHeightPreset: "normal",
132
136
  maxTextWidth: "auto"
@@ -156,6 +160,7 @@ var defaultBuilderThemeTokens = {
156
160
 
157
161
  // src/studio-pages/builder/adapters/settingsV2.ts
158
162
  var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
163
+ var isTextAlign = (value) => value === "left" || value === "center" || value === "right" || value === "justify";
159
164
  var parsePercent = (value) => {
160
165
  if (typeof value === "number" && Number.isFinite(value)) {
161
166
  return Math.max(0, Math.min(100, value));
@@ -180,6 +185,18 @@ var parsePixel = (value) => {
180
185
  }
181
186
  return null;
182
187
  };
188
+ var parsePoint = (value) => {
189
+ if (typeof value === "number" && Number.isFinite(value)) {
190
+ return Math.max(6, Math.min(120, Math.round(value)));
191
+ }
192
+ if (typeof value === "string" && value.trim().length > 0) {
193
+ const parsed = Number(value);
194
+ if (Number.isFinite(parsed)) {
195
+ return Math.max(6, Math.min(120, Math.round(parsed)));
196
+ }
197
+ }
198
+ return null;
199
+ };
183
200
  var mergeSettings = (defaults, input) => {
184
201
  if (!isRecord(input)) {
185
202
  return structuredClone(defaults);
@@ -198,6 +215,10 @@ var mergeSettings = (defaults, input) => {
198
215
  };
199
216
  var legacyBlockToV2Settings = (block) => {
200
217
  const current = structuredClone(defaultBuilderBlockSettingsV2);
218
+ if (block.blockType === "hero" && block.variant === "centered") {
219
+ current.typography.headingAlign = "center";
220
+ current.typography.bodyAlign = "center";
221
+ }
201
222
  current.layout.contentWidth = block.contentWidth === "narrow" || block.contentWidth === "content" || block.contentWidth === "wide" || block.contentWidth === "full" || block.contentWidth === "inherit" ? block.contentWidth : current.layout.contentWidth;
202
223
  current.layout.sectionPaddingX = block.sectionPaddingX === "none" || block.sectionPaddingX === "sm" || block.sectionPaddingX === "md" || block.sectionPaddingX === "lg" || block.sectionPaddingX === "inherit" ? block.sectionPaddingX : current.layout.sectionPaddingX;
203
224
  current.layout.sectionPaddingY = block.sectionPaddingY === "none" || block.sectionPaddingY === "sm" || block.sectionPaddingY === "lg" ? block.sectionPaddingY : current.layout.sectionPaddingY;
@@ -234,15 +255,28 @@ var legacyBlockToV2Settings = (block) => {
234
255
  current.media.positionX = parsePercent(block.imagePositionX ?? block.backgroundImagePositionX);
235
256
  current.media.positionY = parsePercent(block.imagePositionY ?? block.backgroundImagePositionY);
236
257
  current.media.height = parsePixel(block.imageHeight);
237
- current.typography.headingAlign = block.textHeadingAlign === "left" || block.textHeadingAlign === "center" || block.textHeadingAlign === "right" || block.textHeadingAlign === "justify" ? block.textHeadingAlign : current.typography.headingAlign;
238
- current.typography.bodyAlign = block.textBodyAlign === "left" || block.textBodyAlign === "center" || block.textBodyAlign === "right" || block.textBodyAlign === "justify" ? block.textBodyAlign : current.typography.bodyAlign;
258
+ current.typography.headingAlign = isTextAlign(block.textHeadingAlign) ? block.textHeadingAlign : current.typography.headingAlign;
259
+ current.typography.bodyAlign = isTextAlign(block.textBodyAlign) ? block.textBodyAlign : current.typography.bodyAlign;
260
+ current.typography.headingSizePt = parsePoint(block.textHeadingSizePt);
261
+ current.typography.bodySizePt = parsePoint(block.textBodySizePt);
239
262
  current.typography.maxTextWidth = block.textMaxWidth === "auto" || block.textMaxWidth === "sm" || block.textMaxWidth === "md" || block.textMaxWidth === "lg" || block.textMaxWidth === "full" ? block.textMaxWidth : current.typography.maxTextWidth;
240
263
  current.typography.lineHeightPreset = block.textLineHeightPreset === "tight" || block.textLineHeightPreset === "normal" || block.textLineHeightPreset === "relaxed" ? block.textLineHeightPreset : current.typography.lineHeightPreset;
241
264
  current.typography.letterSpacingPreset = block.textLetterSpacingPreset === "tight" || block.textLetterSpacingPreset === "normal" || block.textLetterSpacingPreset === "relaxed" ? block.textLetterSpacingPreset : current.typography.letterSpacingPreset;
242
265
  current.advanced.editCopyInPanel = Boolean(block.editCopyInPanel ?? current.advanced.editCopyInPanel);
243
266
  current.advanced.customClassName = typeof block.customClassName === "string" ? block.customClassName : current.advanced.customClassName;
244
267
  current.advanced.hideOnMobile = Boolean(block.hideOnMobile ?? current.advanced.hideOnMobile);
245
- return mergeSettings(current, block.settings);
268
+ const settings = mergeSettings(current, block.settings);
269
+ if (block.blockType === "hero") {
270
+ const top = settings.layout.paddingTopPt;
271
+ const bottom = settings.layout.paddingBottomPt;
272
+ const hasLegacyLinkedHeroPadding = settings.layout.linkVerticalPadding !== false && (top === null || typeof top === "undefined" || top === 30) && (bottom === null || typeof bottom === "undefined" || bottom === 30 || bottom === 20);
273
+ if (hasLegacyLinkedHeroPadding) {
274
+ settings.layout.linkVerticalPadding = false;
275
+ settings.layout.paddingTopPt = 30;
276
+ settings.layout.paddingBottomPt = 20;
277
+ }
278
+ }
279
+ return settings;
246
280
  };
247
281
  var v2SettingsToLegacyBlock = (blockWithSettings) => {
248
282
  const settings = legacyBlockToV2Settings(blockWithSettings);
@@ -268,6 +302,8 @@ var v2SettingsToLegacyBlock = (blockWithSettings) => {
268
302
  next.contentGradientAngle = settings.appearance.contentGradientAngle;
269
303
  next.textHeadingAlign = settings.typography.headingAlign;
270
304
  next.textBodyAlign = settings.typography.bodyAlign;
305
+ next.textHeadingSizePt = settings.typography.headingSizePt;
306
+ next.textBodySizePt = settings.typography.bodySizePt;
271
307
  next.textMaxWidth = settings.typography.maxTextWidth;
272
308
  next.textLineHeightPreset = settings.typography.lineHeightPreset;
273
309
  next.textLetterSpacingPreset = settings.typography.letterSpacingPreset;
@@ -362,6 +398,7 @@ var resolveTypographyStyleFromSettings = (settings) => {
362
398
  const letterSpacing = settings.letterSpacingPreset === "tight" ? "-0.01em" : settings.letterSpacingPreset === "relaxed" ? "0.02em" : "0.01em";
363
399
  const maxWidth = settings.maxTextWidth === "sm" ? "36ch" : settings.maxTextWidth === "md" ? "52ch" : settings.maxTextWidth === "lg" ? "72ch" : settings.maxTextWidth === "full" ? "100%" : void 0;
364
400
  return {
401
+ ...typeof settings.bodySizePt === "number" && Number.isFinite(settings.bodySizePt) ? { fontSize: `${settings.bodySizePt}pt` } : {},
365
402
  letterSpacing,
366
403
  lineHeight,
367
404
  maxWidth,
@@ -531,8 +568,52 @@ var alignOptions = [
531
568
  { label: "Right", value: "right" },
532
569
  { label: "Justify", value: "justify" }
533
570
  ];
534
- var layoutFieldSet = [];
571
+ var layoutFieldSet = [
572
+ {
573
+ group: "layout",
574
+ key: "settings.layout.linkVerticalPadding",
575
+ label: "Link Top/Bottom Padding",
576
+ tags: ["spacing", "padding", "vertical"],
577
+ type: "checkbox"
578
+ },
579
+ {
580
+ group: "layout",
581
+ key: "settings.layout.paddingTopPt",
582
+ label: "Top Padding (pt)",
583
+ max: 240,
584
+ min: 0,
585
+ tags: ["spacing", "padding", "top"],
586
+ type: "number"
587
+ },
588
+ {
589
+ group: "layout",
590
+ key: "settings.layout.paddingBottomPt",
591
+ label: "Bottom Padding (pt)",
592
+ max: 240,
593
+ min: 0,
594
+ tags: ["spacing", "padding", "bottom"],
595
+ type: "number"
596
+ }
597
+ ];
535
598
  var typographyFieldSet = [
599
+ {
600
+ group: "typography",
601
+ key: "settings.typography.headingSizePt",
602
+ label: "Heading Text Size (pt)",
603
+ max: 120,
604
+ min: 6,
605
+ tags: ["text", "size", "heading", "font"],
606
+ type: "number"
607
+ },
608
+ {
609
+ group: "typography",
610
+ key: "settings.typography.bodySizePt",
611
+ label: "Body Text Size (pt)",
612
+ max: 72,
613
+ min: 6,
614
+ tags: ["text", "size", "body", "paragraph", "font"],
615
+ type: "number"
616
+ },
536
617
  {
537
618
  group: "typography",
538
619
  key: "settings.typography.headingAlign",
@@ -639,6 +720,7 @@ var mediaFieldSet = [
639
720
  ];
640
721
  var commonInspectorGroups = [
641
722
  { key: "basics", label: "Basics" },
723
+ { key: "layout", label: "Layout" },
642
724
  { key: "typography", label: "Typography" },
643
725
  { key: "media", label: "Media" },
644
726
  { key: "advanced", label: "Advanced" }
@@ -755,6 +837,13 @@ var inspectorDefinitionByBlockType = {
755
837
  { group: "basics", inlineEditable: true, key: "kicker", label: "Kicker", type: "text" },
756
838
  { group: "basics", inlineEditable: true, key: "headline", label: "Headline", type: "text" },
757
839
  { group: "basics", inlineEditable: true, key: "subheadline", label: "Subheadline", type: "textarea" },
840
+ {
841
+ group: "basics",
842
+ key: "settings.marquee.itemsText",
843
+ label: "Scrolling Bar Options",
844
+ tags: ["marquee", "scrolling", "bar", "categories"],
845
+ type: "textarea"
846
+ },
758
847
  {
759
848
  group: "basics",
760
849
  key: "variant",
@@ -924,6 +1013,69 @@ var normalizeNumber = (value, fallback) => {
924
1013
  }
925
1014
  return fallback;
926
1015
  };
1016
+ var sectionPaddingPointMap = {
1017
+ none: 0,
1018
+ sm: 17,
1019
+ md: 31,
1020
+ lg: 41
1021
+ };
1022
+ var heroDefaultPaddingTopPt = 30;
1023
+ var heroDefaultPaddingBottomPt = 20;
1024
+ var defaultTextSizePointMap = {
1025
+ cta: { body: 14, heading: 36 },
1026
+ faq: { body: 12, heading: 18 },
1027
+ featureGrid: { body: 12, heading: 36 },
1028
+ formEmbed: { body: 12, heading: 36 },
1029
+ hero: { body: 14, heading: 48 },
1030
+ media: { body: 12, heading: 36 },
1031
+ richText: { body: 12, heading: 39 },
1032
+ stats: { body: 11, heading: 30 },
1033
+ testimonials: { body: 12, heading: 36 }
1034
+ };
1035
+ var normalizeSectionPaddingY = (value) => value === "none" || value === "sm" || value === "lg" ? value : "md";
1036
+ var normalizePaddingPointValue = (value) => {
1037
+ if (typeof value === "number" && Number.isFinite(value)) {
1038
+ return Math.max(0, Math.min(240, Math.round(value)));
1039
+ }
1040
+ if (typeof value === "string" && value.trim().length > 0) {
1041
+ const parsed = Number(value);
1042
+ if (Number.isFinite(parsed)) {
1043
+ return Math.max(0, Math.min(240, Math.round(parsed)));
1044
+ }
1045
+ }
1046
+ return null;
1047
+ };
1048
+ var normalizeTextSizePointValue = (value) => {
1049
+ if (typeof value === "number" && Number.isFinite(value)) {
1050
+ return Math.max(6, Math.min(120, Math.round(value)));
1051
+ }
1052
+ if (typeof value === "string" && value.trim().length > 0) {
1053
+ const parsed = Number(value);
1054
+ if (Number.isFinite(parsed)) {
1055
+ return Math.max(6, Math.min(120, Math.round(parsed)));
1056
+ }
1057
+ }
1058
+ return null;
1059
+ };
1060
+ var getEffectiveVerticalPaddingValue = (block, key) => {
1061
+ const explicit = normalizePaddingPointValue(getByPath(block, key));
1062
+ if (explicit !== null) {
1063
+ return explicit;
1064
+ }
1065
+ const layoutSectionPaddingY = getByPath(block, "settings.layout.sectionPaddingY");
1066
+ const legacySectionPaddingY = block.sectionPaddingY;
1067
+ const inherited = block.blockType === "hero" ? key === "settings.layout.paddingBottomPt" ? heroDefaultPaddingBottomPt : heroDefaultPaddingTopPt : sectionPaddingPointMap[normalizeSectionPaddingY(layoutSectionPaddingY || legacySectionPaddingY)];
1068
+ return inherited;
1069
+ };
1070
+ var getEffectiveTextSizeValue = (block, key) => {
1071
+ const explicit = normalizeTextSizePointValue(getByPath(block, key));
1072
+ if (explicit !== null) {
1073
+ return explicit;
1074
+ }
1075
+ const blockType = typeof block.blockType === "string" ? block.blockType : "";
1076
+ const defaults = defaultTextSizePointMap[blockType] || { body: 12, heading: 36 };
1077
+ return key === "settings.typography.headingSizePt" ? defaults.heading : defaults.body;
1078
+ };
927
1079
  var getRelationID = (value) => {
928
1080
  if (typeof value === "number" || typeof value === "string") {
929
1081
  return value;
@@ -952,6 +1104,12 @@ var toMediaLibraryItem = (value) => {
952
1104
  };
953
1105
  };
954
1106
  var mediaLabel = (item) => item.filename || item.alt || `Media #${item.id}`;
1107
+ var findMediaLibraryItem = (library, id) => {
1108
+ if (id === null) {
1109
+ return null;
1110
+ }
1111
+ return library.find((item) => String(item.id) === String(id)) || null;
1112
+ };
955
1113
  var groupLabel = (key) => commonInspectorGroups.find((group) => group.key === key)?.label || key;
956
1114
  function BlockInspectorRenderer({
957
1115
  block,
@@ -1075,8 +1233,9 @@ function BlockInspectorRenderer({
1075
1233
  title: group.label,
1076
1234
  children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "orion-builder-settings-field-list", children: [
1077
1235
  group.key === "media" ? effectiveMediaSources.map((source) => {
1078
- const selectedSourceMedia = toMediaLibraryItem(source.value);
1079
1236
  const selectedSourceMediaID = getRelationID(source.value);
1237
+ const selectedRelationMedia = toMediaLibraryItem(source.value);
1238
+ const selectedSourceMedia = selectedRelationMedia ?? findMediaLibraryItem(source.library, selectedSourceMediaID);
1080
1239
  const sourceOptions = selectedSourceMedia && !source.library.some((item) => String(item.id) === String(selectedSourceMedia.id)) ? [selectedSourceMedia, ...source.library] : source.library;
1081
1240
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1082
1241
  "div",
@@ -1086,6 +1245,26 @@ function BlockInspectorRenderer({
1086
1245
  children: [
1087
1246
  source.loading ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "orion-builder-settings-note", children: "Loading media library..." }) : null,
1088
1247
  source.error ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "orion-builder-settings-error", children: source.error }) : null,
1248
+ selectedSourceMedia?.url ? (
1249
+ // eslint-disable-next-line @next/next/no-img-element
1250
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1251
+ "img",
1252
+ {
1253
+ alt: selectedSourceMedia.alt || source.label,
1254
+ src: selectedSourceMedia.url,
1255
+ style: {
1256
+ aspectRatio: "16 / 9",
1257
+ border: "1px solid rgba(35, 51, 82, 0.14)",
1258
+ borderRadius: 10,
1259
+ display: "block",
1260
+ marginBottom: "0.7rem",
1261
+ objectFit: effectiveMedia.fit,
1262
+ objectPosition: `${effectiveMedia.positionX}% ${effectiveMedia.positionY}%`,
1263
+ width: "100%"
1264
+ }
1265
+ }
1266
+ )
1267
+ ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "orion-builder-settings-empty", children: "No image selected." }),
1089
1268
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "orion-builder-settings-label", children: [
1090
1269
  source.label,
1091
1270
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
@@ -1101,6 +1280,10 @@ function BlockInspectorRenderer({
1101
1280
  }
1102
1281
  )
1103
1282
  ] }),
1283
+ selectedSourceMedia?.alt ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "orion-builder-settings-label", children: [
1284
+ "Media Description",
1285
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { className: "orion-builder-settings-input", readOnly: true, type: "text", value: selectedSourceMedia.alt })
1286
+ ] }) : selectedSourceMediaID !== null ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "orion-builder-settings-note", children: "This media item does not have a description yet." }) : null,
1104
1287
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1105
1288
  "button",
1106
1289
  {
@@ -1157,19 +1340,20 @@ function BlockInspectorRenderer({
1157
1340
  }
1158
1341
  ) : null,
1159
1342
  (hasMediaGroupContent ? group.fields.filter((field) => !(group.key === "media" && field.key.startsWith("settings.media."))) : group.fields).map((field) => {
1160
- if (field.key === "settings.layout.paddingBottomPt" && Boolean(getByPath(block, "settings.layout.linkVerticalPadding"))) {
1343
+ if (field.key === "settings.layout.paddingBottomPt" && getByPath(block, "settings.layout.linkVerticalPadding") !== false && block.blockType !== "hero") {
1161
1344
  return null;
1162
1345
  }
1163
- if (field.key === "settings.layout.paddingRightPt" && Boolean(getByPath(block, "settings.layout.linkHorizontalPadding"))) {
1346
+ if (field.key === "settings.layout.paddingRightPt" && getByPath(block, "settings.layout.linkHorizontalPadding") !== false) {
1164
1347
  return null;
1165
1348
  }
1166
1349
  const fieldValue = getByPath(block, field.key);
1167
1350
  if (field.type === "checkbox") {
1351
+ const checked = field.key === "settings.layout.linkVerticalPadding" || field.key === "settings.layout.linkHorizontalPadding" ? typeof fieldValue === "boolean" ? fieldValue : block.blockType === "hero" ? false : true : Boolean(fieldValue);
1168
1352
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "orion-builder-settings-label is-checkbox", children: [
1169
1353
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1170
1354
  "input",
1171
1355
  {
1172
- checked: Boolean(fieldValue),
1356
+ checked,
1173
1357
  onChange: (event) => updateForKey(field.key, event.target.checked),
1174
1358
  type: "checkbox"
1175
1359
  }
@@ -1192,8 +1376,10 @@ function BlockInspectorRenderer({
1192
1376
  ] }, field.key);
1193
1377
  }
1194
1378
  if (field.type === "number") {
1195
- const numberValue = typeof fieldValue === "number" ? fieldValue : typeof fieldValue === "string" && fieldValue.trim().length > 0 ? Number(fieldValue) : null;
1196
- const resolvedValue = typeof numberValue === "number" && Number.isFinite(numberValue) ? numberValue : "";
1379
+ const isPaddingPointField = field.key === "settings.layout.paddingTopPt" || field.key === "settings.layout.paddingBottomPt";
1380
+ const isTextSizePointField = field.key === "settings.typography.headingSizePt" || field.key === "settings.typography.bodySizePt";
1381
+ const numberValue = isTextSizePointField ? normalizeTextSizePointValue(fieldValue) : normalizePaddingPointValue(fieldValue);
1382
+ const resolvedValue = numberValue !== null ? numberValue : isPaddingPointField ? getEffectiveVerticalPaddingValue(block, field.key) : isTextSizePointField ? getEffectiveTextSizeValue(block, field.key) : "";
1197
1383
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "orion-builder-settings-label", children: [
1198
1384
  field.label,
1199
1385
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
@@ -2249,8 +2435,8 @@ function renderSimpleBlockPreview(args) {
2249
2435
  getImagePresentationStyle: getImagePresentationStyle2,
2250
2436
  index,
2251
2437
  isBlockUploadTarget,
2252
- normalizeImageCornerStyle: normalizeImageCornerStyle2,
2253
- normalizeImageFit: normalizeImageFit2,
2438
+ normalizeImageCornerStyle: normalizeImageCornerStyle3,
2439
+ normalizeImageFit: normalizeImageFit3,
2254
2440
  normalizeText: normalizeText3,
2255
2441
  onDropAt,
2256
2442
  renderWithSectionShell,
@@ -2434,8 +2620,8 @@ function renderSimpleBlockPreview(args) {
2434
2620
  const imagePositionX = parseOptionalPercentNumber(mediaSettings.positionX ?? block?.imagePositionX);
2435
2621
  const imagePositionY = parseOptionalPercentNumber(mediaSettings.positionY ?? block?.imagePositionY);
2436
2622
  const imageStyle = getImagePresentationStyle2({
2437
- cornerStyle: normalizeImageCornerStyle2(mediaSettings.cornerStyle ?? block?.imageCornerStyle),
2438
- fit: normalizeImageFit2(mediaSettings.fit ?? block?.imageFit),
2623
+ cornerStyle: normalizeImageCornerStyle3(mediaSettings.cornerStyle ?? block?.imageCornerStyle),
2624
+ fit: normalizeImageFit3(mediaSettings.fit ?? block?.imageFit),
2439
2625
  positionX: imagePositionX,
2440
2626
  positionY: imagePositionY
2441
2627
  });
@@ -2965,6 +3151,76 @@ var normalizeNumber2 = (value, fallback) => {
2965
3151
  return fallback;
2966
3152
  };
2967
3153
  var clamp = (value, min, max) => Math.max(min, Math.min(max, value));
3154
+ var getRelationID2 = (value) => {
3155
+ if (typeof value === "number" || typeof value === "string") {
3156
+ return value;
3157
+ }
3158
+ if (!isRecord5(value)) {
3159
+ return null;
3160
+ }
3161
+ const id = value.id;
3162
+ return typeof id === "number" || typeof id === "string" ? id : null;
3163
+ };
3164
+ var toMediaLibraryItem2 = (value) => {
3165
+ if (!isRecord5(value)) {
3166
+ return null;
3167
+ }
3168
+ const id = getRelationID2(value);
3169
+ if (id === null) {
3170
+ return null;
3171
+ }
3172
+ const filename = typeof value.filename === "string" ? value.filename : "";
3173
+ const url = typeof value.url === "string" && value.url.length > 0 ? value.url : filename ? `/api/media/file/${encodeURIComponent(filename)}` : "";
3174
+ return {
3175
+ alt: typeof value.alt === "string" ? value.alt : "",
3176
+ filename,
3177
+ id,
3178
+ url
3179
+ };
3180
+ };
3181
+ var mediaFromImageURL = (url, fallbackLabel) => {
3182
+ if (typeof url !== "string" || url.trim().length === 0) {
3183
+ return null;
3184
+ }
3185
+ const normalizedURL = url.trim();
3186
+ const filename = normalizedURL.split("/").filter(Boolean).pop() || fallbackLabel;
3187
+ return {
3188
+ alt: fallbackLabel,
3189
+ filename,
3190
+ id: `url:${normalizedURL}`,
3191
+ url: normalizedURL
3192
+ };
3193
+ };
3194
+ var mediaLabel2 = (item) => item.filename || item.alt || `Media #${item.id}`;
3195
+ var findMediaLibraryItem2 = (library, id) => {
3196
+ if (id === null) {
3197
+ return null;
3198
+ }
3199
+ return library.find((item) => String(item.id) === String(id)) || null;
3200
+ };
3201
+ var normalizeImageFit = (value) => value === "contain" ? "contain" : "cover";
3202
+ var normalizeImageCornerStyle = (value) => value === "square" ? "square" : "rounded";
3203
+ var getItemMediaSettings = (item) => {
3204
+ const settings = isRecord5(item.settings) ? item.settings : {};
3205
+ const media = isRecord5(settings.media) ? settings.media : {};
3206
+ return {
3207
+ cornerStyle: normalizeImageCornerStyle(media.cornerStyle ?? item.imageCornerStyle),
3208
+ fit: normalizeImageFit(media.fit ?? item.imageFit),
3209
+ height: (() => {
3210
+ const value = media.height ?? item.imageHeight;
3211
+ if (typeof value === "number" && Number.isFinite(value)) {
3212
+ return value;
3213
+ }
3214
+ if (typeof value === "string" && value.trim().length > 0) {
3215
+ const parsed = Number(value);
3216
+ return Number.isFinite(parsed) ? parsed : null;
3217
+ }
3218
+ return null;
3219
+ })(),
3220
+ positionX: clamp(normalizeNumber2(media.positionX ?? item.imagePositionX, 50), 0, 100),
3221
+ positionY: clamp(normalizeNumber2(media.positionY ?? item.imagePositionY, 50), 0, 100)
3222
+ };
3223
+ };
2968
3224
  var hasQueryMatch = (query, ...values) => {
2969
3225
  const normalized = query.trim().toLowerCase();
2970
3226
  if (!normalized) {
@@ -3011,18 +3267,148 @@ var bulletsToTextareaValue = (value) => {
3011
3267
  return value.map((item) => isRecord5(item) && typeof item.label === "string" ? item.label.trim() : "").filter(Boolean).join("\n");
3012
3268
  };
3013
3269
  var textareaValueToBullets = (value) => value.split("\n").map((line) => line.trim()).filter(Boolean).map((label) => ({ label }));
3270
+ function ItemMediaControl({
3271
+ fieldName,
3272
+ imageURLFieldName,
3273
+ item,
3274
+ itemIndex,
3275
+ label,
3276
+ mediaLibrary,
3277
+ mediaLibraryError,
3278
+ mediaLibraryLoading,
3279
+ maxHeight,
3280
+ minHeight,
3281
+ onRemoveItemMedia,
3282
+ onSelectItemMedia,
3283
+ onUpdateItemField,
3284
+ onUpdateItemMediaPresentation,
3285
+ onUploadItemMedia,
3286
+ searchQuery,
3287
+ uploadDisabled,
3288
+ uploadLabel,
3289
+ uploading
3290
+ }) {
3291
+ const directImageURL = normalizeText(item[imageURLFieldName]);
3292
+ const selectedRelationMedia = toMediaLibraryItem2(item[fieldName]) ?? mediaFromImageURL(directImageURL, label);
3293
+ const selectedMediaID = getRelationID2(item[fieldName]) ?? selectedRelationMedia?.id ?? null;
3294
+ const selectedMedia = selectedRelationMedia ?? findMediaLibraryItem2(mediaLibrary, selectedMediaID);
3295
+ const previewURL = selectedMedia?.url || directImageURL;
3296
+ const mediaSettings = getItemMediaSettings(item);
3297
+ const sourceOptions = selectedMedia && !mediaLibrary.some((libraryItem) => String(libraryItem.id) === String(selectedMedia.id)) ? [selectedMedia, ...mediaLibrary] : mediaLibrary;
3298
+ if (!hasQueryMatch(searchQuery, label, "image", "media", "photo", "picture", "url", "fit", "crop", "height")) {
3299
+ return null;
3300
+ }
3301
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "orion-builder-settings-item-card", style: { padding: "0.56rem" }, children: [
3302
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "orion-builder-settings-label", children: label }),
3303
+ previewURL ? (
3304
+ // eslint-disable-next-line @next/next/no-img-element
3305
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3306
+ "img",
3307
+ {
3308
+ alt: selectedMedia?.alt || label,
3309
+ src: previewURL,
3310
+ style: {
3311
+ aspectRatio: "16 / 9",
3312
+ border: "1px solid rgba(35, 51, 82, 0.14)",
3313
+ borderRadius: mediaSettings.cornerStyle === "square" ? 4 : 10,
3314
+ display: "block",
3315
+ objectFit: mediaSettings.fit,
3316
+ objectPosition: `${mediaSettings.positionX}% ${mediaSettings.positionY}%`,
3317
+ width: "100%"
3318
+ }
3319
+ }
3320
+ )
3321
+ ) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "orion-builder-settings-empty", children: "No image selected." }),
3322
+ mediaLibraryLoading ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "orion-builder-settings-note", children: "Loading media library..." }) : null,
3323
+ mediaLibraryError ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "orion-builder-settings-error", children: mediaLibraryError }) : null,
3324
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "orion-builder-settings-label", children: [
3325
+ "Media Library Image",
3326
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3327
+ "select",
3328
+ {
3329
+ className: "orion-builder-settings-input",
3330
+ onChange: (event) => onSelectItemMedia?.(itemIndex, fieldName, event.target.value),
3331
+ value: selectedMediaID !== null ? String(selectedMediaID) : "",
3332
+ children: [
3333
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: "", children: "No image" }),
3334
+ sourceOptions.map((libraryItem) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: String(libraryItem.id), children: mediaLabel2(libraryItem) }, String(libraryItem.id)))
3335
+ ]
3336
+ }
3337
+ )
3338
+ ] }),
3339
+ selectedMedia?.alt ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "orion-builder-settings-label", children: [
3340
+ "Media Description",
3341
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { className: "orion-builder-settings-input", readOnly: true, type: "text", value: selectedMedia.alt })
3342
+ ] }) : selectedMediaID !== null ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "orion-builder-settings-note", children: "This media item does not have a description yet." }) : null,
3343
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3344
+ "button",
3345
+ {
3346
+ className: "orion-builder-settings-inline-btn",
3347
+ disabled: selectedMediaID === null,
3348
+ onClick: () => {
3349
+ onRemoveItemMedia?.(itemIndex, fieldName);
3350
+ onUpdateItemField(itemIndex, imageURLFieldName, "");
3351
+ },
3352
+ type: "button",
3353
+ children: "Remove Image"
3354
+ }
3355
+ ),
3356
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "orion-builder-settings-label", children: [
3357
+ uploadLabel,
3358
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3359
+ "input",
3360
+ {
3361
+ accept: "image/*",
3362
+ className: "orion-builder-settings-input",
3363
+ disabled: uploadDisabled,
3364
+ onChange: (event) => {
3365
+ const file = event.currentTarget.files?.[0];
3366
+ if (file) {
3367
+ onUploadItemMedia?.(itemIndex, fieldName, file);
3368
+ }
3369
+ event.currentTarget.value = "";
3370
+ },
3371
+ type: "file"
3372
+ }
3373
+ )
3374
+ ] }),
3375
+ uploading ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "orion-builder-settings-note", children: "Uploading image..." }) : null,
3376
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3377
+ ImageControls,
3378
+ {
3379
+ cornerStyle: mediaSettings.cornerStyle,
3380
+ fit: mediaSettings.fit,
3381
+ height: mediaSettings.height,
3382
+ maxHeight,
3383
+ minHeight,
3384
+ onChange: (field, value) => onUpdateItemMediaPresentation?.(itemIndex, field, value),
3385
+ positionX: mediaSettings.positionX,
3386
+ positionY: mediaSettings.positionY
3387
+ }
3388
+ )
3389
+ ] });
3390
+ }
3014
3391
  function ArrayItemsEditor({
3015
3392
  blockType,
3016
3393
  expandedItemIndex,
3017
3394
  items,
3395
+ mediaLibrary = [],
3396
+ mediaLibraryError = "",
3397
+ mediaLibraryLoading = false,
3018
3398
  mode,
3019
3399
  onAddItem,
3400
+ onRemoveItemMedia,
3020
3401
  onRemoveItem,
3402
+ onSelectItemMedia,
3021
3403
  onToggleItem,
3022
3404
  onUpdateItemField,
3405
+ onUpdateItemMediaPresentation,
3023
3406
  onUpdateItemSetting,
3407
+ onUploadItemMedia,
3024
3408
  searchQuery,
3025
- showInlineCopyFields
3409
+ showInlineCopyFields,
3410
+ uploadDisabled = false,
3411
+ isItemMediaUploading
3026
3412
  }) {
3027
3413
  const config = blockConfig[blockType];
3028
3414
  const normalizedQuery = searchQuery.trim().toLowerCase();
@@ -3172,11 +3558,30 @@ function ArrayItemsEditor({
3172
3558
  }
3173
3559
  )
3174
3560
  ] }) : null,
3175
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "orion-builder-settings-note", children: [
3176
- "Select this item and use the ",
3177
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Media" }),
3178
- " group above for image source and presentation."
3179
- ] })
3561
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3562
+ ItemMediaControl,
3563
+ {
3564
+ fieldName: "media",
3565
+ imageURLFieldName: "imageURL",
3566
+ item,
3567
+ itemIndex,
3568
+ label: "Feature Image",
3569
+ maxHeight: 600,
3570
+ mediaLibrary,
3571
+ mediaLibraryError,
3572
+ mediaLibraryLoading,
3573
+ minHeight: 40,
3574
+ onRemoveItemMedia,
3575
+ onSelectItemMedia,
3576
+ onUpdateItemField,
3577
+ onUpdateItemMediaPresentation,
3578
+ onUploadItemMedia,
3579
+ searchQuery: normalizedQuery,
3580
+ uploadDisabled,
3581
+ uploadLabel: "Upload Feature Image",
3582
+ uploading: Boolean(isItemMediaUploading?.(itemIndex, "media"))
3583
+ }
3584
+ )
3180
3585
  ] }) : null,
3181
3586
  blockType === "logoWall" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
3182
3587
  showInlineCopyFields ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "orion-builder-settings-label", children: [
@@ -3203,11 +3608,30 @@ function ArrayItemsEditor({
3203
3608
  }
3204
3609
  )
3205
3610
  ] }) : null,
3206
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "orion-builder-settings-note", children: [
3207
- "Select this item and use the ",
3208
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Media" }),
3209
- " group above for image source and presentation."
3210
- ] })
3611
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3612
+ ItemMediaControl,
3613
+ {
3614
+ fieldName: "media",
3615
+ imageURLFieldName: "imageURL",
3616
+ item,
3617
+ itemIndex,
3618
+ label: "Logo Image",
3619
+ maxHeight: 200,
3620
+ mediaLibrary,
3621
+ mediaLibraryError,
3622
+ mediaLibraryLoading,
3623
+ minHeight: 24,
3624
+ onRemoveItemMedia,
3625
+ onSelectItemMedia,
3626
+ onUpdateItemField,
3627
+ onUpdateItemMediaPresentation,
3628
+ onUploadItemMedia,
3629
+ searchQuery: normalizedQuery,
3630
+ uploadDisabled,
3631
+ uploadLabel: "Upload Logo Image",
3632
+ uploading: Boolean(isItemMediaUploading?.(itemIndex, "media"))
3633
+ }
3634
+ )
3211
3635
  ] }) : null,
3212
3636
  blockType === "beforeAfter" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
3213
3637
  showInlineCopyFields ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
@@ -3235,11 +3659,54 @@ function ArrayItemsEditor({
3235
3659
  )
3236
3660
  ] })
3237
3661
  ] }) : null,
3238
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "orion-builder-settings-note", children: [
3239
- "Select this item and use the ",
3240
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Media" }),
3241
- " group above for before/after image source and presentation."
3242
- ] })
3662
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3663
+ ItemMediaControl,
3664
+ {
3665
+ fieldName: "beforeMedia",
3666
+ imageURLFieldName: "beforeImageURL",
3667
+ item,
3668
+ itemIndex,
3669
+ label: "Before Image",
3670
+ maxHeight: 600,
3671
+ mediaLibrary,
3672
+ mediaLibraryError,
3673
+ mediaLibraryLoading,
3674
+ minHeight: 60,
3675
+ onRemoveItemMedia,
3676
+ onSelectItemMedia,
3677
+ onUpdateItemField,
3678
+ onUpdateItemMediaPresentation,
3679
+ onUploadItemMedia,
3680
+ searchQuery: normalizedQuery,
3681
+ uploadDisabled,
3682
+ uploadLabel: "Upload Before Image",
3683
+ uploading: Boolean(isItemMediaUploading?.(itemIndex, "beforeMedia"))
3684
+ }
3685
+ ),
3686
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3687
+ ItemMediaControl,
3688
+ {
3689
+ fieldName: "afterMedia",
3690
+ imageURLFieldName: "afterImageURL",
3691
+ item,
3692
+ itemIndex,
3693
+ label: "After Image",
3694
+ maxHeight: 600,
3695
+ mediaLibrary,
3696
+ mediaLibraryError,
3697
+ mediaLibraryLoading,
3698
+ minHeight: 60,
3699
+ onRemoveItemMedia,
3700
+ onSelectItemMedia,
3701
+ onUpdateItemField,
3702
+ onUpdateItemMediaPresentation,
3703
+ onUploadItemMedia,
3704
+ searchQuery: normalizedQuery,
3705
+ uploadDisabled,
3706
+ uploadLabel: "Upload After Image",
3707
+ uploading: Boolean(isItemMediaUploading?.(itemIndex, "afterMedia"))
3708
+ }
3709
+ )
3243
3710
  ] }) : null,
3244
3711
  blockType === "stats" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_jsx_runtime12.Fragment, { children: showInlineCopyFields ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
3245
3712
  /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { className: "orion-builder-settings-label", children: [
@@ -3404,6 +3871,19 @@ var resolveMedia = (value) => {
3404
3871
  }
3405
3872
  return null;
3406
3873
  };
3874
+ var mediaFromImageURL2 = (url, fallbackLabel = "Current image") => {
3875
+ if (typeof url !== "string" || url.trim().length === 0) {
3876
+ return null;
3877
+ }
3878
+ const normalizedURL = url.trim();
3879
+ const filename = normalizedURL.split("/").filter(Boolean).pop() || fallbackLabel;
3880
+ return {
3881
+ alt: fallbackLabel,
3882
+ filename,
3883
+ id: `url:${normalizedURL}`,
3884
+ url: normalizedURL
3885
+ };
3886
+ };
3407
3887
  var resolveMediaWithURL = (value, imageURL, alt) => {
3408
3888
  const resolved = resolveMedia(value);
3409
3889
  if (resolved?.url) {
@@ -3445,8 +3925,8 @@ var resolveBuilderMediumHeroHeight = (topViewportHeight) => {
3445
3925
  }
3446
3926
  return "50svh";
3447
3927
  };
3448
- var normalizeImageFit = (value) => normalizeHeroImageFit(value);
3449
- var normalizeImageCornerStyle = (value, legacyFitValue) => normalizeHeroImageCornerStyle(value, legacyFitValue);
3928
+ var normalizeImageFit2 = (value) => normalizeHeroImageFit(value);
3929
+ var normalizeImageCornerStyle2 = (value, legacyFitValue) => normalizeHeroImageCornerStyle(value, legacyFitValue);
3450
3930
  var positionPercent = (value, fit) => {
3451
3931
  const resolved = fit === "cover" && (value === "left" || value === "right") ? "center" : value;
3452
3932
  switch (resolved) {
@@ -3615,6 +4095,8 @@ var sectionPaddingMap = {
3615
4095
  md: "2.6rem",
3616
4096
  lg: "3.4rem"
3617
4097
  };
4098
+ var heroDefaultPaddingTop = "30pt";
4099
+ var heroDefaultPaddingBottom = "20pt";
3618
4100
  var quickAddBlockTypes = [
3619
4101
  "hero",
3620
4102
  "featureGrid",
@@ -3878,6 +4360,12 @@ function getThemeColorOverride(tokens, colorKey) {
3878
4360
  const normalized = value.trim();
3879
4361
  return normalized.length > 0 ? normalized : null;
3880
4362
  }
4363
+ function normalizeCustomClassName(value) {
4364
+ if (typeof value !== "string") {
4365
+ return "";
4366
+ }
4367
+ return value.split(/\s+/).map((className) => className.trim()).filter(Boolean).join(" ");
4368
+ }
3881
4369
  var sectionStyleFromBlock = (block, pageDefaults) => {
3882
4370
  const settings = isRecord6(block.settings) ? block.settings : {};
3883
4371
  const layoutSettings = isRecord6(settings.layout) ? settings.layout : {};
@@ -3963,15 +4451,15 @@ var sectionStyleFromBlock = (block, pageDefaults) => {
3963
4451
  } : {},
3964
4452
  sectionClass: `orion-builder-shell is-${pageDefaults.pageWidthDefault} padx-${resolvedSectionPaddingX}`,
3965
4453
  sectionInnerStyle: {
3966
- paddingBottom: customPaddingBottom === null ? sectionPaddingMap[sectionPaddingY] : `${customPaddingBottom}pt`,
4454
+ paddingBottom: customPaddingBottom === null ? block.blockType === "hero" ? heroDefaultPaddingBottom : sectionPaddingMap[sectionPaddingY] : `${customPaddingBottom}pt`,
3967
4455
  paddingLeft: customPaddingLeft === null ? void 0 : `${customPaddingLeft}pt`,
3968
4456
  paddingRight: customPaddingRight === null ? void 0 : `${customPaddingRight}pt`,
3969
- paddingTop: customPaddingTop === null ? sectionPaddingMap[sectionPaddingY] : `${customPaddingTop}pt`
4457
+ paddingTop: customPaddingTop === null ? block.blockType === "hero" ? heroDefaultPaddingTop : sectionPaddingMap[sectionPaddingY] : `${customPaddingTop}pt`
3970
4458
  },
3971
4459
  sectionStyle: sectionMode === "color" ? { background: sectionColor } : sectionMode === "gradient" ? { background: sectionGradient } : block.blockType === "hero" ? { background: "transparent" } : {}
3972
4460
  };
3973
4461
  };
3974
- function getRelationID2(value) {
4462
+ function getRelationID3(value) {
3975
4463
  if (typeof value === "number" || typeof value === "string") {
3976
4464
  return value;
3977
4465
  }
@@ -4004,7 +4492,7 @@ function extractUploadedMedia(value) {
4004
4492
  if (!candidate || typeof candidate !== "object") {
4005
4493
  return null;
4006
4494
  }
4007
- const id = getRelationID2(candidate);
4495
+ const id = getRelationID3(candidate);
4008
4496
  if (id === null) {
4009
4497
  return null;
4010
4498
  }
@@ -4015,11 +4503,11 @@ function extractUploadedMedia(value) {
4015
4503
  url: typeof candidate.url === "string" ? candidate.url : ""
4016
4504
  };
4017
4505
  }
4018
- function toMediaLibraryItem2(value) {
4506
+ function toMediaLibraryItem3(value) {
4019
4507
  if (!value || typeof value !== "object") {
4020
4508
  return null;
4021
4509
  }
4022
- const id = getRelationID2(value);
4510
+ const id = getRelationID3(value);
4023
4511
  if (id === null) {
4024
4512
  return null;
4025
4513
  }
@@ -4152,7 +4640,7 @@ function BuilderPageEditor({
4152
4640
  const selectedBlockAdvancedSettings = isRecord6(selectedBlockSettings.advanced) ? selectedBlockSettings.advanced : {};
4153
4641
  const isArrayItemBlockSelected = selectedType === "featureGrid" || selectedType === "logoWall" || selectedType === "beforeAfter" || selectedType === "stats" || selectedType === "faq" || selectedType === "testimonials";
4154
4642
  const selectedBlockHasMediaSource = selectedType === "hero" || selectedType === "media";
4155
- const selectedBlockMediaValue = selectedType === "hero" ? selectedBlock?.media : selectedType === "media" ? selectedBlock?.image : null;
4643
+ const selectedBlockMediaValue = selectedType === "hero" ? selectedBlock?.media ?? mediaFromImageURL2(selectedBlock?.backgroundImageURL, "Hero image") : selectedType === "media" ? selectedBlock?.image ?? mediaFromImageURL2(selectedBlock?.imageURL, "Section image") : null;
4156
4644
  const selectedItemRecord = typeof selectedItemIndex === "number" && selectedItemIndex >= 0 && selectedItemIndex < selectedItems.length && isRecord6(selectedItems[selectedItemIndex]) ? selectedItems[selectedItemIndex] : null;
4157
4645
  const editCopyInPanelEnabled = Boolean(selectedBlockAdvancedSettings.editCopyInPanel);
4158
4646
  const isBlockUploadTarget = (blockIndex, kind) => selectedIndex === blockIndex && uploadingTarget?.kind === kind;
@@ -4197,7 +4685,7 @@ function BuilderPageEditor({
4197
4685
  }
4198
4686
  const json = await response.json();
4199
4687
  const docs = Array.isArray(json.docs) ? json.docs : [];
4200
- const items = docs.map((doc2) => toMediaLibraryItem2(doc2)).filter((item) => item !== null);
4688
+ const items = docs.map((doc2) => toMediaLibraryItem3(doc2)).filter((item) => item !== null);
4201
4689
  setMediaLibrary(items);
4202
4690
  } catch (error) {
4203
4691
  setMediaLibraryError(error instanceof Error ? error.message : "Could not load media library.");
@@ -4551,7 +5039,7 @@ function BuilderPageEditor({
4551
5039
  const nextLayout = cloneBlockLayout(layout);
4552
5040
  const block = nextLayout[selectedIndex];
4553
5041
  if (target.kind === "hero") {
4554
- const uploadedItem = toMediaLibraryItem2(uploaded);
5042
+ const uploadedItem = toMediaLibraryItem3(uploaded);
4555
5043
  nextLayout[selectedIndex] = {
4556
5044
  ...block,
4557
5045
  backgroundImageURL: uploadedItem?.url || normalizeText2(uploaded.url),
@@ -4615,13 +5103,13 @@ function BuilderPageEditor({
4615
5103
  const nextBlock = { ...migrateBlockToSettingsV2(block) };
4616
5104
  const blockType = normalizeText2(nextBlock.blockType);
4617
5105
  if (blockType === "hero") {
4618
- const mediaID = getRelationID2(nextBlock.media);
5106
+ const mediaID = getRelationID3(nextBlock.media);
4619
5107
  if (mediaID !== null) {
4620
5108
  nextBlock.media = mediaID;
4621
5109
  }
4622
5110
  }
4623
5111
  if (blockType === "media") {
4624
- const imageID = getRelationID2(nextBlock.image);
5112
+ const imageID = getRelationID3(nextBlock.image);
4625
5113
  if (imageID !== null) {
4626
5114
  nextBlock.image = imageID;
4627
5115
  }
@@ -4633,15 +5121,15 @@ function BuilderPageEditor({
4633
5121
  return rawItem;
4634
5122
  }
4635
5123
  const nextItem = { ...rawItem };
4636
- const mediaID = getRelationID2(nextItem.media);
5124
+ const mediaID = getRelationID3(nextItem.media);
4637
5125
  if (mediaID !== null) {
4638
5126
  nextItem.media = mediaID;
4639
5127
  }
4640
- const beforeMediaID = getRelationID2(nextItem.beforeMedia);
5128
+ const beforeMediaID = getRelationID3(nextItem.beforeMedia);
4641
5129
  if (beforeMediaID !== null) {
4642
5130
  nextItem.beforeMedia = beforeMediaID;
4643
5131
  }
4644
- const afterMediaID = getRelationID2(nextItem.afterMedia);
5132
+ const afterMediaID = getRelationID3(nextItem.afterMedia);
4645
5133
  if (afterMediaID !== null) {
4646
5134
  nextItem.afterMedia = afterMediaID;
4647
5135
  }
@@ -4697,6 +5185,7 @@ function BuilderPageEditor({
4697
5185
  const inheritProjectStyles = options?.inheritProjectStyles === true;
4698
5186
  const shell = sectionStyleFromBlock(block, pageDefaults);
4699
5187
  const blockSettings = isRecord6(block.settings) ? block.settings : {};
5188
+ const blockAdvanced = isRecord6(blockSettings.advanced) ? blockSettings.advanced : {};
4700
5189
  const blockTypography = isRecord6(blockSettings.typography) ? blockSettings.typography : {};
4701
5190
  const blockTheme = isRecord6(blockSettings.theme) ? blockSettings.theme : {};
4702
5191
  const heroBackgroundColor = normalizeText2(block.backgroundColor).trim();
@@ -4704,23 +5193,35 @@ function BuilderPageEditor({
4704
5193
  const heroMedia = block.blockType === "hero" ? resolveMedia(block.media) : null;
4705
5194
  const heroHasImage = block.blockType === "hero" && Boolean(heroBackgroundImageURL || heroMedia?.url);
4706
5195
  const heroTextColor = block.blockType === "hero" ? heroHasImage ? "#ffffff" : heroBackgroundColor ? getReadableTextColor(heroBackgroundColor, resolvedThemeTokens.colors.headingText, "#ffffff") : resolvedThemeTokens.colors.headingText : null;
5196
+ const bodyAlign = blockTypography.bodyAlign === "center" || blockTypography.bodyAlign === "justify" || blockTypography.bodyAlign === "right" ? blockTypography.bodyAlign : "left";
4707
5197
  const typographyStyle = resolveTypographyStyleFromSettings({
4708
- bodyAlign: blockTypography.bodyAlign === "center" || blockTypography.bodyAlign === "justify" || blockTypography.bodyAlign === "right" ? blockTypography.bodyAlign : "left",
5198
+ bodyAlign,
4709
5199
  letterSpacingPreset: blockTypography.letterSpacingPreset === "tight" || blockTypography.letterSpacingPreset === "relaxed" ? blockTypography.letterSpacingPreset : "normal",
4710
5200
  lineHeightPreset: blockTypography.lineHeightPreset === "tight" || blockTypography.lineHeightPreset === "relaxed" ? blockTypography.lineHeightPreset : "normal",
5201
+ bodySizePt: typeof blockTypography.bodySizePt === "number" && Number.isFinite(blockTypography.bodySizePt) ? blockTypography.bodySizePt : null,
4711
5202
  maxTextWidth: blockTypography.maxTextWidth === "sm" || blockTypography.maxTextWidth === "md" || blockTypography.maxTextWidth === "lg" || blockTypography.maxTextWidth === "full" ? blockTypography.maxTextWidth : "auto"
4712
5203
  });
4713
5204
  const headingAlign = blockTypography.headingAlign === "center" || blockTypography.headingAlign === "justify" || blockTypography.headingAlign === "right" ? blockTypography.headingAlign : "left";
4714
5205
  const headingColor = getThemeColorOverride(blockTheme, "headingText") || getThemeColorOverride(pageDefaults.themePage, "headingText") || getThemeColorOverride(siteThemeTokens, "headingText") || heroTextColor || resolvedThemeTokens.colors.headingText;
4715
5206
  const bodyColor = getThemeColorOverride(blockTheme, "bodyText") || getThemeColorOverride(pageDefaults.themePage, "bodyText") || getThemeColorOverride(siteThemeTokens, "bodyText") || heroTextColor || resolvedThemeTokens.colors.bodyText;
4716
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("section", { className: `${className} ${shell.sectionClass}`, style: shell.sectionStyle, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: shell.sectionInnerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5207
+ const customClassName = normalizeCustomClassName(blockAdvanced.customClassName ?? block.customClassName);
5208
+ const hideOnMobile = Boolean(blockAdvanced.hideOnMobile ?? block.hideOnMobile);
5209
+ const sectionClassName = [
5210
+ className,
5211
+ shell.sectionClass,
5212
+ customClassName,
5213
+ hideOnMobile ? "orion-builder-hide-mobile" : ""
5214
+ ].filter(Boolean).join(" ");
5215
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("section", { className: sectionClassName, style: shell.sectionStyle, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: shell.sectionInnerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4717
5216
  "div",
4718
5217
  {
4719
5218
  className: shell.contentClass,
4720
5219
  style: {
4721
5220
  ...shell.contentStyle,
5221
+ "--orion-builder-heading-align": headingAlign,
5222
+ "--orion-builder-body-align": bodyAlign,
5223
+ "--orion-builder-actions-align": bodyAlign === "center" ? "center" : bodyAlign === "right" ? "flex-end" : "flex-start",
4722
5224
  ...inheritProjectStyles ? {} : {
4723
- "--orion-builder-heading-align": headingAlign,
4724
5225
  "--orion-builder-heading-color": headingColor,
4725
5226
  color: bodyColor,
4726
5227
  ...typographyStyle
@@ -5207,8 +5708,8 @@ function BuilderPageEditor({
5207
5708
  }
5208
5709
  ] : [];
5209
5710
  const selectedMediaImageControls = selectedItemRecord && typeof selectedItemIndex === "number" && (selectedType === "featureGrid" || selectedType === "logoWall" || selectedType === "beforeAfter") ? {
5210
- cornerStyle: normalizeImageCornerStyle(selectedItemRecord.imageCornerStyle),
5211
- fit: normalizeImageFit(selectedItemRecord.imageFit),
5711
+ cornerStyle: normalizeImageCornerStyle2(selectedItemRecord.imageCornerStyle),
5712
+ fit: normalizeImageFit2(selectedItemRecord.imageFit),
5212
5713
  height: (() => {
5213
5714
  if (typeof selectedItemRecord.imageHeight === "number" && Number.isFinite(selectedItemRecord.imageHeight)) {
5214
5715
  return selectedItemRecord.imageHeight;
@@ -5683,8 +6184,8 @@ function BuilderPageEditor({
5683
6184
  const itemPositionX = parseOptionalPercentNumber2(itemRecord?.imagePositionX);
5684
6185
  const itemPositionY = parseOptionalPercentNumber2(itemRecord?.imagePositionY);
5685
6186
  const itemImageStyle = getImagePresentationStyle({
5686
- cornerStyle: normalizeImageCornerStyle(itemRecord?.imageCornerStyle),
5687
- fit: normalizeImageFit(itemRecord?.imageFit),
6187
+ cornerStyle: normalizeImageCornerStyle2(itemRecord?.imageCornerStyle),
6188
+ fit: normalizeImageFit2(itemRecord?.imageFit),
5688
6189
  positionX: itemPositionX,
5689
6190
  positionY: itemPositionY
5690
6191
  });
@@ -5801,8 +6302,8 @@ function BuilderPageEditor({
5801
6302
  const itemPositionX = parseOptionalPercentNumber2(itemRecord?.imagePositionX);
5802
6303
  const itemPositionY = parseOptionalPercentNumber2(itemRecord?.imagePositionY);
5803
6304
  const itemImageStyle = getImagePresentationStyle({
5804
- cornerStyle: normalizeImageCornerStyle(itemRecord?.imageCornerStyle),
5805
- fit: normalizeImageFit(itemRecord?.imageFit),
6305
+ cornerStyle: normalizeImageCornerStyle2(itemRecord?.imageCornerStyle),
6306
+ fit: normalizeImageFit2(itemRecord?.imageFit),
5806
6307
  positionX: itemPositionX,
5807
6308
  positionY: itemPositionY
5808
6309
  });
@@ -6008,8 +6509,8 @@ function BuilderPageEditor({
6008
6509
  const itemPositionX = parseOptionalPercentNumber2(itemRecord?.imagePositionX);
6009
6510
  const itemPositionY = parseOptionalPercentNumber2(itemRecord?.imagePositionY);
6010
6511
  const imageStyle = getImagePresentationStyle({
6011
- cornerStyle: normalizeImageCornerStyle(itemRecord?.imageCornerStyle),
6012
- fit: normalizeImageFit(itemRecord?.imageFit),
6512
+ cornerStyle: normalizeImageCornerStyle2(itemRecord?.imageCornerStyle),
6513
+ fit: normalizeImageFit2(itemRecord?.imageFit),
6013
6514
  positionX: itemPositionX,
6014
6515
  positionY: itemPositionY,
6015
6516
  roundedRadius: 10
@@ -6122,8 +6623,8 @@ function BuilderPageEditor({
6122
6623
  const itemPositionX = parseOptionalPercentNumber2(itemRecord?.imagePositionX);
6123
6624
  const itemPositionY = parseOptionalPercentNumber2(itemRecord?.imagePositionY);
6124
6625
  const imageStyle = getImagePresentationStyle({
6125
- cornerStyle: normalizeImageCornerStyle(itemRecord?.imageCornerStyle),
6126
- fit: normalizeImageFit(itemRecord?.imageFit),
6626
+ cornerStyle: normalizeImageCornerStyle2(itemRecord?.imageCornerStyle),
6627
+ fit: normalizeImageFit2(itemRecord?.imageFit),
6127
6628
  positionX: itemPositionX,
6128
6629
  positionY: itemPositionY
6129
6630
  });
@@ -6429,8 +6930,8 @@ function BuilderPageEditor({
6429
6930
  getImagePresentationStyle,
6430
6931
  index,
6431
6932
  isBlockUploadTarget,
6432
- normalizeImageCornerStyle,
6433
- normalizeImageFit,
6933
+ normalizeImageCornerStyle: normalizeImageCornerStyle2,
6934
+ normalizeImageFit: normalizeImageFit2,
6434
6935
  normalizeText: normalizeText2,
6435
6936
  onDropAt,
6436
6937
  renderWithSectionShell,
@@ -6659,23 +7160,32 @@ function BuilderPageEditor({
6659
7160
  blockType: selectedType,
6660
7161
  expandedItemIndex,
6661
7162
  items: selectedItems,
7163
+ isItemMediaUploading: isSelectedItemMediaUploading,
7164
+ mediaLibrary,
7165
+ mediaLibraryError,
7166
+ mediaLibraryLoading,
6662
7167
  mode: settingsPanelMode,
6663
7168
  onAddItem: appendDefaultItemToSelected,
6664
7169
  onRemoveItem: (itemIndex) => removeItemFromSelected("items", itemIndex),
7170
+ onRemoveItemMedia: (itemIndex, fieldName) => setSelectedItemMediaFieldFromLibrary(itemIndex, fieldName, ""),
7171
+ onSelectItemMedia: (itemIndex, fieldName, mediaID) => setSelectedItemMediaFieldFromLibrary(itemIndex, fieldName, mediaID),
6665
7172
  onToggleItem: toggleSelectedItem,
6666
7173
  onUpdateItemField: (itemIndex, fieldName, value) => updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, fieldName, value),
7174
+ onUpdateItemMediaPresentation: (itemIndex, fieldName, value) => updateArrayItemSettingField(selectedIndex ?? 0, "items", itemIndex, `media.${fieldName}`, value),
6667
7175
  onUpdateItemSetting: (itemIndex, path, value) => updateArrayItemSettingField(selectedIndex ?? 0, "items", itemIndex, path, value),
7176
+ onUploadItemMedia: uploadItemMediaFromV2,
6668
7177
  searchQuery: settingsSearchQuery,
6669
- showInlineCopyFields: editCopyInPanelEnabled
7178
+ showInlineCopyFields: editCopyInPanelEnabled,
7179
+ uploadDisabled: uploadingTarget !== null
6670
7180
  }
6671
7181
  ) : null,
6672
7182
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { style: sidebarLabelStyle, children: [
6673
- "Upload Alt Text",
7183
+ "New Upload Alt Text",
6674
7184
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
6675
7185
  "input",
6676
7186
  {
6677
7187
  onChange: (event) => setUploadAltText(event.target.value),
6678
- placeholder: "Describe the image",
7188
+ placeholder: "Used only when uploading a new image",
6679
7189
  style: sidebarInputStyle,
6680
7190
  type: "text",
6681
7191
  value: uploadAltText