@drawnagency/primitives 0.1.74 → 0.1.76

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.
@@ -376,7 +376,7 @@ function Tabs({ tabs, defaultTabId, activeTabId, onTabChange, fullBleedTabBar })
376
376
  },
377
377
  tab.id
378
378
  )) }) }),
379
- /* @__PURE__ */ jsx8("div", { role: "tabpanel", className: cn(fullBleedTabBar && "pt-4"), children: activeTab?.content })
379
+ /* @__PURE__ */ jsx8("div", { role: "tabpanel", className: cn("px-px", fullBleedTabBar && "pt-4"), children: activeTab?.content })
380
380
  ] });
381
381
  }
382
382
 
@@ -31,7 +31,7 @@ import {
31
31
  buildBlockDropData,
32
32
  canDropBlock,
33
33
  isBlockDragData
34
- } from "./chunk-RIVBCL6U.js";
34
+ } from "./chunk-Q3T23HVW.js";
35
35
  import {
36
36
  useMediaLibrary,
37
37
  useResolvedMedia
@@ -536,6 +536,7 @@ var ChildBlockWrapper = forwardRef(
536
536
  onDuplicate,
537
537
  onColSpanChange,
538
538
  onOpenSettings,
539
+ clearSectionChrome,
539
540
  children
540
541
  }, ref) {
541
542
  return /* @__PURE__ */ jsxs4(
@@ -548,23 +549,33 @@ var ChildBlockWrapper = forwardRef(
548
549
  "hover:outline hover:outline-2 hover:outline-primary/30"
549
550
  ),
550
551
  children: [
551
- /* @__PURE__ */ jsxs4("div", { className: "absolute top-0 left-0 -translate-x-full z-20 flex flex-col items-center gap-1 opacity-0 transition-opacity group-hover/childblock:opacity-100 group-focus-within/childblock:opacity-100 pointer-events-none", children: [
552
- /* @__PURE__ */ jsx12("span", { className: "sr-only", children: label }),
553
- /* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(DragHandle, { ref: dragHandleRef }) }),
554
- /* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(ColSpanControl, { colSpan, columns, onChange: onColSpanChange }) }),
555
- hasSettings && onOpenSettings && /* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(SettingsButton, { onClick: onOpenSettings }) }),
556
- /* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(
557
- "button",
558
- {
559
- type: "button",
560
- "aria-label": "Duplicate block",
561
- onClick: onDuplicate,
562
- className: "cursor-pointer rounded p-1 text-base-contrast-light hover:text-primary",
563
- children: /* @__PURE__ */ jsx12(CopyPlus, { size: 16 })
564
- }
565
- ) }),
566
- /* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(DeleteButton, { onDelete }) })
567
- ] }),
552
+ /* @__PURE__ */ jsxs4(
553
+ "div",
554
+ {
555
+ "data-testid": "child-control-rail",
556
+ className: cn(
557
+ "absolute left-0 -translate-x-full z-20 flex flex-col items-center gap-1 opacity-0 transition-opacity group-hover/childblock:opacity-100 group-focus-within/childblock:opacity-100 pointer-events-none",
558
+ clearSectionChrome ? "top-8 xl:top-0" : "top-0"
559
+ ),
560
+ children: [
561
+ /* @__PURE__ */ jsx12("span", { className: "sr-only", children: label }),
562
+ /* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(DragHandle, { ref: dragHandleRef }) }),
563
+ /* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(ColSpanControl, { colSpan, columns, onChange: onColSpanChange }) }),
564
+ hasSettings && onOpenSettings && /* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(SettingsButton, { onClick: onOpenSettings }) }),
565
+ /* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(
566
+ "button",
567
+ {
568
+ type: "button",
569
+ "aria-label": "Duplicate block",
570
+ onClick: onDuplicate,
571
+ className: "cursor-pointer rounded p-1 text-base-contrast-light hover:text-primary",
572
+ children: /* @__PURE__ */ jsx12(CopyPlus, { size: 16 })
573
+ }
574
+ ) }),
575
+ /* @__PURE__ */ jsx12("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx12(DeleteButton, { onDelete }) })
576
+ ]
577
+ }
578
+ ),
568
579
  closestEdge === "left" && /* @__PURE__ */ jsx12(
569
580
  "div",
570
581
  {
@@ -764,6 +775,7 @@ function ContainerChild({
764
775
  hasSettings,
765
776
  mergedOptions,
766
777
  isEditMode,
778
+ clearSectionChrome,
767
779
  ChildComp,
768
780
  onDelete,
769
781
  onDuplicate,
@@ -797,6 +809,7 @@ function ContainerChild({
797
809
  closestEdge,
798
810
  isDragging,
799
811
  hasSettings,
812
+ clearSectionChrome,
800
813
  dragHandleRef: handleRef,
801
814
  onDelete,
802
815
  onDuplicate,
@@ -858,7 +871,12 @@ function Container({ content, isEditMode, onChange, openModal }) {
858
871
  };
859
872
  const emit = (nextSection) => onChange?.({ ...content, content: nextSection.content });
860
873
  const updateChild = (index, childContent) => {
861
- const next = children.map((c, i) => i === index ? childContent : c);
874
+ const next = children.map((c, i) => {
875
+ if (i !== index) return c;
876
+ const merged = { ...childContent, id: c.id ?? newId() };
877
+ if (c.layout !== void 0) merged.layout = c.layout;
878
+ return merged;
879
+ });
862
880
  onChange?.({ ...content, content: { ...content.content, children: next } });
863
881
  };
864
882
  const gridClass = cn(
@@ -951,6 +969,7 @@ function Container({ content, isEditMode, onChange, openModal }) {
951
969
  hasSettings,
952
970
  mergedOptions,
953
971
  isEditMode,
972
+ clearSectionChrome: index === 0,
954
973
  ChildComp: def.component,
955
974
  onDelete: () => emit(trimTrailingSpacers(removeChildAt(container, index).container)),
956
975
  onDuplicate: () => emit(duplicateChildAt(container, index, newId)),
@@ -13,6 +13,13 @@ export interface ChildBlockWrapperProps {
13
13
  onDuplicate: () => void;
14
14
  onColSpanChange: (span: number) => void;
15
15
  onOpenSettings?: () => void;
16
+ /**
17
+ * Below xl the parent SECTION's "+" hangs down into the left gutter where this
18
+ * rail starts — set on the container's first cell so the rail (not the cell)
19
+ * shifts down out of the collision. Cells never move: edit-mode layout must
20
+ * match view mode exactly.
21
+ */
22
+ clearSectionChrome?: boolean;
16
23
  children: ReactNode;
17
24
  }
18
25
  export declare const ChildBlockWrapper: import("react").ForwardRefExoticComponent<ChildBlockWrapperProps & import("react").RefAttributes<HTMLDivElement>>;
@@ -1 +1 @@
1
- {"version":3,"file":"ChildBlockWrapper.d.ts","sourceRoot":"","sources":["../../../src/components/editor/ChildBlockWrapper.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,SAAS,EAAE,KAAK,GAAG,EAAE,MAAM,OAAO,CAAC;AAC7D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uDAAuD,CAAC;AAQlF,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACvC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,eAAO,MAAM,iBAAiB,mHAkF7B,CAAC"}
1
+ {"version":3,"file":"ChildBlockWrapper.d.ts","sourceRoot":"","sources":["../../../src/components/editor/ChildBlockWrapper.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,SAAS,EAAE,KAAK,GAAG,EAAE,MAAM,OAAO,CAAC;AAC7D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uDAAuD,CAAC;AAQlF,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACvC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,eAAO,MAAM,iBAAiB,mHAyF7B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"SectionWrapper.d.ts","sourceRoot":"","sources":["../../../src/components/editor/SectionWrapper.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIvD,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,WAAW,EACX,MAAM,EACN,KAAK,EACL,KAAK,EACL,MAAM,EACN,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,SAAS,EACT,MAAM,EACN,cAAc,EACd,cAAc,EACd,eAAe,EACf,SAAS,EACT,eAAe,EACf,QAAQ,EACR,aAAa,EACb,UAAU,EACV,UAAU,EACV,sBAAsB,EACtB,WAAW,EACX,QAAQ,GACT,EAAE,YAAY,2CAgTd"}
1
+ {"version":3,"file":"SectionWrapper.d.ts","sourceRoot":"","sources":["../../../src/components/editor/SectionWrapper.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIvD,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,WAAW,EACX,MAAM,EACN,KAAK,EACL,KAAK,EACL,MAAM,EACN,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,SAAS,EACT,MAAM,EACN,cAAc,EACd,cAAc,EACd,eAAe,EACf,SAAS,EACT,eAAe,EACf,QAAQ,EACR,aAAa,EACb,UAAU,EACV,UAAU,EACV,sBAAsB,EACtB,WAAW,EACX,QAAQ,GACT,EAAE,YAAY,2CAqTd"}
@@ -11,7 +11,7 @@ import {
11
11
  buildBlockDropData,
12
12
  canDropBlock,
13
13
  isBlockDragData
14
- } from "../../chunk-RIVBCL6U.js";
14
+ } from "../../chunk-Q3T23HVW.js";
15
15
  import "../../chunk-ZSPCE6MZ.js";
16
16
  import "../../chunk-5THS4K5D.js";
17
17
  import {
@@ -540,7 +540,7 @@ function SectionWrapper({
540
540
  "div",
541
541
  {
542
542
  className: cn(
543
- "absolute -left-16 bottom-full z-30 mb-1 hidden xl:block transition-opacity",
543
+ "absolute -left-16 bottom-full z-30 hover:z-[60] mb-1 hidden xl:block transition-opacity",
544
544
  alwaysShow ? "opacity-100" : "opacity-0 group-hover:opacity-100"
545
545
  ),
546
546
  children: /* @__PURE__ */ jsx7(InsertButton, { index, onInsert: onRequestInsert })
@@ -550,13 +550,16 @@ function SectionWrapper({
550
550
  "div",
551
551
  {
552
552
  className: cn(
553
- "absolute left-0 bottom-full z-30 mb-1 flex items-center gap-1.5 transition-opacity",
553
+ "absolute left-0 bottom-full z-30 hover:z-[60] mb-1 flex items-center gap-1.5 transition-opacity",
554
554
  alwaysShow ? "opacity-100" : "opacity-0 group-hover:opacity-100"
555
555
  ),
556
556
  children: [
557
- /* @__PURE__ */ jsxs5("div", { className: "-ml-[34px] flex flex-col items-center", children: [
557
+ /* @__PURE__ */ jsxs5("div", { className: "relative -ml-[34px] flex flex-col items-center", children: [
558
558
  /* @__PURE__ */ jsx7(DragHandle, { ref: handleRef }),
559
- onRequestInsert && !isDragging && chromeReady && /* @__PURE__ */ jsx7("div", { className: "xl:hidden -mt-1", children: /* @__PURE__ */ jsx7(InsertButton, { index, onInsert: onRequestInsert }) })
559
+ onRequestInsert && !isDragging && chromeReady && // Below xl the gutter can't fit the plus beside the handle, so it
560
+ // hangs below it (absolute → no row-height contribution: the handle
561
+ // stays put and the pair stacks DOWN instead of centering).
562
+ /* @__PURE__ */ jsx7("div", { className: "absolute top-full xl:hidden", children: /* @__PURE__ */ jsx7(InsertButton, { index, onInsert: onRequestInsert }) })
560
563
  ] }),
561
564
  /* @__PURE__ */ jsx7("span", { className: "pointer-events-none select-none whitespace-nowrap text-sm capitalize text-base-contrast-light/80", children: definition.label })
562
565
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"Container.d.ts","sourceRoot":"","sources":["../../../../src/components/sections/Container/Container.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAgB3D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAqGzD,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,gBAAgB,CAAA;KAAE,CAAC;IACpD,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,KAAK,IAAI,CAAC;CACzD;AAkDD,wBAAgB,SAAS,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,cAAc,2CA8KrF"}
1
+ {"version":3,"file":"Container.d.ts","sourceRoot":"","sources":["../../../../src/components/sections/Container/Container.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAgB3D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAyGzD,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,gBAAgB,CAAA;KAAE,CAAC;IACpD,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,KAAK,IAAI,CAAC;CACzD;AAkDD,wBAAgB,SAAS,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,cAAc,2CAyLrF"}
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  allSectionDefs
3
- } from "../../chunk-YYDQGA2N.js";
3
+ } from "../../chunk-SWEVWC5K.js";
4
4
  import "../../chunk-NKVZGPR6.js";
5
5
  import "../../chunk-Y4JQGO6G.js";
6
6
  import "../../chunk-7T2WQSWF.js";
7
7
  import "../../chunk-T7MP7ANP.js";
8
- import "../../chunk-RIVBCL6U.js";
8
+ import "../../chunk-Q3T23HVW.js";
9
9
  import "../../chunk-ZSPCE6MZ.js";
10
10
  import "../../chunk-5THS4K5D.js";
11
11
  import "../../chunk-IFHRHV7S.js";
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  allSectionDefs
3
- } from "../../chunk-YYDQGA2N.js";
3
+ } from "../../chunk-SWEVWC5K.js";
4
4
  import "../../chunk-NKVZGPR6.js";
5
5
  import "../../chunk-Y4JQGO6G.js";
6
6
  import "../../chunk-7T2WQSWF.js";
7
7
  import "../../chunk-T7MP7ANP.js";
8
- import "../../chunk-RIVBCL6U.js";
8
+ import "../../chunk-Q3T23HVW.js";
9
9
  import "../../chunk-ZSPCE6MZ.js";
10
10
  import "../../chunk-5THS4K5D.js";
11
11
  import "../../chunk-IFHRHV7S.js";
@@ -1 +1 @@
1
- {"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../src/components/shared/Tabs.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGjD,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,CAAC;CACpB;AAED,UAAU,SAAS;IACjB,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,eAAe,EAAE,EAAE,SAAS,2CAqChG"}
1
+ {"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../src/components/shared/Tabs.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGjD,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,CAAC;CACpB;AAED,UAAU,SAAS;IACjB,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,eAAe,EAAE,EAAE,SAAS,2CAwChG"}
@@ -1 +1 @@
1
- {"version":3,"file":"useEditorPublish.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditorPublish.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AA6C/D,UAAU,WAAW;IACnB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,aAAa,EAAE,MAAM,OAAO,CAAC;IAC7B,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACzC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,aAAa,EAAE,aAAa,CAAC;IAC7B,aAAa,EAAE,OAAO,CAAC;IACvB,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,iBAAiB,EAAE,SAAS,EAAE,CAAC;IAC/B,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,gBAAgB,EAAE,CAAC,cAAc,EAAE,SAAS,EAAE,EAAE,kBAAkB,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACtF,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACzE,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAI/B,cAAc,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IACpC,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAQD,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,QAAQ,GAAG,YAAY,CAAC;AAE7D,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,iBAAiB,EACjB,SAAS,EACT,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,eAAe,GAChB,EAAE,WAAW;;;;;;;EAoXb"}
1
+ {"version":3,"file":"useEditorPublish.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditorPublish.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAgD/D,UAAU,WAAW;IACnB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,aAAa,EAAE,MAAM,OAAO,CAAC;IAC7B,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACzC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,aAAa,EAAE,aAAa,CAAC;IAC7B,aAAa,EAAE,OAAO,CAAC;IACvB,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,iBAAiB,EAAE,SAAS,EAAE,CAAC;IAC/B,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,gBAAgB,EAAE,CAAC,cAAc,EAAE,SAAS,EAAE,EAAE,kBAAkB,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACtF,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACzE,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAI/B,cAAc,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IACpC,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAQD,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,QAAQ,GAAG,YAAY,CAAC;AAE7D,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,iBAAiB,EACjB,SAAS,EACT,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,eAAe,GAChB,EAAE,WAAW;;;;;;;EAoXb"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drawnagency/primitives",
3
- "version": "0.1.74",
3
+ "version": "0.1.76",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./package.json": "./package.json",
@@ -20,6 +20,13 @@ export interface ChildBlockWrapperProps {
20
20
  onDuplicate: () => void;
21
21
  onColSpanChange: (span: number) => void;
22
22
  onOpenSettings?: () => void;
23
+ /**
24
+ * Below xl the parent SECTION's "+" hangs down into the left gutter where this
25
+ * rail starts — set on the container's first cell so the rail (not the cell)
26
+ * shifts down out of the collision. Cells never move: edit-mode layout must
27
+ * match view mode exactly.
28
+ */
29
+ clearSectionChrome?: boolean;
23
30
  children: ReactNode;
24
31
  }
25
32
 
@@ -37,6 +44,7 @@ export const ChildBlockWrapper = forwardRef<HTMLDivElement, ChildBlockWrapperPro
37
44
  onDuplicate,
38
45
  onColSpanChange,
39
46
  onOpenSettings,
47
+ clearSectionChrome,
40
48
  children,
41
49
  },
42
50
  ref,
@@ -53,7 +61,13 @@ export const ChildBlockWrapper = forwardRef<HTMLDivElement, ChildBlockWrapperPro
53
61
  {/* Controls — vertical rail in the cell's LEFT gutter. Revealed on hover OR
54
62
  focus-within, so an open col-span popover (which traps focus) keeps the rail
55
63
  visible even when the pointer moves off the block to reach an option. */}
56
- <div className="absolute top-0 left-0 -translate-x-full z-20 flex flex-col items-center gap-1 opacity-0 transition-opacity group-hover/childblock:opacity-100 group-focus-within/childblock:opacity-100 pointer-events-none">
64
+ <div
65
+ data-testid="child-control-rail"
66
+ className={cn(
67
+ "absolute left-0 -translate-x-full z-20 flex flex-col items-center gap-1 opacity-0 transition-opacity group-hover/childblock:opacity-100 group-focus-within/childblock:opacity-100 pointer-events-none",
68
+ clearSectionChrome ? "top-8 xl:top-0" : "top-0",
69
+ )}
70
+ >
57
71
  <span className="sr-only">{label}</span>
58
72
  <div className="pointer-events-auto">
59
73
  <DragHandle ref={dragHandleRef} />
@@ -239,11 +239,13 @@ export function SectionWrapper({
239
239
  data-section-id={sectionId}
240
240
  data-section-type={sectionType}
241
241
  >
242
- {/* Plus button — left gutter on xl+, hidden below */}
242
+ {/* Plus button — left gutter on xl+, hidden below. hover:z-[60] lifts the
243
+ whole slot (a z-30 stacking context the tooltip can't escape) above the
244
+ inline section-type picker (z-50) while the tooltip is showing. */}
243
245
  {onRequestInsert && !isDragging && chromeReady && (
244
246
  <div
245
247
  className={cn(
246
- "absolute -left-16 bottom-full z-30 mb-1 hidden xl:block transition-opacity",
248
+ "absolute -left-16 bottom-full z-30 hover:z-[60] mb-1 hidden xl:block transition-opacity",
247
249
  alwaysShow ? "opacity-100" : "opacity-0 group-hover:opacity-100",
248
250
  )}
249
251
  >
@@ -254,14 +256,17 @@ export function SectionWrapper({
254
256
  {/* Drag handle + section label */}
255
257
  <div
256
258
  className={cn(
257
- "absolute left-0 bottom-full z-30 mb-1 flex items-center gap-1.5 transition-opacity",
259
+ "absolute left-0 bottom-full z-30 hover:z-[60] mb-1 flex items-center gap-1.5 transition-opacity",
258
260
  alwaysShow ? "opacity-100" : "opacity-0 group-hover:opacity-100",
259
261
  )}
260
262
  >
261
- <div className="-ml-[34px] flex flex-col items-center">
263
+ <div className="relative -ml-[34px] flex flex-col items-center">
262
264
  <DragHandle ref={handleRef} />
263
265
  {onRequestInsert && !isDragging && chromeReady && (
264
- <div className="xl:hidden -mt-1">
266
+ // Below xl the gutter can't fit the plus beside the handle, so it
267
+ // hangs below it (absolute → no row-height contribution: the handle
268
+ // stays put and the pair stacks DOWN instead of centering).
269
+ <div className="absolute top-full xl:hidden">
265
270
  <InsertButton index={index} onInsert={onRequestInsert} />
266
271
  </div>
267
272
  )}
@@ -40,6 +40,8 @@ interface ContainerChildProps {
40
40
  hasSettings: boolean;
41
41
  mergedOptions: Record<string, unknown>;
42
42
  isEditMode: boolean;
43
+ /** First cell only: shift the control rail below the section's stacked "+" (below xl). */
44
+ clearSectionChrome?: boolean;
43
45
  ChildComp: ChildComponent;
44
46
  onDelete: () => void;
45
47
  onDuplicate: () => void;
@@ -65,6 +67,7 @@ function ContainerChild({
65
67
  hasSettings,
66
68
  mergedOptions,
67
69
  isEditMode,
70
+ clearSectionChrome,
68
71
  ChildComp,
69
72
  onDelete,
70
73
  onDuplicate,
@@ -97,6 +100,7 @@ function ContainerChild({
97
100
  closestEdge={closestEdge}
98
101
  isDragging={isDragging}
99
102
  hasSettings={hasSettings}
103
+ clearSectionChrome={clearSectionChrome}
100
104
  dragHandleRef={handleRef}
101
105
  onDelete={onDelete}
102
106
  onDuplicate={onDuplicate}
@@ -192,8 +196,18 @@ export function Container({ content, isEditMode, onChange, openModal }: Containe
192
196
  onChange?.({ ...content, content: nextSection.content });
193
197
 
194
198
  // Per-child inline content edits (e.g. prose/media bubble their own onChange).
199
+ // Section components emit id-less SectionContent (EditorShell re-attaches the id
200
+ // at the root) and know nothing of the layout envelope, so preserve both from
201
+ // the existing child — an id-less child fails save validation for the whole
202
+ // container. Minting when the existing child has no id self-heals drafts saved
203
+ // by the pre-fix path.
195
204
  const updateChild = (index: number, childContent: unknown) => {
196
- const next = children.map((c, i) => (i === index ? (childContent as Section) : c));
205
+ const next = children.map((c, i) => {
206
+ if (i !== index) return c;
207
+ const merged = { ...(childContent as Section), id: c.id ?? newId() };
208
+ if (c.layout !== undefined) merged.layout = c.layout;
209
+ return merged;
210
+ });
197
211
  onChange?.({ ...content, content: { ...content.content, children: next } });
198
212
  };
199
213
 
@@ -318,6 +332,7 @@ export function Container({ content, isEditMode, onChange, openModal }: Containe
318
332
  hasSettings={hasSettings}
319
333
  mergedOptions={mergedOptions}
320
334
  isEditMode={isEditMode}
335
+ clearSectionChrome={index === 0}
321
336
  ChildComp={def.component as ChildComponent}
322
337
  onDelete={() => emit(trimTrailingSpacers(removeChildAt(container, index).container))}
323
338
  onDuplicate={() => emit(duplicateChildAt(container, index, newId))}
@@ -57,7 +57,10 @@ export function Tabs({ tabs, defaultTabId, activeTabId, onTabChange, fullBleedTa
57
57
  ))}
58
58
  </div>
59
59
  </div>
60
- <div role="tabpanel" className={cn(fullBleedTabBar && "pt-4")}>{activeTab?.content}</div>
60
+ {/* px-px: the root's overflow-hidden would clip the 1px focus ring of
61
+ inputs that span the full panel width (rings are box-shadows drawn
62
+ outside the border box) — give them 1px to paint into. */}
63
+ <div role="tabpanel" className={cn("px-px", fullBleedTabBar && "pt-4")}>{activeTab?.content}</div>
61
64
  </div>
62
65
  );
63
66
  }
@@ -34,8 +34,11 @@ async function postSave(payload: object): Promise<{ sha: string }> {
34
34
  throw new Error("Network error while saving — check your connection and try again.");
35
35
  }
36
36
  if (!response.ok) {
37
- const errorBody = await response.json().catch(() => null) as { message?: string; error?: string } | null;
38
- const serverMessage = errorBody?.message || errorBody?.error;
37
+ const errorBody = await response.json().catch(() => null) as { message?: string; error?: string; details?: string } | null;
38
+ // `details` carries the field-level cause (e.g. the Zod path inside a failing
39
+ // container child) — without it a validation failure only names the section.
40
+ const baseMessage = errorBody?.message || errorBody?.error;
41
+ const serverMessage = baseMessage && errorBody?.details ? `${baseMessage} — ${errorBody.details}` : baseMessage;
39
42
  const fallback = !errorBody && body.length > 5_500_000
40
43
  ? "This save is too large to send in one request — remove some images from the media library and try again."
41
44
  : `Save failed (HTTP ${response.status})`;