@orion-studios/payload-studio 0.5.0-beta.35 → 0.5.0-beta.37

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.
@@ -737,6 +737,58 @@ var HeroBlock = {
737
737
  description: "Optional background color override (example: #124a37)."
738
738
  }
739
739
  },
740
+ {
741
+ name: "backgroundOverlayMode",
742
+ type: "select",
743
+ defaultValue: "none",
744
+ options: [
745
+ { label: "None", value: "none" },
746
+ { label: "Solid", value: "solid" },
747
+ { label: "Gradient", value: "gradient" }
748
+ ],
749
+ admin: {
750
+ description: "Optional overlay on top of the hero image (applies when an image is present)."
751
+ }
752
+ },
753
+ {
754
+ name: "backgroundOverlayOpacity",
755
+ type: "number",
756
+ defaultValue: 45,
757
+ min: 0,
758
+ max: 100,
759
+ admin: {
760
+ description: "Overlay opacity (0-100).",
761
+ step: 1
762
+ }
763
+ },
764
+ {
765
+ name: "backgroundOverlayColor",
766
+ type: "text",
767
+ admin: {
768
+ description: "Overlay solid color (example: #000000). Used when Overlay Mode is Solid."
769
+ }
770
+ },
771
+ {
772
+ name: "backgroundOverlayGradientFrom",
773
+ type: "text",
774
+ admin: {
775
+ description: "Gradient overlay start color (example: #0d4a37). Used when Overlay Mode is Gradient."
776
+ }
777
+ },
778
+ {
779
+ name: "backgroundOverlayGradientTo",
780
+ type: "text",
781
+ admin: {
782
+ description: "Gradient overlay end color (example: #1f684f). Used when Overlay Mode is Gradient."
783
+ }
784
+ },
785
+ {
786
+ name: "backgroundOverlayGradientAngle",
787
+ type: "text",
788
+ admin: {
789
+ description: "Gradient overlay angle in degrees (0-360). Used when Overlay Mode is Gradient."
790
+ }
791
+ },
740
792
  {
741
793
  name: "variant",
742
794
  type: "select",
@@ -17,7 +17,7 @@ import {
17
17
  defaultPageLayoutBlocks,
18
18
  sectionPresets,
19
19
  templateStarterPresets
20
- } from "../chunk-DUPYIJJH.mjs";
20
+ } from "../chunk-OVB5EC6L.mjs";
21
21
  import "../chunk-SIL2J5MF.mjs";
22
22
  import "../chunk-6BWS3CLP.mjs";
23
23
  export {
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-N67KVM2S.mjs";
4
4
  import {
5
5
  studioDocumentToLayout
6
- } from "./chunk-QW24Y4UH.mjs";
6
+ } from "./chunk-ZKG4V5MI.mjs";
7
7
  import {
8
8
  __export
9
9
  } from "./chunk-6BWS3CLP.mjs";
@@ -573,6 +573,58 @@ var HeroBlock = {
573
573
  description: "Optional background color override (example: #124a37)."
574
574
  }
575
575
  },
576
+ {
577
+ name: "backgroundOverlayMode",
578
+ type: "select",
579
+ defaultValue: "none",
580
+ options: [
581
+ { label: "None", value: "none" },
582
+ { label: "Solid", value: "solid" },
583
+ { label: "Gradient", value: "gradient" }
584
+ ],
585
+ admin: {
586
+ description: "Optional overlay on top of the hero image (applies when an image is present)."
587
+ }
588
+ },
589
+ {
590
+ name: "backgroundOverlayOpacity",
591
+ type: "number",
592
+ defaultValue: 45,
593
+ min: 0,
594
+ max: 100,
595
+ admin: {
596
+ description: "Overlay opacity (0-100).",
597
+ step: 1
598
+ }
599
+ },
600
+ {
601
+ name: "backgroundOverlayColor",
602
+ type: "text",
603
+ admin: {
604
+ description: "Overlay solid color (example: #000000). Used when Overlay Mode is Solid."
605
+ }
606
+ },
607
+ {
608
+ name: "backgroundOverlayGradientFrom",
609
+ type: "text",
610
+ admin: {
611
+ description: "Gradient overlay start color (example: #0d4a37). Used when Overlay Mode is Gradient."
612
+ }
613
+ },
614
+ {
615
+ name: "backgroundOverlayGradientTo",
616
+ type: "text",
617
+ admin: {
618
+ description: "Gradient overlay end color (example: #1f684f). Used when Overlay Mode is Gradient."
619
+ }
620
+ },
621
+ {
622
+ name: "backgroundOverlayGradientAngle",
623
+ type: "text",
624
+ admin: {
625
+ description: "Gradient overlay angle in degrees (0-360). Used when Overlay Mode is Gradient."
626
+ }
627
+ },
576
628
  {
577
629
  name: "variant",
578
630
  type: "select",
@@ -74,6 +74,12 @@ var defaultNodeData = {
74
74
  hero: {
75
75
  ...withSectionStyleDefaults({}),
76
76
  backgroundColor: "",
77
+ backgroundOverlayMode: "none",
78
+ backgroundOverlayOpacity: 45,
79
+ backgroundOverlayColor: "#000000",
80
+ backgroundOverlayGradientFrom: "#0d4a37",
81
+ backgroundOverlayGradientTo: "#1f684f",
82
+ backgroundOverlayGradientAngle: "135",
77
83
  backgroundImageCornerStyle: "rounded",
78
84
  backgroundImageFit: "cover",
79
85
  backgroundImagePosition: "center",
package/dist/index.js CHANGED
@@ -1278,6 +1278,58 @@ var HeroBlock = {
1278
1278
  description: "Optional background color override (example: #124a37)."
1279
1279
  }
1280
1280
  },
1281
+ {
1282
+ name: "backgroundOverlayMode",
1283
+ type: "select",
1284
+ defaultValue: "none",
1285
+ options: [
1286
+ { label: "None", value: "none" },
1287
+ { label: "Solid", value: "solid" },
1288
+ { label: "Gradient", value: "gradient" }
1289
+ ],
1290
+ admin: {
1291
+ description: "Optional overlay on top of the hero image (applies when an image is present)."
1292
+ }
1293
+ },
1294
+ {
1295
+ name: "backgroundOverlayOpacity",
1296
+ type: "number",
1297
+ defaultValue: 45,
1298
+ min: 0,
1299
+ max: 100,
1300
+ admin: {
1301
+ description: "Overlay opacity (0-100).",
1302
+ step: 1
1303
+ }
1304
+ },
1305
+ {
1306
+ name: "backgroundOverlayColor",
1307
+ type: "text",
1308
+ admin: {
1309
+ description: "Overlay solid color (example: #000000). Used when Overlay Mode is Solid."
1310
+ }
1311
+ },
1312
+ {
1313
+ name: "backgroundOverlayGradientFrom",
1314
+ type: "text",
1315
+ admin: {
1316
+ description: "Gradient overlay start color (example: #0d4a37). Used when Overlay Mode is Gradient."
1317
+ }
1318
+ },
1319
+ {
1320
+ name: "backgroundOverlayGradientTo",
1321
+ type: "text",
1322
+ admin: {
1323
+ description: "Gradient overlay end color (example: #1f684f). Used when Overlay Mode is Gradient."
1324
+ }
1325
+ },
1326
+ {
1327
+ name: "backgroundOverlayGradientAngle",
1328
+ type: "text",
1329
+ admin: {
1330
+ description: "Gradient overlay angle in degrees (0-360). Used when Overlay Mode is Gradient."
1331
+ }
1332
+ },
1281
1333
  {
1282
1334
  name: "variant",
1283
1335
  type: "select",
@@ -2203,6 +2255,12 @@ var defaultNodeData = {
2203
2255
  hero: {
2204
2256
  ...withSectionStyleDefaults({}),
2205
2257
  backgroundColor: "",
2258
+ backgroundOverlayMode: "none",
2259
+ backgroundOverlayOpacity: 45,
2260
+ backgroundOverlayColor: "#000000",
2261
+ backgroundOverlayGradientFrom: "#0d4a37",
2262
+ backgroundOverlayGradientTo: "#1f684f",
2263
+ backgroundOverlayGradientAngle: "135",
2206
2264
  backgroundImageCornerStyle: "rounded",
2207
2265
  backgroundImageFit: "cover",
2208
2266
  backgroundImagePosition: "center",
package/dist/index.mjs CHANGED
@@ -1,21 +1,21 @@
1
1
  import {
2
2
  admin_exports
3
3
  } from "./chunk-7IGLXLUB.mjs";
4
+ import {
5
+ blocks_exports
6
+ } from "./chunk-OVB5EC6L.mjs";
4
7
  import {
5
8
  admin_app_exports
6
9
  } from "./chunk-XVH5SCBD.mjs";
7
- import {
8
- blocks_exports
9
- } from "./chunk-DUPYIJJH.mjs";
10
10
  import {
11
11
  nextjs_exports
12
- } from "./chunk-GPQPDEB5.mjs";
12
+ } from "./chunk-FKJNK7TP.mjs";
13
13
  import {
14
14
  studio_exports
15
15
  } from "./chunk-N67KVM2S.mjs";
16
16
  import {
17
17
  studio_pages_exports
18
- } from "./chunk-QW24Y4UH.mjs";
18
+ } from "./chunk-ZKG4V5MI.mjs";
19
19
  import "./chunk-SIL2J5MF.mjs";
20
20
  import "./chunk-6BWS3CLP.mjs";
21
21
  export {
@@ -163,6 +163,12 @@ var defaultNodeData = {
163
163
  hero: {
164
164
  ...withSectionStyleDefaults({}),
165
165
  backgroundColor: "",
166
+ backgroundOverlayMode: "none",
167
+ backgroundOverlayOpacity: 45,
168
+ backgroundOverlayColor: "#000000",
169
+ backgroundOverlayGradientFrom: "#0d4a37",
170
+ backgroundOverlayGradientTo: "#1f684f",
171
+ backgroundOverlayGradientAngle: "135",
166
172
  backgroundImageCornerStyle: "rounded",
167
173
  backgroundImageFit: "cover",
168
174
  backgroundImagePosition: "center",
@@ -4,9 +4,9 @@ import {
4
4
  createPayloadClient,
5
5
  createSiteQueries,
6
6
  resolveMedia
7
- } from "../chunk-GPQPDEB5.mjs";
7
+ } from "../chunk-FKJNK7TP.mjs";
8
8
  import "../chunk-N67KVM2S.mjs";
9
- import "../chunk-QW24Y4UH.mjs";
9
+ import "../chunk-ZKG4V5MI.mjs";
10
10
  import "../chunk-SIL2J5MF.mjs";
11
11
  import "../chunk-6BWS3CLP.mjs";
12
12
  export {
@@ -112,6 +112,12 @@ var defaultNodeData = {
112
112
  hero: {
113
113
  ...withSectionStyleDefaults({}),
114
114
  backgroundColor: "",
115
+ backgroundOverlayMode: "none",
116
+ backgroundOverlayOpacity: 45,
117
+ backgroundOverlayColor: "#000000",
118
+ backgroundOverlayGradientFrom: "#0d4a37",
119
+ backgroundOverlayGradientTo: "#1f684f",
120
+ backgroundOverlayGradientAngle: "135",
115
121
  backgroundImageCornerStyle: "rounded",
116
122
  backgroundImageFit: "cover",
117
123
  backgroundImagePosition: "center",
@@ -500,29 +506,31 @@ var heroHeightMap = {
500
506
  var normalizeImageFit = (value) => normalizeHeroImageFit(value);
501
507
  var normalizeImageCornerStyle = (value, legacyFitValue) => normalizeHeroImageCornerStyle(value, legacyFitValue);
502
508
  var normalizeImagePosition = (value) => normalizeHeroImagePosition(value);
503
- var imageObjectPosition = (value, fit = "cover") => {
509
+ var positionPercent = (value, fit) => {
504
510
  const resolved = fit === "cover" && (value === "left" || value === "right") ? "center" : value;
505
511
  switch (resolved) {
506
512
  case "top":
507
- return "center top";
513
+ return { x: 50, y: 0 };
508
514
  case "bottom":
509
- return "center bottom";
515
+ return { x: 50, y: 100 };
510
516
  case "left":
511
- return "left center";
517
+ return { x: 0, y: 50 };
512
518
  case "right":
513
- return "right center";
519
+ return { x: 100, y: 50 };
514
520
  default:
515
- return "center center";
521
+ return { x: 50, y: 50 };
516
522
  }
517
523
  };
518
524
  var getImagePresentationStyle = (options) => {
519
- const hasCustomPosition = typeof options.positionX === "number" || typeof options.positionY === "number";
520
- const x = typeof options.positionX === "number" && Number.isFinite(options.positionX) ? Math.max(0, Math.min(100, options.positionX)) : 50;
521
- const y = typeof options.positionY === "number" && Number.isFinite(options.positionY) ? Math.max(0, Math.min(100, options.positionY)) : 50;
525
+ const fit = options.fit || "cover";
526
+ const base = positionPercent(options.position || "center", fit);
527
+ const x = typeof options.positionX === "number" && Number.isFinite(options.positionX) ? Math.max(0, Math.min(100, options.positionX)) : base.x;
528
+ const y = typeof options.positionY === "number" && Number.isFinite(options.positionY) ? Math.max(0, Math.min(100, options.positionY)) : base.y;
522
529
  return {
523
530
  borderRadius: options.cornerStyle === "square" ? 0 : `${options.roundedRadius ?? 12}px`,
524
- objectFit: options.fit || "cover",
525
- objectPosition: hasCustomPosition ? `${x}% ${y}%` : imageObjectPosition(options.position || "center", options.fit || "cover")
531
+ objectFit: fit,
532
+ // Always use percent positioning so presets behave identically with/without custom axis overrides.
533
+ objectPosition: `${x}% ${y}%`
526
534
  };
527
535
  };
528
536
  function cloneBlockLayout(layout) {
@@ -815,6 +823,43 @@ function parsePixelNumber(value, fallback) {
815
823
  function parsePercentNumber(value, fallback) {
816
824
  return Math.max(0, Math.min(100, parsePixelNumber(value, fallback)));
817
825
  }
826
+ function parseOptionalPercentNumber(value) {
827
+ if (typeof value === "number" && Number.isFinite(value)) {
828
+ return Math.max(0, Math.min(100, value));
829
+ }
830
+ if (typeof value === "string") {
831
+ const parsed = Number(value);
832
+ if (Number.isFinite(parsed)) {
833
+ return Math.max(0, Math.min(100, parsed));
834
+ }
835
+ }
836
+ return void 0;
837
+ }
838
+ function hexToRgb(value) {
839
+ const normalized = value.trim();
840
+ if (!/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(normalized)) {
841
+ return null;
842
+ }
843
+ const hex = normalized.slice(1);
844
+ if (hex.length === 3) {
845
+ const r2 = parseInt(hex[0] + hex[0], 16);
846
+ const g2 = parseInt(hex[1] + hex[1], 16);
847
+ const b2 = parseInt(hex[2] + hex[2], 16);
848
+ return { r: r2, g: g2, b: b2 };
849
+ }
850
+ const r = parseInt(hex.slice(0, 2), 16);
851
+ const g = parseInt(hex.slice(2, 4), 16);
852
+ const b = parseInt(hex.slice(4, 6), 16);
853
+ return { r, g, b };
854
+ }
855
+ function rgbaFromHex(hex, alpha) {
856
+ const rgb = hexToRgb(hex);
857
+ const clamped = Number.isFinite(alpha) ? Math.max(0, Math.min(1, alpha)) : 1;
858
+ if (!rgb) {
859
+ return `rgba(0, 0, 0, ${clamped})`;
860
+ }
861
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${clamped})`;
862
+ }
818
863
  var sectionStyleFromBlock = (block, pageDefaults) => {
819
864
  const contentWidthRaw = normalizeText(block.contentWidth, defaultSectionStyle.contentWidth);
820
865
  const sectionPaddingRaw = normalizeText(block.sectionPaddingY, defaultSectionStyle.sectionPaddingY);
@@ -2125,12 +2170,20 @@ function BuilderPageEditor({ initialDoc, pageID }) {
2125
2170
  const backgroundImageURL = normalizeText(block.backgroundImageURL);
2126
2171
  const backgroundImage = media?.url || backgroundImageURL;
2127
2172
  const hasCustomHeroColor = backgroundColor.length > 0 && backgroundColor.toLowerCase() !== "#124a37";
2173
+ const overlayModeRaw = normalizeText(block?.backgroundOverlayMode, "none");
2174
+ const overlayMode = overlayModeRaw === "solid" || overlayModeRaw === "gradient" ? overlayModeRaw : "none";
2175
+ const overlayOpacity = parsePercentNumber(block?.backgroundOverlayOpacity, 45) / 100;
2176
+ const overlayColor = parseColor(block?.backgroundOverlayColor, "#000000");
2177
+ const overlayFrom = parseColor(block?.backgroundOverlayGradientFrom, "#0d4a37");
2178
+ const overlayTo = parseColor(block?.backgroundOverlayGradientTo, "#1f684f");
2179
+ const overlayAngle = parseAngle(block?.backgroundOverlayGradientAngle, "135");
2180
+ const overlayLayer = overlayMode === "solid" ? `linear-gradient(${rgbaFromHex(overlayColor, overlayOpacity)}, ${rgbaFromHex(overlayColor, overlayOpacity)})` : overlayMode === "gradient" ? `linear-gradient(${overlayAngle}deg, ${rgbaFromHex(overlayFrom, overlayOpacity)}, ${rgbaFromHex(overlayTo, overlayOpacity)})` : "";
2128
2181
  const mediaStyle = backgroundImage && variant === "default" ? {
2129
2182
  ...hasCustomHeroColor ? { backgroundColor } : {},
2130
- backgroundImage: `url('${backgroundImage}')`,
2131
- backgroundPosition: backgroundImagePosition,
2132
- backgroundRepeat: "no-repeat",
2133
- backgroundSize: backgroundImageFit,
2183
+ backgroundImage: overlayLayer ? `${overlayLayer}, url('${backgroundImage}')` : `url('${backgroundImage}')`,
2184
+ backgroundPosition: overlayLayer ? `center center, ${backgroundImagePosition}` : backgroundImagePosition,
2185
+ backgroundRepeat: overlayLayer ? "no-repeat, no-repeat" : "no-repeat",
2186
+ backgroundSize: overlayLayer ? `cover, ${backgroundImageFit}` : backgroundImageFit,
2134
2187
  minHeight: heroMinHeight
2135
2188
  } : hasCustomHeroColor && sectionBackgroundMode !== "none" ? {
2136
2189
  backgroundColor,
@@ -2243,15 +2296,14 @@ function BuilderPageEditor({ initialDoc, pageID }) {
2243
2296
  const itemRecord = item;
2244
2297
  const itemMedia = resolveMedia(itemRecord?.media);
2245
2298
  const itemImageHeight = parsePixelNumber(itemRecord?.imageHeight, 120);
2246
- const hasCustomFocus = typeof itemRecord?.imagePositionX === "number" || typeof itemRecord?.imagePositionX === "string" || typeof itemRecord?.imagePositionY === "number" || typeof itemRecord?.imagePositionY === "string";
2299
+ const itemPositionX = parseOptionalPercentNumber(itemRecord?.imagePositionX);
2300
+ const itemPositionY = parseOptionalPercentNumber(itemRecord?.imagePositionY);
2247
2301
  const itemImageStyle = getImagePresentationStyle({
2248
2302
  cornerStyle: normalizeImageCornerStyle(itemRecord?.imageCornerStyle),
2249
2303
  fit: normalizeImageFit(itemRecord?.imageFit),
2250
2304
  position: normalizeImagePosition(itemRecord?.imagePosition),
2251
- ...hasCustomFocus ? {
2252
- positionX: parsePercentNumber(itemRecord?.imagePositionX, 50),
2253
- positionY: parsePercentNumber(itemRecord?.imagePositionY, 50)
2254
- } : {}
2305
+ positionX: itemPositionX,
2306
+ positionY: itemPositionY
2255
2307
  });
2256
2308
  const isItemSelected = selectedIndex === index && selectedItemIndex === itemIndex;
2257
2309
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
@@ -2342,15 +2394,14 @@ function BuilderPageEditor({ initialDoc, pageID }) {
2342
2394
  const itemRecord = item;
2343
2395
  const itemMedia = resolveMedia(itemRecord?.media);
2344
2396
  const itemImageHeight = parsePixelNumber(itemRecord?.imageHeight, 120);
2345
- const hasCustomFocus = typeof itemRecord?.imagePositionX === "number" || typeof itemRecord?.imagePositionX === "string" || typeof itemRecord?.imagePositionY === "number" || typeof itemRecord?.imagePositionY === "string";
2397
+ const itemPositionX = parseOptionalPercentNumber(itemRecord?.imagePositionX);
2398
+ const itemPositionY = parseOptionalPercentNumber(itemRecord?.imagePositionY);
2346
2399
  const itemImageStyle = getImagePresentationStyle({
2347
2400
  cornerStyle: normalizeImageCornerStyle(itemRecord?.imageCornerStyle),
2348
2401
  fit: normalizeImageFit(itemRecord?.imageFit),
2349
2402
  position: normalizeImagePosition(itemRecord?.imagePosition),
2350
- ...hasCustomFocus ? {
2351
- positionX: parsePercentNumber(itemRecord?.imagePositionX, 50),
2352
- positionY: parsePercentNumber(itemRecord?.imagePositionY, 50)
2353
- } : {}
2403
+ positionX: itemPositionX,
2404
+ positionY: itemPositionY
2354
2405
  });
2355
2406
  const isItemSelected = selectedIndex === index && selectedItemIndex === itemIndex;
2356
2407
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -2543,15 +2594,14 @@ function BuilderPageEditor({ initialDoc, pageID }) {
2543
2594
  const itemRecord = item;
2544
2595
  const media = resolveMedia(itemRecord?.media);
2545
2596
  const imageHeight = parsePixelNumber(itemRecord?.imageHeight, 54);
2546
- const hasCustomFocus = typeof itemRecord?.imagePositionX === "number" || typeof itemRecord?.imagePositionX === "string" || typeof itemRecord?.imagePositionY === "number" || typeof itemRecord?.imagePositionY === "string";
2597
+ const itemPositionX = parseOptionalPercentNumber(itemRecord?.imagePositionX);
2598
+ const itemPositionY = parseOptionalPercentNumber(itemRecord?.imagePositionY);
2547
2599
  const imageStyle = getImagePresentationStyle({
2548
2600
  cornerStyle: normalizeImageCornerStyle(itemRecord?.imageCornerStyle),
2549
2601
  fit: normalizeImageFit(itemRecord?.imageFit),
2550
2602
  position: normalizeImagePosition(itemRecord?.imagePosition),
2551
- ...hasCustomFocus ? {
2552
- positionX: parsePercentNumber(itemRecord?.imagePositionX, 50),
2553
- positionY: parsePercentNumber(itemRecord?.imagePositionY, 50)
2554
- } : {},
2603
+ positionX: itemPositionX,
2604
+ positionY: itemPositionY,
2555
2605
  roundedRadius: 10
2556
2606
  });
2557
2607
  const isItemSelected = selectedIndex === index && selectedItemIndex === itemIndex;
@@ -2636,15 +2686,14 @@ function BuilderPageEditor({ initialDoc, pageID }) {
2636
2686
  const beforeMedia = resolveMedia(itemRecord?.beforeMedia);
2637
2687
  const afterMedia = resolveMedia(itemRecord?.afterMedia);
2638
2688
  const imageHeight = parsePixelNumber(itemRecord?.imageHeight, 160);
2639
- const hasCustomFocus = typeof itemRecord?.imagePositionX === "number" || typeof itemRecord?.imagePositionX === "string" || typeof itemRecord?.imagePositionY === "number" || typeof itemRecord?.imagePositionY === "string";
2689
+ const itemPositionX = parseOptionalPercentNumber(itemRecord?.imagePositionX);
2690
+ const itemPositionY = parseOptionalPercentNumber(itemRecord?.imagePositionY);
2640
2691
  const imageStyle = getImagePresentationStyle({
2641
2692
  cornerStyle: normalizeImageCornerStyle(itemRecord?.imageCornerStyle),
2642
2693
  fit: normalizeImageFit(itemRecord?.imageFit),
2643
2694
  position: normalizeImagePosition(itemRecord?.imagePosition),
2644
- ...hasCustomFocus ? {
2645
- positionX: parsePercentNumber(itemRecord?.imagePositionX, 50),
2646
- positionY: parsePercentNumber(itemRecord?.imagePositionY, 50)
2647
- } : {}
2695
+ positionX: itemPositionX,
2696
+ positionY: itemPositionY
2648
2697
  });
2649
2698
  const isItemSelected = selectedIndex === index && selectedItemIndex === itemIndex;
2650
2699
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
@@ -3811,6 +3860,120 @@ function BuilderPageEditor({ initialDoc, pageID }) {
3811
3860
  )
3812
3861
  ] })
3813
3862
  ] }),
3863
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { ...sidebarSectionStyle, display: "grid", gap: 8 }, children: [
3864
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { color: "var(--ink-700)", fontSize: 12, fontWeight: 600 }, children: "Hero Overlay" }),
3865
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: sidebarLabelStyle, children: [
3866
+ "Overlay Type",
3867
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
3868
+ "select",
3869
+ {
3870
+ onChange: (event) => updateSelectedField("backgroundOverlayMode", event.target.value),
3871
+ style: sidebarInputStyle,
3872
+ value: normalizeText(selectedBlock.backgroundOverlayMode, "none"),
3873
+ children: [
3874
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "none", children: "None" }),
3875
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "solid", children: "Solid" }),
3876
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "gradient", children: "Gradient" })
3877
+ ]
3878
+ }
3879
+ )
3880
+ ] }),
3881
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: sidebarLabelStyle, children: [
3882
+ "Opacity (%)",
3883
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { alignItems: "center", display: "grid", gap: 8, gridTemplateColumns: "1fr 90px" }, children: [
3884
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
3885
+ "input",
3886
+ {
3887
+ max: 100,
3888
+ min: 0,
3889
+ onChange: (event) => updateSelectedField("backgroundOverlayOpacity", Number(event.target.value)),
3890
+ type: "range",
3891
+ value: parsePercentNumber(selectedBlock.backgroundOverlayOpacity, 45)
3892
+ }
3893
+ ),
3894
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
3895
+ "input",
3896
+ {
3897
+ max: 100,
3898
+ min: 0,
3899
+ onChange: (event) => updateSelectedField(
3900
+ "backgroundOverlayOpacity",
3901
+ event.target.value === "" ? 45 : Number(event.target.value)
3902
+ ),
3903
+ style: sidebarInputStyle,
3904
+ type: "number",
3905
+ value: parsePercentNumber(selectedBlock.backgroundOverlayOpacity, 45)
3906
+ }
3907
+ )
3908
+ ] })
3909
+ ] }),
3910
+ normalizeText(selectedBlock.backgroundOverlayMode, "none") === "solid" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: sidebarLabelStyle, children: [
3911
+ "Overlay Color",
3912
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
3913
+ "input",
3914
+ {
3915
+ onChange: (event) => updateSelectedField("backgroundOverlayColor", event.target.value),
3916
+ style: { ...sidebarInputStyle, height: 36, padding: 4 },
3917
+ type: "color",
3918
+ value: parseColor(selectedBlock.backgroundOverlayColor, "#000000")
3919
+ }
3920
+ )
3921
+ ] }) : null,
3922
+ normalizeText(selectedBlock.backgroundOverlayMode, "none") === "gradient" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
3923
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "grid", gap: 6, gridTemplateColumns: "1fr 1fr" }, children: [
3924
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: sidebarLabelStyle, children: [
3925
+ "From",
3926
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
3927
+ "input",
3928
+ {
3929
+ onChange: (event) => updateSelectedField("backgroundOverlayGradientFrom", event.target.value),
3930
+ style: { ...sidebarInputStyle, height: 36, padding: 4 },
3931
+ type: "color",
3932
+ value: parseColor(selectedBlock.backgroundOverlayGradientFrom, "#0d4a37")
3933
+ }
3934
+ )
3935
+ ] }),
3936
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: sidebarLabelStyle, children: [
3937
+ "To",
3938
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
3939
+ "input",
3940
+ {
3941
+ onChange: (event) => updateSelectedField("backgroundOverlayGradientTo", event.target.value),
3942
+ style: { ...sidebarInputStyle, height: 36, padding: 4 },
3943
+ type: "color",
3944
+ value: parseColor(selectedBlock.backgroundOverlayGradientTo, "#1f684f")
3945
+ }
3946
+ )
3947
+ ] })
3948
+ ] }),
3949
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: sidebarLabelStyle, children: [
3950
+ "Angle",
3951
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
3952
+ "input",
3953
+ {
3954
+ max: 360,
3955
+ min: 0,
3956
+ onChange: (event) => updateSelectedField("backgroundOverlayGradientAngle", event.target.value),
3957
+ style: sidebarInputStyle,
3958
+ type: "number",
3959
+ value: parseAngle(selectedBlock.backgroundOverlayGradientAngle, "135")
3960
+ }
3961
+ )
3962
+ ] })
3963
+ ] }) : null,
3964
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
3965
+ "button",
3966
+ {
3967
+ onClick: () => {
3968
+ updateSelectedField("backgroundOverlayMode", "none");
3969
+ updateSelectedField("backgroundOverlayOpacity", 45);
3970
+ },
3971
+ style: { borderRadius: 999, cursor: "pointer", fontSize: 12, padding: "7px 10px" },
3972
+ type: "button",
3973
+ children: "Clear Hero Overlay"
3974
+ }
3975
+ )
3976
+ ] }),
3814
3977
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: sidebarLabelStyle, children: [
3815
3978
  "Background Color",
3816
3979
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -4041,8 +4204,6 @@ function BuilderPageEditor({ initialDoc, pageID }) {
4041
4204
  {
4042
4205
  onChange: (event) => {
4043
4206
  updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, "imagePosition", event.target.value);
4044
- updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, "imagePositionX", null);
4045
- updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, "imagePositionY", null);
4046
4207
  },
4047
4208
  style: sidebarInputStyle,
4048
4209
  value: (() => {
@@ -4495,8 +4656,6 @@ function BuilderPageEditor({ initialDoc, pageID }) {
4495
4656
  {
4496
4657
  onChange: (event) => {
4497
4658
  updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, "imagePosition", event.target.value);
4498
- updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, "imagePositionX", null);
4499
- updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, "imagePositionY", null);
4500
4659
  },
4501
4660
  style: sidebarInputStyle,
4502
4661
  value: (() => {
@@ -4866,8 +5025,6 @@ function BuilderPageEditor({ initialDoc, pageID }) {
4866
5025
  {
4867
5026
  onChange: (event) => {
4868
5027
  updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, "imagePosition", event.target.value);
4869
- updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, "imagePositionX", null);
4870
- updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, "imagePositionY", null);
4871
5028
  },
4872
5029
  style: sidebarInputStyle,
4873
5030
  value: (() => {
@@ -84,6 +84,12 @@ var defaultNodeData = {
84
84
  hero: {
85
85
  ...withSectionStyleDefaults({}),
86
86
  backgroundColor: "",
87
+ backgroundOverlayMode: "none",
88
+ backgroundOverlayOpacity: 45,
89
+ backgroundOverlayColor: "#000000",
90
+ backgroundOverlayGradientFrom: "#0d4a37",
91
+ backgroundOverlayGradientTo: "#1f684f",
92
+ backgroundOverlayGradientAngle: "135",
87
93
  backgroundImageCornerStyle: "rounded",
88
94
  backgroundImageFit: "cover",
89
95
  backgroundImagePosition: "center",
@@ -472,29 +478,31 @@ var heroHeightMap = {
472
478
  var normalizeImageFit = (value) => normalizeHeroImageFit(value);
473
479
  var normalizeImageCornerStyle = (value, legacyFitValue) => normalizeHeroImageCornerStyle(value, legacyFitValue);
474
480
  var normalizeImagePosition = (value) => normalizeHeroImagePosition(value);
475
- var imageObjectPosition = (value, fit = "cover") => {
481
+ var positionPercent = (value, fit) => {
476
482
  const resolved = fit === "cover" && (value === "left" || value === "right") ? "center" : value;
477
483
  switch (resolved) {
478
484
  case "top":
479
- return "center top";
485
+ return { x: 50, y: 0 };
480
486
  case "bottom":
481
- return "center bottom";
487
+ return { x: 50, y: 100 };
482
488
  case "left":
483
- return "left center";
489
+ return { x: 0, y: 50 };
484
490
  case "right":
485
- return "right center";
491
+ return { x: 100, y: 50 };
486
492
  default:
487
- return "center center";
493
+ return { x: 50, y: 50 };
488
494
  }
489
495
  };
490
496
  var getImagePresentationStyle = (options) => {
491
- const hasCustomPosition = typeof options.positionX === "number" || typeof options.positionY === "number";
492
- const x = typeof options.positionX === "number" && Number.isFinite(options.positionX) ? Math.max(0, Math.min(100, options.positionX)) : 50;
493
- const y = typeof options.positionY === "number" && Number.isFinite(options.positionY) ? Math.max(0, Math.min(100, options.positionY)) : 50;
497
+ const fit = options.fit || "cover";
498
+ const base = positionPercent(options.position || "center", fit);
499
+ const x = typeof options.positionX === "number" && Number.isFinite(options.positionX) ? Math.max(0, Math.min(100, options.positionX)) : base.x;
500
+ const y = typeof options.positionY === "number" && Number.isFinite(options.positionY) ? Math.max(0, Math.min(100, options.positionY)) : base.y;
494
501
  return {
495
502
  borderRadius: options.cornerStyle === "square" ? 0 : `${options.roundedRadius ?? 12}px`,
496
- objectFit: options.fit || "cover",
497
- objectPosition: hasCustomPosition ? `${x}% ${y}%` : imageObjectPosition(options.position || "center", options.fit || "cover")
503
+ objectFit: fit,
504
+ // Always use percent positioning so presets behave identically with/without custom axis overrides.
505
+ objectPosition: `${x}% ${y}%`
498
506
  };
499
507
  };
500
508
  function cloneBlockLayout(layout) {
@@ -787,6 +795,43 @@ function parsePixelNumber(value, fallback) {
787
795
  function parsePercentNumber(value, fallback) {
788
796
  return Math.max(0, Math.min(100, parsePixelNumber(value, fallback)));
789
797
  }
798
+ function parseOptionalPercentNumber(value) {
799
+ if (typeof value === "number" && Number.isFinite(value)) {
800
+ return Math.max(0, Math.min(100, value));
801
+ }
802
+ if (typeof value === "string") {
803
+ const parsed = Number(value);
804
+ if (Number.isFinite(parsed)) {
805
+ return Math.max(0, Math.min(100, parsed));
806
+ }
807
+ }
808
+ return void 0;
809
+ }
810
+ function hexToRgb(value) {
811
+ const normalized = value.trim();
812
+ if (!/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(normalized)) {
813
+ return null;
814
+ }
815
+ const hex = normalized.slice(1);
816
+ if (hex.length === 3) {
817
+ const r2 = parseInt(hex[0] + hex[0], 16);
818
+ const g2 = parseInt(hex[1] + hex[1], 16);
819
+ const b2 = parseInt(hex[2] + hex[2], 16);
820
+ return { r: r2, g: g2, b: b2 };
821
+ }
822
+ const r = parseInt(hex.slice(0, 2), 16);
823
+ const g = parseInt(hex.slice(2, 4), 16);
824
+ const b = parseInt(hex.slice(4, 6), 16);
825
+ return { r, g, b };
826
+ }
827
+ function rgbaFromHex(hex, alpha) {
828
+ const rgb = hexToRgb(hex);
829
+ const clamped = Number.isFinite(alpha) ? Math.max(0, Math.min(1, alpha)) : 1;
830
+ if (!rgb) {
831
+ return `rgba(0, 0, 0, ${clamped})`;
832
+ }
833
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${clamped})`;
834
+ }
790
835
  var sectionStyleFromBlock = (block, pageDefaults) => {
791
836
  const contentWidthRaw = normalizeText(block.contentWidth, defaultSectionStyle.contentWidth);
792
837
  const sectionPaddingRaw = normalizeText(block.sectionPaddingY, defaultSectionStyle.sectionPaddingY);
@@ -2097,12 +2142,20 @@ function BuilderPageEditor({ initialDoc, pageID }) {
2097
2142
  const backgroundImageURL = normalizeText(block.backgroundImageURL);
2098
2143
  const backgroundImage = media?.url || backgroundImageURL;
2099
2144
  const hasCustomHeroColor = backgroundColor.length > 0 && backgroundColor.toLowerCase() !== "#124a37";
2145
+ const overlayModeRaw = normalizeText(block?.backgroundOverlayMode, "none");
2146
+ const overlayMode = overlayModeRaw === "solid" || overlayModeRaw === "gradient" ? overlayModeRaw : "none";
2147
+ const overlayOpacity = parsePercentNumber(block?.backgroundOverlayOpacity, 45) / 100;
2148
+ const overlayColor = parseColor(block?.backgroundOverlayColor, "#000000");
2149
+ const overlayFrom = parseColor(block?.backgroundOverlayGradientFrom, "#0d4a37");
2150
+ const overlayTo = parseColor(block?.backgroundOverlayGradientTo, "#1f684f");
2151
+ const overlayAngle = parseAngle(block?.backgroundOverlayGradientAngle, "135");
2152
+ const overlayLayer = overlayMode === "solid" ? `linear-gradient(${rgbaFromHex(overlayColor, overlayOpacity)}, ${rgbaFromHex(overlayColor, overlayOpacity)})` : overlayMode === "gradient" ? `linear-gradient(${overlayAngle}deg, ${rgbaFromHex(overlayFrom, overlayOpacity)}, ${rgbaFromHex(overlayTo, overlayOpacity)})` : "";
2100
2153
  const mediaStyle = backgroundImage && variant === "default" ? {
2101
2154
  ...hasCustomHeroColor ? { backgroundColor } : {},
2102
- backgroundImage: `url('${backgroundImage}')`,
2103
- backgroundPosition: backgroundImagePosition,
2104
- backgroundRepeat: "no-repeat",
2105
- backgroundSize: backgroundImageFit,
2155
+ backgroundImage: overlayLayer ? `${overlayLayer}, url('${backgroundImage}')` : `url('${backgroundImage}')`,
2156
+ backgroundPosition: overlayLayer ? `center center, ${backgroundImagePosition}` : backgroundImagePosition,
2157
+ backgroundRepeat: overlayLayer ? "no-repeat, no-repeat" : "no-repeat",
2158
+ backgroundSize: overlayLayer ? `cover, ${backgroundImageFit}` : backgroundImageFit,
2106
2159
  minHeight: heroMinHeight
2107
2160
  } : hasCustomHeroColor && sectionBackgroundMode !== "none" ? {
2108
2161
  backgroundColor,
@@ -2215,15 +2268,14 @@ function BuilderPageEditor({ initialDoc, pageID }) {
2215
2268
  const itemRecord = item;
2216
2269
  const itemMedia = resolveMedia(itemRecord?.media);
2217
2270
  const itemImageHeight = parsePixelNumber(itemRecord?.imageHeight, 120);
2218
- const hasCustomFocus = typeof itemRecord?.imagePositionX === "number" || typeof itemRecord?.imagePositionX === "string" || typeof itemRecord?.imagePositionY === "number" || typeof itemRecord?.imagePositionY === "string";
2271
+ const itemPositionX = parseOptionalPercentNumber(itemRecord?.imagePositionX);
2272
+ const itemPositionY = parseOptionalPercentNumber(itemRecord?.imagePositionY);
2219
2273
  const itemImageStyle = getImagePresentationStyle({
2220
2274
  cornerStyle: normalizeImageCornerStyle(itemRecord?.imageCornerStyle),
2221
2275
  fit: normalizeImageFit(itemRecord?.imageFit),
2222
2276
  position: normalizeImagePosition(itemRecord?.imagePosition),
2223
- ...hasCustomFocus ? {
2224
- positionX: parsePercentNumber(itemRecord?.imagePositionX, 50),
2225
- positionY: parsePercentNumber(itemRecord?.imagePositionY, 50)
2226
- } : {}
2277
+ positionX: itemPositionX,
2278
+ positionY: itemPositionY
2227
2279
  });
2228
2280
  const isItemSelected = selectedIndex === index && selectedItemIndex === itemIndex;
2229
2281
  return /* @__PURE__ */ jsxs(
@@ -2314,15 +2366,14 @@ function BuilderPageEditor({ initialDoc, pageID }) {
2314
2366
  const itemRecord = item;
2315
2367
  const itemMedia = resolveMedia(itemRecord?.media);
2316
2368
  const itemImageHeight = parsePixelNumber(itemRecord?.imageHeight, 120);
2317
- const hasCustomFocus = typeof itemRecord?.imagePositionX === "number" || typeof itemRecord?.imagePositionX === "string" || typeof itemRecord?.imagePositionY === "number" || typeof itemRecord?.imagePositionY === "string";
2369
+ const itemPositionX = parseOptionalPercentNumber(itemRecord?.imagePositionX);
2370
+ const itemPositionY = parseOptionalPercentNumber(itemRecord?.imagePositionY);
2318
2371
  const itemImageStyle = getImagePresentationStyle({
2319
2372
  cornerStyle: normalizeImageCornerStyle(itemRecord?.imageCornerStyle),
2320
2373
  fit: normalizeImageFit(itemRecord?.imageFit),
2321
2374
  position: normalizeImagePosition(itemRecord?.imagePosition),
2322
- ...hasCustomFocus ? {
2323
- positionX: parsePercentNumber(itemRecord?.imagePositionX, 50),
2324
- positionY: parsePercentNumber(itemRecord?.imagePositionY, 50)
2325
- } : {}
2375
+ positionX: itemPositionX,
2376
+ positionY: itemPositionY
2326
2377
  });
2327
2378
  const isItemSelected = selectedIndex === index && selectedItemIndex === itemIndex;
2328
2379
  return /* @__PURE__ */ jsx(
@@ -2515,15 +2566,14 @@ function BuilderPageEditor({ initialDoc, pageID }) {
2515
2566
  const itemRecord = item;
2516
2567
  const media = resolveMedia(itemRecord?.media);
2517
2568
  const imageHeight = parsePixelNumber(itemRecord?.imageHeight, 54);
2518
- const hasCustomFocus = typeof itemRecord?.imagePositionX === "number" || typeof itemRecord?.imagePositionX === "string" || typeof itemRecord?.imagePositionY === "number" || typeof itemRecord?.imagePositionY === "string";
2569
+ const itemPositionX = parseOptionalPercentNumber(itemRecord?.imagePositionX);
2570
+ const itemPositionY = parseOptionalPercentNumber(itemRecord?.imagePositionY);
2519
2571
  const imageStyle = getImagePresentationStyle({
2520
2572
  cornerStyle: normalizeImageCornerStyle(itemRecord?.imageCornerStyle),
2521
2573
  fit: normalizeImageFit(itemRecord?.imageFit),
2522
2574
  position: normalizeImagePosition(itemRecord?.imagePosition),
2523
- ...hasCustomFocus ? {
2524
- positionX: parsePercentNumber(itemRecord?.imagePositionX, 50),
2525
- positionY: parsePercentNumber(itemRecord?.imagePositionY, 50)
2526
- } : {},
2575
+ positionX: itemPositionX,
2576
+ positionY: itemPositionY,
2527
2577
  roundedRadius: 10
2528
2578
  });
2529
2579
  const isItemSelected = selectedIndex === index && selectedItemIndex === itemIndex;
@@ -2608,15 +2658,14 @@ function BuilderPageEditor({ initialDoc, pageID }) {
2608
2658
  const beforeMedia = resolveMedia(itemRecord?.beforeMedia);
2609
2659
  const afterMedia = resolveMedia(itemRecord?.afterMedia);
2610
2660
  const imageHeight = parsePixelNumber(itemRecord?.imageHeight, 160);
2611
- const hasCustomFocus = typeof itemRecord?.imagePositionX === "number" || typeof itemRecord?.imagePositionX === "string" || typeof itemRecord?.imagePositionY === "number" || typeof itemRecord?.imagePositionY === "string";
2661
+ const itemPositionX = parseOptionalPercentNumber(itemRecord?.imagePositionX);
2662
+ const itemPositionY = parseOptionalPercentNumber(itemRecord?.imagePositionY);
2612
2663
  const imageStyle = getImagePresentationStyle({
2613
2664
  cornerStyle: normalizeImageCornerStyle(itemRecord?.imageCornerStyle),
2614
2665
  fit: normalizeImageFit(itemRecord?.imageFit),
2615
2666
  position: normalizeImagePosition(itemRecord?.imagePosition),
2616
- ...hasCustomFocus ? {
2617
- positionX: parsePercentNumber(itemRecord?.imagePositionX, 50),
2618
- positionY: parsePercentNumber(itemRecord?.imagePositionY, 50)
2619
- } : {}
2667
+ positionX: itemPositionX,
2668
+ positionY: itemPositionY
2620
2669
  });
2621
2670
  const isItemSelected = selectedIndex === index && selectedItemIndex === itemIndex;
2622
2671
  return /* @__PURE__ */ jsxs(
@@ -3783,6 +3832,120 @@ function BuilderPageEditor({ initialDoc, pageID }) {
3783
3832
  )
3784
3833
  ] })
3785
3834
  ] }),
3835
+ /* @__PURE__ */ jsxs("div", { style: { ...sidebarSectionStyle, display: "grid", gap: 8 }, children: [
3836
+ /* @__PURE__ */ jsx("div", { style: { color: "var(--ink-700)", fontSize: 12, fontWeight: 600 }, children: "Hero Overlay" }),
3837
+ /* @__PURE__ */ jsxs("label", { style: sidebarLabelStyle, children: [
3838
+ "Overlay Type",
3839
+ /* @__PURE__ */ jsxs(
3840
+ "select",
3841
+ {
3842
+ onChange: (event) => updateSelectedField("backgroundOverlayMode", event.target.value),
3843
+ style: sidebarInputStyle,
3844
+ value: normalizeText(selectedBlock.backgroundOverlayMode, "none"),
3845
+ children: [
3846
+ /* @__PURE__ */ jsx("option", { value: "none", children: "None" }),
3847
+ /* @__PURE__ */ jsx("option", { value: "solid", children: "Solid" }),
3848
+ /* @__PURE__ */ jsx("option", { value: "gradient", children: "Gradient" })
3849
+ ]
3850
+ }
3851
+ )
3852
+ ] }),
3853
+ /* @__PURE__ */ jsxs("label", { style: sidebarLabelStyle, children: [
3854
+ "Opacity (%)",
3855
+ /* @__PURE__ */ jsxs("div", { style: { alignItems: "center", display: "grid", gap: 8, gridTemplateColumns: "1fr 90px" }, children: [
3856
+ /* @__PURE__ */ jsx(
3857
+ "input",
3858
+ {
3859
+ max: 100,
3860
+ min: 0,
3861
+ onChange: (event) => updateSelectedField("backgroundOverlayOpacity", Number(event.target.value)),
3862
+ type: "range",
3863
+ value: parsePercentNumber(selectedBlock.backgroundOverlayOpacity, 45)
3864
+ }
3865
+ ),
3866
+ /* @__PURE__ */ jsx(
3867
+ "input",
3868
+ {
3869
+ max: 100,
3870
+ min: 0,
3871
+ onChange: (event) => updateSelectedField(
3872
+ "backgroundOverlayOpacity",
3873
+ event.target.value === "" ? 45 : Number(event.target.value)
3874
+ ),
3875
+ style: sidebarInputStyle,
3876
+ type: "number",
3877
+ value: parsePercentNumber(selectedBlock.backgroundOverlayOpacity, 45)
3878
+ }
3879
+ )
3880
+ ] })
3881
+ ] }),
3882
+ normalizeText(selectedBlock.backgroundOverlayMode, "none") === "solid" ? /* @__PURE__ */ jsxs("label", { style: sidebarLabelStyle, children: [
3883
+ "Overlay Color",
3884
+ /* @__PURE__ */ jsx(
3885
+ "input",
3886
+ {
3887
+ onChange: (event) => updateSelectedField("backgroundOverlayColor", event.target.value),
3888
+ style: { ...sidebarInputStyle, height: 36, padding: 4 },
3889
+ type: "color",
3890
+ value: parseColor(selectedBlock.backgroundOverlayColor, "#000000")
3891
+ }
3892
+ )
3893
+ ] }) : null,
3894
+ normalizeText(selectedBlock.backgroundOverlayMode, "none") === "gradient" ? /* @__PURE__ */ jsxs(Fragment, { children: [
3895
+ /* @__PURE__ */ jsxs("div", { style: { display: "grid", gap: 6, gridTemplateColumns: "1fr 1fr" }, children: [
3896
+ /* @__PURE__ */ jsxs("label", { style: sidebarLabelStyle, children: [
3897
+ "From",
3898
+ /* @__PURE__ */ jsx(
3899
+ "input",
3900
+ {
3901
+ onChange: (event) => updateSelectedField("backgroundOverlayGradientFrom", event.target.value),
3902
+ style: { ...sidebarInputStyle, height: 36, padding: 4 },
3903
+ type: "color",
3904
+ value: parseColor(selectedBlock.backgroundOverlayGradientFrom, "#0d4a37")
3905
+ }
3906
+ )
3907
+ ] }),
3908
+ /* @__PURE__ */ jsxs("label", { style: sidebarLabelStyle, children: [
3909
+ "To",
3910
+ /* @__PURE__ */ jsx(
3911
+ "input",
3912
+ {
3913
+ onChange: (event) => updateSelectedField("backgroundOverlayGradientTo", event.target.value),
3914
+ style: { ...sidebarInputStyle, height: 36, padding: 4 },
3915
+ type: "color",
3916
+ value: parseColor(selectedBlock.backgroundOverlayGradientTo, "#1f684f")
3917
+ }
3918
+ )
3919
+ ] })
3920
+ ] }),
3921
+ /* @__PURE__ */ jsxs("label", { style: sidebarLabelStyle, children: [
3922
+ "Angle",
3923
+ /* @__PURE__ */ jsx(
3924
+ "input",
3925
+ {
3926
+ max: 360,
3927
+ min: 0,
3928
+ onChange: (event) => updateSelectedField("backgroundOverlayGradientAngle", event.target.value),
3929
+ style: sidebarInputStyle,
3930
+ type: "number",
3931
+ value: parseAngle(selectedBlock.backgroundOverlayGradientAngle, "135")
3932
+ }
3933
+ )
3934
+ ] })
3935
+ ] }) : null,
3936
+ /* @__PURE__ */ jsx(
3937
+ "button",
3938
+ {
3939
+ onClick: () => {
3940
+ updateSelectedField("backgroundOverlayMode", "none");
3941
+ updateSelectedField("backgroundOverlayOpacity", 45);
3942
+ },
3943
+ style: { borderRadius: 999, cursor: "pointer", fontSize: 12, padding: "7px 10px" },
3944
+ type: "button",
3945
+ children: "Clear Hero Overlay"
3946
+ }
3947
+ )
3948
+ ] }),
3786
3949
  /* @__PURE__ */ jsxs("label", { style: sidebarLabelStyle, children: [
3787
3950
  "Background Color",
3788
3951
  /* @__PURE__ */ jsx(
@@ -4013,8 +4176,6 @@ function BuilderPageEditor({ initialDoc, pageID }) {
4013
4176
  {
4014
4177
  onChange: (event) => {
4015
4178
  updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, "imagePosition", event.target.value);
4016
- updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, "imagePositionX", null);
4017
- updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, "imagePositionY", null);
4018
4179
  },
4019
4180
  style: sidebarInputStyle,
4020
4181
  value: (() => {
@@ -4467,8 +4628,6 @@ function BuilderPageEditor({ initialDoc, pageID }) {
4467
4628
  {
4468
4629
  onChange: (event) => {
4469
4630
  updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, "imagePosition", event.target.value);
4470
- updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, "imagePositionX", null);
4471
- updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, "imagePositionY", null);
4472
4631
  },
4473
4632
  style: sidebarInputStyle,
4474
4633
  value: (() => {
@@ -4838,8 +4997,6 @@ function BuilderPageEditor({ initialDoc, pageID }) {
4838
4997
  {
4839
4998
  onChange: (event) => {
4840
4999
  updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, "imagePosition", event.target.value);
4841
- updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, "imagePositionX", null);
4842
- updateArrayItemField(selectedIndex ?? 0, "items", itemIndex, "imagePositionY", null);
4843
5000
  },
4844
5001
  style: sidebarInputStyle,
4845
5002
  value: (() => {
@@ -109,6 +109,12 @@ var defaultNodeData = {
109
109
  hero: {
110
110
  ...withSectionStyleDefaults({}),
111
111
  backgroundColor: "",
112
+ backgroundOverlayMode: "none",
113
+ backgroundOverlayOpacity: 45,
114
+ backgroundOverlayColor: "#000000",
115
+ backgroundOverlayGradientFrom: "#0d4a37",
116
+ backgroundOverlayGradientTo: "#1f684f",
117
+ backgroundOverlayGradientAngle: "135",
112
118
  backgroundImageCornerStyle: "rounded",
113
119
  backgroundImageFit: "cover",
114
120
  backgroundImagePosition: "center",
@@ -6,7 +6,7 @@ import {
6
6
  pagePaletteGroups,
7
7
  pageStudioModuleManifest,
8
8
  studioDocumentToLayout
9
- } from "../chunk-QW24Y4UH.mjs";
9
+ } from "../chunk-ZKG4V5MI.mjs";
10
10
  import "../chunk-SIL2J5MF.mjs";
11
11
  import "../chunk-6BWS3CLP.mjs";
12
12
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orion-studios/payload-studio",
3
- "version": "0.5.0-beta.35",
3
+ "version": "0.5.0-beta.37",
4
4
  "description": "Unified Payload CMS toolkit for Orion Studios",
5
5
  "types": "./dist/index.d.ts",
6
6
  "main": "./dist/index.js",