@orion-studios/payload-studio 0.6.0-beta.3 → 0.6.0-beta.30

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 (36) hide show
  1. package/dist/admin/client.d.mts +1 -1
  2. package/dist/admin/client.d.ts +1 -1
  3. package/dist/admin/client.js +4160 -1732
  4. package/dist/admin/client.mjs +4240 -1818
  5. package/dist/admin/index.d.mts +2 -2
  6. package/dist/admin/index.d.ts +2 -2
  7. package/dist/admin/index.js +140 -17
  8. package/dist/admin/index.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 +705 -41
  12. package/dist/admin.css +18 -2
  13. package/dist/{chunk-PF3EBZXF.mjs → chunk-4LSIUED5.mjs} +7 -2
  14. package/dist/{chunk-XKUTZ7IU.mjs → chunk-EDW7DPXW.mjs} +1 -1
  15. package/dist/{chunk-OTHERBGX.mjs → chunk-H4GTEY24.mjs} +1 -1
  16. package/dist/{chunk-QJAWO6K3.mjs → chunk-JC3UV74N.mjs} +140 -17
  17. package/dist/index-BV0vEGl6.d.ts +188 -0
  18. package/dist/{index-52HdVLQq.d.ts → index-DAdN56fM.d.ts} +1 -1
  19. package/dist/index-DLfPOqYA.d.mts +188 -0
  20. package/dist/{index-DEQC3Dwj.d.mts → index-G_uTNffQ.d.mts} +1 -1
  21. package/dist/index.d.mts +3 -3
  22. package/dist/index.d.ts +3 -3
  23. package/dist/index.js +147 -19
  24. package/dist/index.mjs +4 -4
  25. package/dist/nextjs/index.js +7 -2
  26. package/dist/nextjs/index.mjs +2 -2
  27. package/dist/{sitePreviewTypes-BkHCWxNW.d.mts → sitePreviewTypes-BrJwGzJj.d.mts} +1 -1
  28. package/dist/{sitePreviewTypes-BkHCWxNW.d.ts → sitePreviewTypes-BrJwGzJj.d.ts} +1 -1
  29. package/dist/studio-pages/builder.css +24 -5
  30. package/dist/studio-pages/client.js +374 -54
  31. package/dist/studio-pages/client.mjs +374 -54
  32. package/dist/studio-pages/index.js +7 -2
  33. package/dist/studio-pages/index.mjs +2 -2
  34. package/package.json +1 -1
  35. package/dist/index-B6_D4Hm4.d.ts +0 -439
  36. package/dist/index-CYaWadBl.d.mts +0 -439
@@ -129,6 +129,7 @@ var defaultBuilderThemeTokens = {
129
129
 
130
130
  // src/studio-pages/builder/adapters/settingsV2.ts
131
131
  var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
132
+ var isTextAlign = (value) => value === "left" || value === "center" || value === "right" || value === "justify";
132
133
  var parsePercent = (value) => {
133
134
  if (typeof value === "number" && Number.isFinite(value)) {
134
135
  return Math.max(0, Math.min(100, value));
@@ -171,6 +172,10 @@ var mergeSettings = (defaults, input) => {
171
172
  };
172
173
  var legacyBlockToV2Settings = (block) => {
173
174
  const current = structuredClone(defaultBuilderBlockSettingsV2);
175
+ if (block.blockType === "hero" && block.variant === "centered") {
176
+ current.typography.headingAlign = "center";
177
+ current.typography.bodyAlign = "center";
178
+ }
174
179
  current.layout.contentWidth = block.contentWidth === "narrow" || block.contentWidth === "content" || block.contentWidth === "wide" || block.contentWidth === "full" || block.contentWidth === "inherit" ? block.contentWidth : current.layout.contentWidth;
175
180
  current.layout.sectionPaddingX = block.sectionPaddingX === "none" || block.sectionPaddingX === "sm" || block.sectionPaddingX === "md" || block.sectionPaddingX === "lg" || block.sectionPaddingX === "inherit" ? block.sectionPaddingX : current.layout.sectionPaddingX;
176
181
  current.layout.sectionPaddingY = block.sectionPaddingY === "none" || block.sectionPaddingY === "sm" || block.sectionPaddingY === "lg" ? block.sectionPaddingY : current.layout.sectionPaddingY;
@@ -207,8 +212,8 @@ var legacyBlockToV2Settings = (block) => {
207
212
  current.media.positionX = parsePercent(block.imagePositionX ?? block.backgroundImagePositionX);
208
213
  current.media.positionY = parsePercent(block.imagePositionY ?? block.backgroundImagePositionY);
209
214
  current.media.height = parsePixel(block.imageHeight);
210
- current.typography.headingAlign = block.textHeadingAlign === "left" || block.textHeadingAlign === "center" || block.textHeadingAlign === "right" || block.textHeadingAlign === "justify" ? block.textHeadingAlign : current.typography.headingAlign;
211
- current.typography.bodyAlign = block.textBodyAlign === "left" || block.textBodyAlign === "center" || block.textBodyAlign === "right" || block.textBodyAlign === "justify" ? block.textBodyAlign : current.typography.bodyAlign;
215
+ current.typography.headingAlign = isTextAlign(block.textHeadingAlign) ? block.textHeadingAlign : current.typography.headingAlign;
216
+ current.typography.bodyAlign = isTextAlign(block.textBodyAlign) ? block.textBodyAlign : current.typography.bodyAlign;
212
217
  current.typography.maxTextWidth = block.textMaxWidth === "auto" || block.textMaxWidth === "sm" || block.textMaxWidth === "md" || block.textMaxWidth === "lg" || block.textMaxWidth === "full" ? block.textMaxWidth : current.typography.maxTextWidth;
213
218
  current.typography.lineHeightPreset = block.textLineHeightPreset === "tight" || block.textLineHeightPreset === "normal" || block.textLineHeightPreset === "relaxed" ? block.textLineHeightPreset : current.typography.lineHeightPreset;
214
219
  current.typography.letterSpacingPreset = block.textLetterSpacingPreset === "tight" || block.textLetterSpacingPreset === "normal" || block.textLetterSpacingPreset === "relaxed" ? block.textLetterSpacingPreset : current.typography.letterSpacingPreset;
@@ -925,6 +930,12 @@ var toMediaLibraryItem = (value) => {
925
930
  };
926
931
  };
927
932
  var mediaLabel = (item) => item.filename || item.alt || `Media #${item.id}`;
933
+ var findMediaLibraryItem = (library, id) => {
934
+ if (id === null) {
935
+ return null;
936
+ }
937
+ return library.find((item) => String(item.id) === String(id)) || null;
938
+ };
928
939
  var groupLabel = (key) => commonInspectorGroups.find((group) => group.key === key)?.label || key;
929
940
  function BlockInspectorRenderer({
930
941
  block,
@@ -1048,8 +1059,9 @@ function BlockInspectorRenderer({
1048
1059
  title: group.label,
1049
1060
  children: /* @__PURE__ */ jsxs3("div", { className: "orion-builder-settings-field-list", children: [
1050
1061
  group.key === "media" ? effectiveMediaSources.map((source) => {
1051
- const selectedSourceMedia = toMediaLibraryItem(source.value);
1052
1062
  const selectedSourceMediaID = getRelationID(source.value);
1063
+ const selectedRelationMedia = toMediaLibraryItem(source.value);
1064
+ const selectedSourceMedia = selectedRelationMedia ?? findMediaLibraryItem(source.library, selectedSourceMediaID);
1053
1065
  const sourceOptions = selectedSourceMedia && !source.library.some((item) => String(item.id) === String(selectedSourceMedia.id)) ? [selectedSourceMedia, ...source.library] : source.library;
1054
1066
  return /* @__PURE__ */ jsxs3(
1055
1067
  "div",
@@ -1074,6 +1086,10 @@ function BlockInspectorRenderer({
1074
1086
  }
1075
1087
  )
1076
1088
  ] }),
1089
+ selectedSourceMedia?.alt ? /* @__PURE__ */ jsxs3("label", { className: "orion-builder-settings-label", children: [
1090
+ "Media Description",
1091
+ /* @__PURE__ */ jsx3("input", { className: "orion-builder-settings-input", readOnly: true, type: "text", value: selectedSourceMedia.alt })
1092
+ ] }) : selectedSourceMediaID !== null ? /* @__PURE__ */ jsx3("div", { className: "orion-builder-settings-note", children: "This media item does not have a description yet." }) : null,
1077
1093
  /* @__PURE__ */ jsx3(
1078
1094
  "button",
1079
1095
  {
@@ -2129,8 +2145,8 @@ function renderSimpleBlockPreview(args) {
2129
2145
  getImagePresentationStyle: getImagePresentationStyle2,
2130
2146
  index,
2131
2147
  isBlockUploadTarget,
2132
- normalizeImageCornerStyle: normalizeImageCornerStyle2,
2133
- normalizeImageFit: normalizeImageFit2,
2148
+ normalizeImageCornerStyle: normalizeImageCornerStyle3,
2149
+ normalizeImageFit: normalizeImageFit3,
2134
2150
  normalizeText: normalizeText3,
2135
2151
  onDropAt,
2136
2152
  renderWithSectionShell,
@@ -2314,8 +2330,8 @@ function renderSimpleBlockPreview(args) {
2314
2330
  const imagePositionX = parseOptionalPercentNumber(mediaSettings.positionX ?? block?.imagePositionX);
2315
2331
  const imagePositionY = parseOptionalPercentNumber(mediaSettings.positionY ?? block?.imagePositionY);
2316
2332
  const imageStyle = getImagePresentationStyle2({
2317
- cornerStyle: normalizeImageCornerStyle2(mediaSettings.cornerStyle ?? block?.imageCornerStyle),
2318
- fit: normalizeImageFit2(mediaSettings.fit ?? block?.imageFit),
2333
+ cornerStyle: normalizeImageCornerStyle3(mediaSettings.cornerStyle ?? block?.imageCornerStyle),
2334
+ fit: normalizeImageFit3(mediaSettings.fit ?? block?.imageFit),
2319
2335
  positionX: imagePositionX,
2320
2336
  positionY: imagePositionY
2321
2337
  });
@@ -2845,6 +2861,63 @@ var normalizeNumber2 = (value, fallback) => {
2845
2861
  return fallback;
2846
2862
  };
2847
2863
  var clamp = (value, min, max) => Math.max(min, Math.min(max, value));
2864
+ var getRelationID2 = (value) => {
2865
+ if (typeof value === "number" || typeof value === "string") {
2866
+ return value;
2867
+ }
2868
+ if (!isRecord5(value)) {
2869
+ return null;
2870
+ }
2871
+ const id = value.id;
2872
+ return typeof id === "number" || typeof id === "string" ? id : null;
2873
+ };
2874
+ var toMediaLibraryItem2 = (value) => {
2875
+ if (!isRecord5(value)) {
2876
+ return null;
2877
+ }
2878
+ const id = getRelationID2(value);
2879
+ if (id === null) {
2880
+ return null;
2881
+ }
2882
+ const filename = typeof value.filename === "string" ? value.filename : "";
2883
+ const url = typeof value.url === "string" && value.url.length > 0 ? value.url : filename ? `/api/media/file/${encodeURIComponent(filename)}` : "";
2884
+ return {
2885
+ alt: typeof value.alt === "string" ? value.alt : "",
2886
+ filename,
2887
+ id,
2888
+ url
2889
+ };
2890
+ };
2891
+ var mediaLabel2 = (item) => item.filename || item.alt || `Media #${item.id}`;
2892
+ var findMediaLibraryItem2 = (library, id) => {
2893
+ if (id === null) {
2894
+ return null;
2895
+ }
2896
+ return library.find((item) => String(item.id) === String(id)) || null;
2897
+ };
2898
+ var normalizeImageFit = (value) => value === "contain" ? "contain" : "cover";
2899
+ var normalizeImageCornerStyle = (value) => value === "square" ? "square" : "rounded";
2900
+ var getItemMediaSettings = (item) => {
2901
+ const settings = isRecord5(item.settings) ? item.settings : {};
2902
+ const media = isRecord5(settings.media) ? settings.media : {};
2903
+ return {
2904
+ cornerStyle: normalizeImageCornerStyle(media.cornerStyle ?? item.imageCornerStyle),
2905
+ fit: normalizeImageFit(media.fit ?? item.imageFit),
2906
+ height: (() => {
2907
+ const value = media.height ?? item.imageHeight;
2908
+ if (typeof value === "number" && Number.isFinite(value)) {
2909
+ return value;
2910
+ }
2911
+ if (typeof value === "string" && value.trim().length > 0) {
2912
+ const parsed = Number(value);
2913
+ return Number.isFinite(parsed) ? parsed : null;
2914
+ }
2915
+ return null;
2916
+ })(),
2917
+ positionX: clamp(normalizeNumber2(media.positionX ?? item.imagePositionX, 50), 0, 100),
2918
+ positionY: clamp(normalizeNumber2(media.positionY ?? item.imagePositionY, 50), 0, 100)
2919
+ };
2920
+ };
2848
2921
  var hasQueryMatch = (query, ...values) => {
2849
2922
  const normalized = query.trim().toLowerCase();
2850
2923
  if (!normalized) {
@@ -2891,18 +2964,157 @@ var bulletsToTextareaValue = (value) => {
2891
2964
  return value.map((item) => isRecord5(item) && typeof item.label === "string" ? item.label.trim() : "").filter(Boolean).join("\n");
2892
2965
  };
2893
2966
  var textareaValueToBullets = (value) => value.split("\n").map((line) => line.trim()).filter(Boolean).map((label) => ({ label }));
2967
+ function ItemMediaControl({
2968
+ fieldName,
2969
+ imageURLFieldName,
2970
+ item,
2971
+ itemIndex,
2972
+ label,
2973
+ mediaLibrary,
2974
+ mediaLibraryError,
2975
+ mediaLibraryLoading,
2976
+ maxHeight,
2977
+ minHeight,
2978
+ onRemoveItemMedia,
2979
+ onSelectItemMedia,
2980
+ onUpdateItemField,
2981
+ onUpdateItemMediaPresentation,
2982
+ onUploadItemMedia,
2983
+ searchQuery,
2984
+ uploadDisabled,
2985
+ uploadLabel,
2986
+ uploading
2987
+ }) {
2988
+ const selectedMediaID = getRelationID2(item[fieldName]);
2989
+ const selectedRelationMedia = toMediaLibraryItem2(item[fieldName]);
2990
+ const selectedMedia = selectedRelationMedia ?? findMediaLibraryItem2(mediaLibrary, selectedMediaID);
2991
+ const directImageURL = normalizeText(item[imageURLFieldName]);
2992
+ const previewURL = selectedMedia?.url || directImageURL;
2993
+ const mediaSettings = getItemMediaSettings(item);
2994
+ const sourceOptions = selectedMedia && !mediaLibrary.some((libraryItem) => String(libraryItem.id) === String(selectedMedia.id)) ? [selectedMedia, ...mediaLibrary] : mediaLibrary;
2995
+ if (!hasQueryMatch(searchQuery, label, "image", "media", "photo", "picture", "url", "fit", "crop", "height")) {
2996
+ return null;
2997
+ }
2998
+ return /* @__PURE__ */ jsxs11("div", { className: "orion-builder-settings-item-card", style: { padding: "0.56rem" }, children: [
2999
+ /* @__PURE__ */ jsx12("div", { className: "orion-builder-settings-label", children: label }),
3000
+ previewURL ? (
3001
+ // eslint-disable-next-line @next/next/no-img-element
3002
+ /* @__PURE__ */ jsx12(
3003
+ "img",
3004
+ {
3005
+ alt: selectedMedia?.alt || label,
3006
+ src: previewURL,
3007
+ style: {
3008
+ aspectRatio: "16 / 9",
3009
+ border: "1px solid rgba(35, 51, 82, 0.14)",
3010
+ borderRadius: mediaSettings.cornerStyle === "square" ? 4 : 10,
3011
+ display: "block",
3012
+ objectFit: mediaSettings.fit,
3013
+ objectPosition: `${mediaSettings.positionX}% ${mediaSettings.positionY}%`,
3014
+ width: "100%"
3015
+ }
3016
+ }
3017
+ )
3018
+ ) : /* @__PURE__ */ jsx12("div", { className: "orion-builder-settings-empty", children: "No image selected." }),
3019
+ mediaLibraryLoading ? /* @__PURE__ */ jsx12("div", { className: "orion-builder-settings-note", children: "Loading media library..." }) : null,
3020
+ mediaLibraryError ? /* @__PURE__ */ jsx12("div", { className: "orion-builder-settings-error", children: mediaLibraryError }) : null,
3021
+ /* @__PURE__ */ jsxs11("label", { className: "orion-builder-settings-label", children: [
3022
+ "Media Library Image",
3023
+ /* @__PURE__ */ jsxs11(
3024
+ "select",
3025
+ {
3026
+ className: "orion-builder-settings-input",
3027
+ onChange: (event) => onSelectItemMedia?.(itemIndex, fieldName, event.target.value),
3028
+ value: selectedMediaID !== null ? String(selectedMediaID) : "",
3029
+ children: [
3030
+ /* @__PURE__ */ jsx12("option", { value: "", children: "No library image" }),
3031
+ sourceOptions.map((libraryItem) => /* @__PURE__ */ jsx12("option", { value: String(libraryItem.id), children: mediaLabel2(libraryItem) }, String(libraryItem.id)))
3032
+ ]
3033
+ }
3034
+ )
3035
+ ] }),
3036
+ selectedMedia?.alt ? /* @__PURE__ */ jsxs11("label", { className: "orion-builder-settings-label", children: [
3037
+ "Media Description",
3038
+ /* @__PURE__ */ jsx12("input", { className: "orion-builder-settings-input", readOnly: true, type: "text", value: selectedMedia.alt })
3039
+ ] }) : selectedMediaID !== null ? /* @__PURE__ */ jsx12("div", { className: "orion-builder-settings-note", children: "This media item does not have a description yet." }) : null,
3040
+ /* @__PURE__ */ jsx12(
3041
+ "button",
3042
+ {
3043
+ className: "orion-builder-settings-inline-btn",
3044
+ disabled: selectedMediaID === null,
3045
+ onClick: () => onRemoveItemMedia?.(itemIndex, fieldName),
3046
+ type: "button",
3047
+ children: "Remove Library Image"
3048
+ }
3049
+ ),
3050
+ /* @__PURE__ */ jsxs11("label", { className: "orion-builder-settings-label", children: [
3051
+ "Direct Image URL",
3052
+ /* @__PURE__ */ jsx12(
3053
+ "input",
3054
+ {
3055
+ className: "orion-builder-settings-input",
3056
+ onChange: (event) => onUpdateItemField(itemIndex, imageURLFieldName, event.target.value),
3057
+ type: "text",
3058
+ value: directImageURL
3059
+ }
3060
+ )
3061
+ ] }),
3062
+ /* @__PURE__ */ jsxs11("label", { className: "orion-builder-settings-label", children: [
3063
+ uploadLabel,
3064
+ /* @__PURE__ */ jsx12(
3065
+ "input",
3066
+ {
3067
+ accept: "image/*",
3068
+ className: "orion-builder-settings-input",
3069
+ disabled: uploadDisabled,
3070
+ onChange: (event) => {
3071
+ const file = event.currentTarget.files?.[0];
3072
+ if (file) {
3073
+ onUploadItemMedia?.(itemIndex, fieldName, file);
3074
+ }
3075
+ event.currentTarget.value = "";
3076
+ },
3077
+ type: "file"
3078
+ }
3079
+ )
3080
+ ] }),
3081
+ uploading ? /* @__PURE__ */ jsx12("div", { className: "orion-builder-settings-note", children: "Uploading image..." }) : null,
3082
+ /* @__PURE__ */ jsx12(
3083
+ ImageControls,
3084
+ {
3085
+ cornerStyle: mediaSettings.cornerStyle,
3086
+ fit: mediaSettings.fit,
3087
+ height: mediaSettings.height,
3088
+ maxHeight,
3089
+ minHeight,
3090
+ onChange: (field, value) => onUpdateItemMediaPresentation?.(itemIndex, field, value),
3091
+ positionX: mediaSettings.positionX,
3092
+ positionY: mediaSettings.positionY
3093
+ }
3094
+ )
3095
+ ] });
3096
+ }
2894
3097
  function ArrayItemsEditor({
2895
3098
  blockType,
2896
3099
  expandedItemIndex,
2897
3100
  items,
3101
+ mediaLibrary = [],
3102
+ mediaLibraryError = "",
3103
+ mediaLibraryLoading = false,
2898
3104
  mode,
2899
3105
  onAddItem,
3106
+ onRemoveItemMedia,
2900
3107
  onRemoveItem,
3108
+ onSelectItemMedia,
2901
3109
  onToggleItem,
2902
3110
  onUpdateItemField,
3111
+ onUpdateItemMediaPresentation,
2903
3112
  onUpdateItemSetting,
3113
+ onUploadItemMedia,
2904
3114
  searchQuery,
2905
- showInlineCopyFields
3115
+ showInlineCopyFields,
3116
+ uploadDisabled = false,
3117
+ isItemMediaUploading
2906
3118
  }) {
2907
3119
  const config = blockConfig[blockType];
2908
3120
  const normalizedQuery = searchQuery.trim().toLowerCase();
@@ -3052,11 +3264,30 @@ function ArrayItemsEditor({
3052
3264
  }
3053
3265
  )
3054
3266
  ] }) : null,
3055
- /* @__PURE__ */ jsxs11("div", { className: "orion-builder-settings-note", children: [
3056
- "Select this item and use the ",
3057
- /* @__PURE__ */ jsx12("strong", { children: "Media" }),
3058
- " group above for image source and presentation."
3059
- ] })
3267
+ /* @__PURE__ */ jsx12(
3268
+ ItemMediaControl,
3269
+ {
3270
+ fieldName: "media",
3271
+ imageURLFieldName: "imageURL",
3272
+ item,
3273
+ itemIndex,
3274
+ label: "Feature Image",
3275
+ maxHeight: 600,
3276
+ mediaLibrary,
3277
+ mediaLibraryError,
3278
+ mediaLibraryLoading,
3279
+ minHeight: 40,
3280
+ onRemoveItemMedia,
3281
+ onSelectItemMedia,
3282
+ onUpdateItemField,
3283
+ onUpdateItemMediaPresentation,
3284
+ onUploadItemMedia,
3285
+ searchQuery: normalizedQuery,
3286
+ uploadDisabled,
3287
+ uploadLabel: "Upload Feature Image",
3288
+ uploading: Boolean(isItemMediaUploading?.(itemIndex, "media"))
3289
+ }
3290
+ )
3060
3291
  ] }) : null,
3061
3292
  blockType === "logoWall" ? /* @__PURE__ */ jsxs11(Fragment4, { children: [
3062
3293
  showInlineCopyFields ? /* @__PURE__ */ jsxs11("label", { className: "orion-builder-settings-label", children: [
@@ -3083,11 +3314,30 @@ function ArrayItemsEditor({
3083
3314
  }
3084
3315
  )
3085
3316
  ] }) : null,
3086
- /* @__PURE__ */ jsxs11("div", { className: "orion-builder-settings-note", children: [
3087
- "Select this item and use the ",
3088
- /* @__PURE__ */ jsx12("strong", { children: "Media" }),
3089
- " group above for image source and presentation."
3090
- ] })
3317
+ /* @__PURE__ */ jsx12(
3318
+ ItemMediaControl,
3319
+ {
3320
+ fieldName: "media",
3321
+ imageURLFieldName: "imageURL",
3322
+ item,
3323
+ itemIndex,
3324
+ label: "Logo Image",
3325
+ maxHeight: 200,
3326
+ mediaLibrary,
3327
+ mediaLibraryError,
3328
+ mediaLibraryLoading,
3329
+ minHeight: 24,
3330
+ onRemoveItemMedia,
3331
+ onSelectItemMedia,
3332
+ onUpdateItemField,
3333
+ onUpdateItemMediaPresentation,
3334
+ onUploadItemMedia,
3335
+ searchQuery: normalizedQuery,
3336
+ uploadDisabled,
3337
+ uploadLabel: "Upload Logo Image",
3338
+ uploading: Boolean(isItemMediaUploading?.(itemIndex, "media"))
3339
+ }
3340
+ )
3091
3341
  ] }) : null,
3092
3342
  blockType === "beforeAfter" ? /* @__PURE__ */ jsxs11(Fragment4, { children: [
3093
3343
  showInlineCopyFields ? /* @__PURE__ */ jsxs11(Fragment4, { children: [
@@ -3115,11 +3365,54 @@ function ArrayItemsEditor({
3115
3365
  )
3116
3366
  ] })
3117
3367
  ] }) : null,
3118
- /* @__PURE__ */ jsxs11("div", { className: "orion-builder-settings-note", children: [
3119
- "Select this item and use the ",
3120
- /* @__PURE__ */ jsx12("strong", { children: "Media" }),
3121
- " group above for before/after image source and presentation."
3122
- ] })
3368
+ /* @__PURE__ */ jsx12(
3369
+ ItemMediaControl,
3370
+ {
3371
+ fieldName: "beforeMedia",
3372
+ imageURLFieldName: "beforeImageURL",
3373
+ item,
3374
+ itemIndex,
3375
+ label: "Before Image",
3376
+ maxHeight: 600,
3377
+ mediaLibrary,
3378
+ mediaLibraryError,
3379
+ mediaLibraryLoading,
3380
+ minHeight: 60,
3381
+ onRemoveItemMedia,
3382
+ onSelectItemMedia,
3383
+ onUpdateItemField,
3384
+ onUpdateItemMediaPresentation,
3385
+ onUploadItemMedia,
3386
+ searchQuery: normalizedQuery,
3387
+ uploadDisabled,
3388
+ uploadLabel: "Upload Before Image",
3389
+ uploading: Boolean(isItemMediaUploading?.(itemIndex, "beforeMedia"))
3390
+ }
3391
+ ),
3392
+ /* @__PURE__ */ jsx12(
3393
+ ItemMediaControl,
3394
+ {
3395
+ fieldName: "afterMedia",
3396
+ imageURLFieldName: "afterImageURL",
3397
+ item,
3398
+ itemIndex,
3399
+ label: "After Image",
3400
+ maxHeight: 600,
3401
+ mediaLibrary,
3402
+ mediaLibraryError,
3403
+ mediaLibraryLoading,
3404
+ minHeight: 60,
3405
+ onRemoveItemMedia,
3406
+ onSelectItemMedia,
3407
+ onUpdateItemField,
3408
+ onUpdateItemMediaPresentation,
3409
+ onUploadItemMedia,
3410
+ searchQuery: normalizedQuery,
3411
+ uploadDisabled,
3412
+ uploadLabel: "Upload After Image",
3413
+ uploading: Boolean(isItemMediaUploading?.(itemIndex, "afterMedia"))
3414
+ }
3415
+ )
3123
3416
  ] }) : null,
3124
3417
  blockType === "stats" ? /* @__PURE__ */ jsx12(Fragment4, { children: showInlineCopyFields ? /* @__PURE__ */ jsxs11(Fragment4, { children: [
3125
3418
  /* @__PURE__ */ jsxs11("label", { className: "orion-builder-settings-label", children: [
@@ -3325,8 +3618,8 @@ var resolveBuilderMediumHeroHeight = (topViewportHeight) => {
3325
3618
  }
3326
3619
  return "50svh";
3327
3620
  };
3328
- var normalizeImageFit = (value) => normalizeHeroImageFit(value);
3329
- var normalizeImageCornerStyle = (value, legacyFitValue) => normalizeHeroImageCornerStyle(value, legacyFitValue);
3621
+ var normalizeImageFit2 = (value) => normalizeHeroImageFit(value);
3622
+ var normalizeImageCornerStyle2 = (value, legacyFitValue) => normalizeHeroImageCornerStyle(value, legacyFitValue);
3330
3623
  var positionPercent = (value, fit) => {
3331
3624
  const resolved = fit === "cover" && (value === "left" || value === "right") ? "center" : value;
3332
3625
  switch (resolved) {
@@ -3758,6 +4051,12 @@ function getThemeColorOverride(tokens, colorKey) {
3758
4051
  const normalized = value.trim();
3759
4052
  return normalized.length > 0 ? normalized : null;
3760
4053
  }
4054
+ function normalizeCustomClassName(value) {
4055
+ if (typeof value !== "string") {
4056
+ return "";
4057
+ }
4058
+ return value.split(/\s+/).map((className) => className.trim()).filter(Boolean).join(" ");
4059
+ }
3761
4060
  var sectionStyleFromBlock = (block, pageDefaults) => {
3762
4061
  const settings = isRecord6(block.settings) ? block.settings : {};
3763
4062
  const layoutSettings = isRecord6(settings.layout) ? settings.layout : {};
@@ -3851,7 +4150,7 @@ var sectionStyleFromBlock = (block, pageDefaults) => {
3851
4150
  sectionStyle: sectionMode === "color" ? { background: sectionColor } : sectionMode === "gradient" ? { background: sectionGradient } : block.blockType === "hero" ? { background: "transparent" } : {}
3852
4151
  };
3853
4152
  };
3854
- function getRelationID2(value) {
4153
+ function getRelationID3(value) {
3855
4154
  if (typeof value === "number" || typeof value === "string") {
3856
4155
  return value;
3857
4156
  }
@@ -3884,7 +4183,7 @@ function extractUploadedMedia(value) {
3884
4183
  if (!candidate || typeof candidate !== "object") {
3885
4184
  return null;
3886
4185
  }
3887
- const id = getRelationID2(candidate);
4186
+ const id = getRelationID3(candidate);
3888
4187
  if (id === null) {
3889
4188
  return null;
3890
4189
  }
@@ -3895,11 +4194,11 @@ function extractUploadedMedia(value) {
3895
4194
  url: typeof candidate.url === "string" ? candidate.url : ""
3896
4195
  };
3897
4196
  }
3898
- function toMediaLibraryItem2(value) {
4197
+ function toMediaLibraryItem3(value) {
3899
4198
  if (!value || typeof value !== "object") {
3900
4199
  return null;
3901
4200
  }
3902
- const id = getRelationID2(value);
4201
+ const id = getRelationID3(value);
3903
4202
  if (id === null) {
3904
4203
  return null;
3905
4204
  }
@@ -4077,7 +4376,7 @@ function BuilderPageEditor({
4077
4376
  }
4078
4377
  const json = await response.json();
4079
4378
  const docs = Array.isArray(json.docs) ? json.docs : [];
4080
- const items = docs.map((doc2) => toMediaLibraryItem2(doc2)).filter((item) => item !== null);
4379
+ const items = docs.map((doc2) => toMediaLibraryItem3(doc2)).filter((item) => item !== null);
4081
4380
  setMediaLibrary(items);
4082
4381
  } catch (error) {
4083
4382
  setMediaLibraryError(error instanceof Error ? error.message : "Could not load media library.");
@@ -4431,7 +4730,7 @@ function BuilderPageEditor({
4431
4730
  const nextLayout = cloneBlockLayout(layout);
4432
4731
  const block = nextLayout[selectedIndex];
4433
4732
  if (target.kind === "hero") {
4434
- const uploadedItem = toMediaLibraryItem2(uploaded);
4733
+ const uploadedItem = toMediaLibraryItem3(uploaded);
4435
4734
  nextLayout[selectedIndex] = {
4436
4735
  ...block,
4437
4736
  backgroundImageURL: uploadedItem?.url || normalizeText2(uploaded.url),
@@ -4495,13 +4794,13 @@ function BuilderPageEditor({
4495
4794
  const nextBlock = { ...migrateBlockToSettingsV2(block) };
4496
4795
  const blockType = normalizeText2(nextBlock.blockType);
4497
4796
  if (blockType === "hero") {
4498
- const mediaID = getRelationID2(nextBlock.media);
4797
+ const mediaID = getRelationID3(nextBlock.media);
4499
4798
  if (mediaID !== null) {
4500
4799
  nextBlock.media = mediaID;
4501
4800
  }
4502
4801
  }
4503
4802
  if (blockType === "media") {
4504
- const imageID = getRelationID2(nextBlock.image);
4803
+ const imageID = getRelationID3(nextBlock.image);
4505
4804
  if (imageID !== null) {
4506
4805
  nextBlock.image = imageID;
4507
4806
  }
@@ -4513,15 +4812,15 @@ function BuilderPageEditor({
4513
4812
  return rawItem;
4514
4813
  }
4515
4814
  const nextItem = { ...rawItem };
4516
- const mediaID = getRelationID2(nextItem.media);
4815
+ const mediaID = getRelationID3(nextItem.media);
4517
4816
  if (mediaID !== null) {
4518
4817
  nextItem.media = mediaID;
4519
4818
  }
4520
- const beforeMediaID = getRelationID2(nextItem.beforeMedia);
4819
+ const beforeMediaID = getRelationID3(nextItem.beforeMedia);
4521
4820
  if (beforeMediaID !== null) {
4522
4821
  nextItem.beforeMedia = beforeMediaID;
4523
4822
  }
4524
- const afterMediaID = getRelationID2(nextItem.afterMedia);
4823
+ const afterMediaID = getRelationID3(nextItem.afterMedia);
4525
4824
  if (afterMediaID !== null) {
4526
4825
  nextItem.afterMedia = afterMediaID;
4527
4826
  }
@@ -4577,6 +4876,7 @@ function BuilderPageEditor({
4577
4876
  const inheritProjectStyles = options?.inheritProjectStyles === true;
4578
4877
  const shell = sectionStyleFromBlock(block, pageDefaults);
4579
4878
  const blockSettings = isRecord6(block.settings) ? block.settings : {};
4879
+ const blockAdvanced = isRecord6(blockSettings.advanced) ? blockSettings.advanced : {};
4580
4880
  const blockTypography = isRecord6(blockSettings.typography) ? blockSettings.typography : {};
4581
4881
  const blockTheme = isRecord6(blockSettings.theme) ? blockSettings.theme : {};
4582
4882
  const heroBackgroundColor = normalizeText2(block.backgroundColor).trim();
@@ -4584,8 +4884,9 @@ function BuilderPageEditor({
4584
4884
  const heroMedia = block.blockType === "hero" ? resolveMedia(block.media) : null;
4585
4885
  const heroHasImage = block.blockType === "hero" && Boolean(heroBackgroundImageURL || heroMedia?.url);
4586
4886
  const heroTextColor = block.blockType === "hero" ? heroHasImage ? "#ffffff" : heroBackgroundColor ? getReadableTextColor(heroBackgroundColor, resolvedThemeTokens.colors.headingText, "#ffffff") : resolvedThemeTokens.colors.headingText : null;
4887
+ const bodyAlign = blockTypography.bodyAlign === "center" || blockTypography.bodyAlign === "justify" || blockTypography.bodyAlign === "right" ? blockTypography.bodyAlign : "left";
4587
4888
  const typographyStyle = resolveTypographyStyleFromSettings({
4588
- bodyAlign: blockTypography.bodyAlign === "center" || blockTypography.bodyAlign === "justify" || blockTypography.bodyAlign === "right" ? blockTypography.bodyAlign : "left",
4889
+ bodyAlign,
4589
4890
  letterSpacingPreset: blockTypography.letterSpacingPreset === "tight" || blockTypography.letterSpacingPreset === "relaxed" ? blockTypography.letterSpacingPreset : "normal",
4590
4891
  lineHeightPreset: blockTypography.lineHeightPreset === "tight" || blockTypography.lineHeightPreset === "relaxed" ? blockTypography.lineHeightPreset : "normal",
4591
4892
  maxTextWidth: blockTypography.maxTextWidth === "sm" || blockTypography.maxTextWidth === "md" || blockTypography.maxTextWidth === "lg" || blockTypography.maxTextWidth === "full" ? blockTypography.maxTextWidth : "auto"
@@ -4593,14 +4894,24 @@ function BuilderPageEditor({
4593
4894
  const headingAlign = blockTypography.headingAlign === "center" || blockTypography.headingAlign === "justify" || blockTypography.headingAlign === "right" ? blockTypography.headingAlign : "left";
4594
4895
  const headingColor = getThemeColorOverride(blockTheme, "headingText") || getThemeColorOverride(pageDefaults.themePage, "headingText") || getThemeColorOverride(siteThemeTokens, "headingText") || heroTextColor || resolvedThemeTokens.colors.headingText;
4595
4896
  const bodyColor = getThemeColorOverride(blockTheme, "bodyText") || getThemeColorOverride(pageDefaults.themePage, "bodyText") || getThemeColorOverride(siteThemeTokens, "bodyText") || heroTextColor || resolvedThemeTokens.colors.bodyText;
4596
- return /* @__PURE__ */ jsx13("section", { className: `${className} ${shell.sectionClass}`, style: shell.sectionStyle, children: /* @__PURE__ */ jsx13("div", { style: shell.sectionInnerStyle, children: /* @__PURE__ */ jsx13(
4897
+ const customClassName = normalizeCustomClassName(blockAdvanced.customClassName ?? block.customClassName);
4898
+ const hideOnMobile = Boolean(blockAdvanced.hideOnMobile ?? block.hideOnMobile);
4899
+ const sectionClassName = [
4900
+ className,
4901
+ shell.sectionClass,
4902
+ customClassName,
4903
+ hideOnMobile ? "orion-builder-hide-mobile" : ""
4904
+ ].filter(Boolean).join(" ");
4905
+ return /* @__PURE__ */ jsx13("section", { className: sectionClassName, style: shell.sectionStyle, children: /* @__PURE__ */ jsx13("div", { style: shell.sectionInnerStyle, children: /* @__PURE__ */ jsx13(
4597
4906
  "div",
4598
4907
  {
4599
4908
  className: shell.contentClass,
4600
4909
  style: {
4601
4910
  ...shell.contentStyle,
4911
+ "--orion-builder-heading-align": headingAlign,
4912
+ "--orion-builder-body-align": bodyAlign,
4913
+ "--orion-builder-actions-align": bodyAlign === "center" ? "center" : bodyAlign === "right" ? "flex-end" : "flex-start",
4602
4914
  ...inheritProjectStyles ? {} : {
4603
- "--orion-builder-heading-align": headingAlign,
4604
4915
  "--orion-builder-heading-color": headingColor,
4605
4916
  color: bodyColor,
4606
4917
  ...typographyStyle
@@ -5087,8 +5398,8 @@ function BuilderPageEditor({
5087
5398
  }
5088
5399
  ] : [];
5089
5400
  const selectedMediaImageControls = selectedItemRecord && typeof selectedItemIndex === "number" && (selectedType === "featureGrid" || selectedType === "logoWall" || selectedType === "beforeAfter") ? {
5090
- cornerStyle: normalizeImageCornerStyle(selectedItemRecord.imageCornerStyle),
5091
- fit: normalizeImageFit(selectedItemRecord.imageFit),
5401
+ cornerStyle: normalizeImageCornerStyle2(selectedItemRecord.imageCornerStyle),
5402
+ fit: normalizeImageFit2(selectedItemRecord.imageFit),
5092
5403
  height: (() => {
5093
5404
  if (typeof selectedItemRecord.imageHeight === "number" && Number.isFinite(selectedItemRecord.imageHeight)) {
5094
5405
  return selectedItemRecord.imageHeight;
@@ -5563,8 +5874,8 @@ function BuilderPageEditor({
5563
5874
  const itemPositionX = parseOptionalPercentNumber2(itemRecord?.imagePositionX);
5564
5875
  const itemPositionY = parseOptionalPercentNumber2(itemRecord?.imagePositionY);
5565
5876
  const itemImageStyle = getImagePresentationStyle({
5566
- cornerStyle: normalizeImageCornerStyle(itemRecord?.imageCornerStyle),
5567
- fit: normalizeImageFit(itemRecord?.imageFit),
5877
+ cornerStyle: normalizeImageCornerStyle2(itemRecord?.imageCornerStyle),
5878
+ fit: normalizeImageFit2(itemRecord?.imageFit),
5568
5879
  positionX: itemPositionX,
5569
5880
  positionY: itemPositionY
5570
5881
  });
@@ -5681,8 +5992,8 @@ function BuilderPageEditor({
5681
5992
  const itemPositionX = parseOptionalPercentNumber2(itemRecord?.imagePositionX);
5682
5993
  const itemPositionY = parseOptionalPercentNumber2(itemRecord?.imagePositionY);
5683
5994
  const itemImageStyle = getImagePresentationStyle({
5684
- cornerStyle: normalizeImageCornerStyle(itemRecord?.imageCornerStyle),
5685
- fit: normalizeImageFit(itemRecord?.imageFit),
5995
+ cornerStyle: normalizeImageCornerStyle2(itemRecord?.imageCornerStyle),
5996
+ fit: normalizeImageFit2(itemRecord?.imageFit),
5686
5997
  positionX: itemPositionX,
5687
5998
  positionY: itemPositionY
5688
5999
  });
@@ -5888,8 +6199,8 @@ function BuilderPageEditor({
5888
6199
  const itemPositionX = parseOptionalPercentNumber2(itemRecord?.imagePositionX);
5889
6200
  const itemPositionY = parseOptionalPercentNumber2(itemRecord?.imagePositionY);
5890
6201
  const imageStyle = getImagePresentationStyle({
5891
- cornerStyle: normalizeImageCornerStyle(itemRecord?.imageCornerStyle),
5892
- fit: normalizeImageFit(itemRecord?.imageFit),
6202
+ cornerStyle: normalizeImageCornerStyle2(itemRecord?.imageCornerStyle),
6203
+ fit: normalizeImageFit2(itemRecord?.imageFit),
5893
6204
  positionX: itemPositionX,
5894
6205
  positionY: itemPositionY,
5895
6206
  roundedRadius: 10
@@ -6002,8 +6313,8 @@ function BuilderPageEditor({
6002
6313
  const itemPositionX = parseOptionalPercentNumber2(itemRecord?.imagePositionX);
6003
6314
  const itemPositionY = parseOptionalPercentNumber2(itemRecord?.imagePositionY);
6004
6315
  const imageStyle = getImagePresentationStyle({
6005
- cornerStyle: normalizeImageCornerStyle(itemRecord?.imageCornerStyle),
6006
- fit: normalizeImageFit(itemRecord?.imageFit),
6316
+ cornerStyle: normalizeImageCornerStyle2(itemRecord?.imageCornerStyle),
6317
+ fit: normalizeImageFit2(itemRecord?.imageFit),
6007
6318
  positionX: itemPositionX,
6008
6319
  positionY: itemPositionY
6009
6320
  });
@@ -6309,8 +6620,8 @@ function BuilderPageEditor({
6309
6620
  getImagePresentationStyle,
6310
6621
  index,
6311
6622
  isBlockUploadTarget,
6312
- normalizeImageCornerStyle,
6313
- normalizeImageFit,
6623
+ normalizeImageCornerStyle: normalizeImageCornerStyle2,
6624
+ normalizeImageFit: normalizeImageFit2,
6314
6625
  normalizeText: normalizeText2,
6315
6626
  onDropAt,
6316
6627
  renderWithSectionShell,
@@ -6539,23 +6850,32 @@ function BuilderPageEditor({
6539
6850
  blockType: selectedType,
6540
6851
  expandedItemIndex,
6541
6852
  items: selectedItems,
6853
+ isItemMediaUploading: isSelectedItemMediaUploading,
6854
+ mediaLibrary,
6855
+ mediaLibraryError,
6856
+ mediaLibraryLoading,
6542
6857
  mode: settingsPanelMode,
6543
6858
  onAddItem: appendDefaultItemToSelected,
6544
6859
  onRemoveItem: (itemIndex) => removeItemFromSelected("items", itemIndex),
6860
+ onRemoveItemMedia: (itemIndex, fieldName) => setSelectedItemMediaFieldFromLibrary(itemIndex, fieldName, ""),
6861
+ onSelectItemMedia: (itemIndex, fieldName, mediaID) => setSelectedItemMediaFieldFromLibrary(itemIndex, fieldName, mediaID),
6545
6862
  onToggleItem: toggleSelectedItem,
6546
6863
  onUpdateItemField: (itemIndex, fieldName, value) => updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, fieldName, value),
6864
+ onUpdateItemMediaPresentation: (itemIndex, fieldName, value) => updateArrayItemSettingField(selectedIndex ?? 0, "items", itemIndex, `media.${fieldName}`, value),
6547
6865
  onUpdateItemSetting: (itemIndex, path, value) => updateArrayItemSettingField(selectedIndex ?? 0, "items", itemIndex, path, value),
6866
+ onUploadItemMedia: uploadItemMediaFromV2,
6548
6867
  searchQuery: settingsSearchQuery,
6549
- showInlineCopyFields: editCopyInPanelEnabled
6868
+ showInlineCopyFields: editCopyInPanelEnabled,
6869
+ uploadDisabled: uploadingTarget !== null
6550
6870
  }
6551
6871
  ) : null,
6552
6872
  /* @__PURE__ */ jsxs12("label", { style: sidebarLabelStyle, children: [
6553
- "Upload Alt Text",
6873
+ "New Upload Alt Text",
6554
6874
  /* @__PURE__ */ jsx13(
6555
6875
  "input",
6556
6876
  {
6557
6877
  onChange: (event) => setUploadAltText(event.target.value),
6558
- placeholder: "Describe the image",
6878
+ placeholder: "Used only when uploading a new image",
6559
6879
  style: sidebarInputStyle,
6560
6880
  type: "text",
6561
6881
  value: uploadAltText