@ptengine/lp-editor-core 1.0.0-alpha.2 → 1.0.0-alpha.3

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.
package/dist/index.js CHANGED
@@ -251,6 +251,9 @@ var THEME_PT_ID = "theme";
251
251
  var ROOT_PT_ID = "root";
252
252
  var FORMAT_META_NAME = "lpx-format";
253
253
  var FORMAT_VERSION = "4";
254
+ var WRAP_ATTR = "data-pt-wrap";
255
+ var WRAP_SECTION_PT_ID = "ptwrap-section";
256
+ var WRAP_CONTAINER_PT_ID = "ptwrap-container";
254
257
  var SWITCHES = [
255
258
  {
256
259
  key: "hide",
@@ -352,6 +355,9 @@ var rules = {
352
355
  rootPtId: ROOT_PT_ID,
353
356
  formatMetaName: FORMAT_META_NAME,
354
357
  formatVersion: FORMAT_VERSION,
358
+ wrapAttr: WRAP_ATTR,
359
+ wrapSectionPtId: WRAP_SECTION_PT_ID,
360
+ wrapContainerPtId: WRAP_CONTAINER_PT_ID,
355
361
  switches: SWITCHES,
356
362
  crossDeviceConsistentProperties: CROSS_DEVICE_CONSISTENT_PROPERTIES,
357
363
  opaqueModes: OPAQUE_MODES,
@@ -362,43 +368,8 @@ var rules = {
362
368
  arbitraryValueAllowedProperties: ARBITRARY_VALUE_ALLOWED_PROPERTIES
363
369
  };
364
370
 
365
- // src/kinds.ts
366
- var KIND_PROFILES = {
367
- page: {
368
- root: "document",
369
- layers: ["section", "container", "leaf"],
370
- compile: "document",
371
- leafTypes: ["text", "media", "button", "shape"],
372
- components: {
373
- carousel: "self",
374
- faq: "self",
375
- tabs: "self",
376
- "sticky-cta": "self",
377
- form: "self"
378
- },
379
- units: { vh: true },
380
- customCode: true
381
- },
382
- popup: {
383
- root: "fragment",
384
- // 弹窗无 section 层:root › children。
385
- layers: ["container", "leaf"],
386
- compile: "shadow-px",
387
- leafTypes: ["text", "media", "button", "shape"],
388
- components: {
389
- form: "engage-sdk",
390
- countdown: "engage-sdk",
391
- carousel: "self",
392
- faq: "self",
393
- tabs: "self"
394
- },
395
- units: { vh: false },
396
- customCode: false
397
- }
398
- };
399
-
400
371
  // src/version.ts
401
- var VERSION = "1.0.0-alpha.2";
372
+ var VERSION = "1.0.0-alpha.3";
402
373
  var COMPILER_VERSION = "1";
403
374
 
404
375
  // src/validate/tree.ts
@@ -564,6 +535,163 @@ function* walkElements(root) {
564
535
  for (let i = 0; i < list.length; i++) yield list[i];
565
536
  }
566
537
 
538
+ // src/wrap.ts
539
+ function isWrapLayer(el) {
540
+ return el.hasAttribute(WRAP_ATTR);
541
+ }
542
+ var SKELETON = `<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="${FORMAT_META_NAME}" content="${FORMAT_VERSION}"></head><body></body></html>`;
543
+ function createWrap(parse) {
544
+ return function wrap(fragmentHtml) {
545
+ if (typeof fragmentHtml !== "string") {
546
+ throw new TypeError("wrap(): fragmentHtml \u5FC5\u987B\u662F\u5B57\u7B26\u4E32");
547
+ }
548
+ const doc = parse(SKELETON);
549
+ const frag = parseFragment(doc, fragmentHtml);
550
+ const { theme, root, before, after } = checkFragmentShape(frag);
551
+ checkReservedLiterals(frag, root, theme);
552
+ const body = doc.body;
553
+ const attrs = root.attributes;
554
+ for (let i = 0; i < attrs.length; i++) {
555
+ body.setAttribute(attrs[i].name, attrs[i].value);
556
+ }
557
+ if (theme) doc.head.appendChild(theme);
558
+ const section = doc.createElement("section");
559
+ section.setAttribute(WRAP_ATTR, "");
560
+ section.setAttribute("data-pt-id", WRAP_SECTION_PT_ID);
561
+ const container = doc.createElement("div");
562
+ container.setAttribute(WRAP_ATTR, "");
563
+ container.setAttribute("data-pt-id", WRAP_CONTAINER_PT_ID);
564
+ while (root.firstChild) container.appendChild(root.firstChild);
565
+ section.appendChild(container);
566
+ for (const node of before) body.appendChild(node);
567
+ body.appendChild(section);
568
+ for (const node of after) body.appendChild(node);
569
+ return doc;
570
+ };
571
+ }
572
+ function checkFragmentShape(frag) {
573
+ const elements = [];
574
+ const nonElements = [];
575
+ let child = frag.firstChild;
576
+ while (child) {
577
+ const next = child.nextSibling;
578
+ if (child.nodeType === 1) {
579
+ elements.push(child);
580
+ } else if (child.nodeType === 3 && child.data.trim() === "") {
581
+ nonElements.push({ node: child, afterElements: elements.length });
582
+ } else {
583
+ throw new TypeError(
584
+ `wrap(): \u7247\u6BB5\u9876\u5C42\u53EA\u5141\u8BB8 theme \u5757\u3001\u5355\u4E00\u6839\u5143\u7D20\u4E0E\u7A7A\u767D \u2014\u2014 \u51FA\u73B0\u4E86 ${describeNode(child)}\u3002\u91CE\u751F\u5F62\u72B6\u8BF7\u5728\u8C03\u7528\u65B9\u7684 adapter \u91CC\u5148\u89C4\u6574\u3002`
585
+ );
586
+ }
587
+ child = next;
588
+ }
589
+ let theme = null;
590
+ let root;
591
+ if (elements.length === 2) {
592
+ if (!isThemeStyle(elements[0])) {
593
+ throw new TypeError(
594
+ 'wrap(): \u7247\u6BB5\u9876\u5C42\u6709\u4E24\u4E2A\u5143\u7D20\u65F6\uFF0C\u7B2C\u4E00\u4E2A\u5FC5\u987B\u662F\u4E3B\u9898\u5757 <style type="text/tailwindcss">'
595
+ );
596
+ }
597
+ theme = elements[0];
598
+ root = elements[1];
599
+ } else if (elements.length === 1) {
600
+ if (isThemeStyle(elements[0])) {
601
+ throw new TypeError("wrap(): \u7247\u6BB5\u53EA\u6709\u4E3B\u9898\u5757\u3001\u6CA1\u6709\u6839\u5143\u7D20");
602
+ }
603
+ root = elements[0];
604
+ } else {
605
+ throw new TypeError(
606
+ `wrap(): \u7247\u6BB5\u9876\u5C42\u5FC5\u987B\u6070\u6709\u4E00\u4E2A\u6839\u5143\u7D20\uFF08\u53EF\u9009\u4E00\u4E2A\u4E3B\u9898\u5757\uFF09\uFF0C\u5B9E\u9645\u6709 ${elements.length} \u4E2A\u5143\u7D20`
607
+ );
608
+ }
609
+ if (tag(root) !== "div") {
610
+ throw new TypeError(`wrap(): \u7247\u6BB5\u6839\u5143\u7D20\u5FC5\u987B\u662F <div>\uFF0C\u5B9E\u9645\u662F <${tag(root)}>`);
611
+ }
612
+ if (root.getAttribute("data-pt-id") !== ROOT_PT_ID) {
613
+ throw new TypeError(
614
+ `wrap(): \u7247\u6BB5\u6839\u5143\u7D20\u7684 data-pt-id \u5FC5\u987B\u662F ${ROOT_PT_ID}\uFF0C\u5B9E\u9645\u662F ${JSON.stringify(root.getAttribute("data-pt-id"))}\u3002\u5B83\u4F1A\u88AB\u8BA4\u9886\u6210\u6587\u6863\u7684 <body>\uFF0C\u6539\u540D\u4F1A\u8BA9\u57CB\u70B9\u951A\u70B9\u65AD\u94FE\u3002`
615
+ );
616
+ }
617
+ const rootIndex = elements.indexOf(root);
618
+ const before = [];
619
+ const after = [];
620
+ for (const { node, afterElements } of nonElements) {
621
+ if (afterElements <= rootIndex) before.push(node);
622
+ else after.push(node);
623
+ }
624
+ return { theme, root, before, after };
625
+ }
626
+ function checkReservedLiterals(frag, root, theme) {
627
+ const all = frag.querySelectorAll("*");
628
+ for (let i = 0; i < all.length; i++) {
629
+ const el = all[i];
630
+ if (el.hasAttribute(WRAP_ATTR)) {
631
+ throw new TypeError(
632
+ `wrap(): \u7247\u6BB5\u91CC\u5DF2\u7ECF\u5E26\u7740\u5408\u6210\u5C42\u6807\u8BB0 ${WRAP_ATTR} \u2014\u2014 \u591A\u534A\u662F\u4E0A\u4E00\u8F6E\u6F0F\u5265\u6216\u56DE\u704C\uFF0C\u5148\u67E5\u4E0A\u6E38\uFF0C\u4E0D\u8981\u91CD\u590D\u5305\u88F9\u3002`
633
+ );
634
+ }
635
+ const id = el.getAttribute("data-pt-id");
636
+ if (id === null) continue;
637
+ if (id === WRAP_SECTION_PT_ID || id === WRAP_CONTAINER_PT_ID) {
638
+ throw new TypeError(`wrap(): \u7247\u6BB5\u91CC\u5DF2\u7ECF\u5360\u7528\u4E86\u5408\u6210\u5C42\u7684\u4FDD\u7559 id ${id}`);
639
+ }
640
+ if (id === ROOT_PT_ID && el !== root) {
641
+ throw new TypeError(
642
+ `wrap(): \u4FDD\u7559 id ${ROOT_PT_ID} \u53EA\u8BB8\u51FA\u73B0\u5728\u7247\u6BB5\u6839\u5143\u7D20\u4E0A\uFF0C\u8FD9\u91CC\u51FA\u73B0\u5728 <${tag(el)}> \u4E0A \u2014\u2014 \u5305\u88F9\u540E\u4F1A\u53D8\u6210\u91CD\u590D id`
643
+ );
644
+ }
645
+ if (id === THEME_PT_ID && el !== theme) {
646
+ throw new TypeError(
647
+ `wrap(): \u4FDD\u7559 id ${THEME_PT_ID} \u53EA\u8BB8\u51FA\u73B0\u5728\u4E3B\u9898\u5757\u4E0A\uFF0C\u8FD9\u91CC\u51FA\u73B0\u5728 <${tag(el)}> \u4E0A`
648
+ );
649
+ }
650
+ }
651
+ }
652
+ function unwrap(doc) {
653
+ if (!doc || doc.nodeType !== 9) {
654
+ throw new TypeError("unwrap(): \u5165\u53C2\u5FC5\u987B\u662F Document");
655
+ }
656
+ const clone = doc.cloneNode(true);
657
+ const body = clone.body;
658
+ if (!body) throw new TypeError("unwrap(): \u6587\u6863\u6CA1\u6709 <body>");
659
+ const section = onlyWrapChild(body, "body");
660
+ const container = onlyWrapChild(section, `<${tag(section)} ${WRAP_ATTR}>`);
661
+ const div = clone.createElement("div");
662
+ const attrs = body.attributes;
663
+ for (let i = 0; i < attrs.length; i++) div.setAttribute(attrs[i].name, attrs[i].value);
664
+ while (container.firstChild) div.appendChild(container.firstChild);
665
+ const out = clone.createDocumentFragment();
666
+ const theme = clone.head?.querySelector('style[type="text/tailwindcss"]') ?? null;
667
+ if (theme) out.appendChild(theme);
668
+ const children = Array.from(body.childNodes);
669
+ for (const node of children) {
670
+ out.appendChild(node === section ? div : node);
671
+ }
672
+ return out;
673
+ }
674
+ function onlyWrapChild(parent, label) {
675
+ const kids = parent.children;
676
+ if (kids.length !== 1) {
677
+ throw new TypeError(
678
+ `unwrap(): ${label} \u4E0B\u5FC5\u987B\u6070\u6709\u4E00\u4E2A\u5408\u6210\u5C42\u5B50\u5143\u7D20\uFF0C\u5B9E\u9645\u6709 ${kids.length} \u4E2A \u2014\u2014 \u4E0D\u731C\u4E00\u4E2A\u51FA\u6765\u3002\u8FD9\u4EFD\u6587\u6863\u4E0D\u662F wrap() \u7684\u4EA7\u7269\uFF0C\u6216\u8005\u88AB\u6539\u6210\u4E86\u522B\u7684\u7ED3\u6784\u3002`
679
+ );
680
+ }
681
+ const only = kids[0];
682
+ if (!only.hasAttribute(WRAP_ATTR)) {
683
+ throw new TypeError(
684
+ `unwrap(): ${label} \u4E0B\u552F\u4E00\u7684\u5B50\u5143\u7D20\u6CA1\u6709 ${WRAP_ATTR} \u6807\u8BB0 \u2014\u2014 \u8FD9\u4EFD\u6587\u6863\u6CA1\u6709\u88AB wrap() \u5305\u88F9\u8FC7\u3002`
685
+ );
686
+ }
687
+ return only;
688
+ }
689
+ function describeNode(node) {
690
+ if (node.nodeType === 8) return "\u6CE8\u91CA\u8282\u70B9";
691
+ if (node.nodeType === 3) return `\u975E\u7A7A\u767D\u6587\u672C ${JSON.stringify(node.data.trim())}`;
692
+ return `nodeType ${node.nodeType}`;
693
+ }
694
+
567
695
  // src/validate/variants.ts
568
696
  var DEVICE = new Set(DEVICE_VARIANTS);
569
697
  var STATE = new Set(STATE_VARIANTS);
@@ -631,14 +759,25 @@ function isNativePaletteClass(className) {
631
759
 
632
760
  // src/validate/index.ts
633
761
  var EVENT_ATTR = /^on[a-z]/i;
634
- function validate(root, options) {
762
+ function validate(root, options = {}) {
635
763
  const issues = [];
636
- const isDocument = options.profile.root === "document" && isDoc(root);
637
- if (isDocument) checkFormatMeta(root, issues);
764
+ if (isDoc(root)) checkFormatMeta(root, issues);
638
765
  checkIds(root, issues);
639
766
  checkElements(root, options, issues);
767
+ if (options.singleSection) checkSingleSection(root, issues);
640
768
  return { ok: issues.length === 0, issues };
641
769
  }
770
+ function checkSingleSection(root, issues) {
771
+ const sections = root.querySelectorAll("section");
772
+ if (sections.length <= 1) return;
773
+ for (let i = 1; i < sections.length; i++) {
774
+ issues.push({
775
+ ptId: sections[i].getAttribute("data-pt-id") ?? void 0,
776
+ rule: "STRUCTURE",
777
+ params: { reason: "multiple-sections", count: sections.length }
778
+ });
779
+ }
780
+ }
642
781
  function isDoc(root) {
643
782
  return root.nodeType === 9;
644
783
  }
@@ -723,11 +862,27 @@ function checkClasses(el, ptId, options, issues) {
723
862
  issues.push({ ptId, rule: "NATIVE_PALETTE", params: { className: cls } });
724
863
  continue;
725
864
  }
865
+ if (options.allowVhUnits === false) {
866
+ const unit = viewportUnitIn(cls);
867
+ if (unit) {
868
+ issues.push({ ptId, rule: "UNIT_FORBIDDEN", params: { className: cls, unit } });
869
+ continue;
870
+ }
871
+ }
726
872
  if (options.canCompileClass && !options.canCompileClass(cls)) {
727
873
  issues.push({ ptId, rule: "CLASS_UNCOMPILABLE", params: { className: cls } });
728
874
  }
729
875
  }
730
876
  }
877
+ var ARBITRARY_VIEWPORT_UNIT = /\[[^\]]*?\d(?:\.\d+)?(l|s|d)?(vh|vw|vmin|vmax|vb|vi)\b/;
878
+ var SCREEN_SCALE = /(^|:)(min-|max-)?[hw]-(screen|[lsd]vh|[lsd]vw|dvh|dvw|svh|svw|lvh|lvw)$/;
879
+ function viewportUnitIn(cls) {
880
+ const arbitrary = ARBITRARY_VIEWPORT_UNIT.exec(cls);
881
+ if (arbitrary) return `${arbitrary[1] ?? ""}${arbitrary[2]}`;
882
+ const scale = SCREEN_SCALE.exec(cls);
883
+ if (scale) return scale[3];
884
+ return null;
885
+ }
731
886
  function checkPlaceholder(el, ptId, issues) {
732
887
  if (!el.hasAttribute("data-pt-placeholder")) return;
733
888
  const cls = el.getAttribute("class") ?? "";
@@ -762,6 +917,12 @@ var ERROR_CODES = [
762
917
  "INLINE_STYLE",
763
918
  /** 使用了 Tailwind 内置色板。它本身可编译,所以必须由独立规则拦。 */
764
919
  "NATIVE_PALETTE",
920
+ /**
921
+ * 用了视口相对单位(vh / dvh / h-screen…),而当前调用方关掉了它
922
+ * (`validate(doc, { allowVhUnits: false })`)。同 NATIVE_PALETTE:它可编译,
923
+ * 拒绝它是产品决定,所以「可编译」判定拦不住,必须独立一条。
924
+ */
925
+ "UNIT_FORBIDDEN",
765
926
  /** class 在当前 @theme 下编译不出 CSS。 */
766
927
  "CLASS_UNCOMPILABLE",
767
928
  /** 变体前缀不在允许集内,或组合顺序不是「设备在前、状态在后」。 */
@@ -795,13 +956,13 @@ function editorError(code, extra) {
795
956
 
796
957
  // src/validate/structure.ts
797
958
  var NOT_A_LAYER = /* @__PURE__ */ new Set(["html", "head", "body"]);
798
- function layerOf(el, profile) {
959
+ var LEAF_TYPE_SET = new Set(LEAF_TYPES);
960
+ function layerOf(el) {
799
961
  const name = tag(el);
800
962
  if (NOT_A_LAYER.has(name)) return null;
801
- const hasSectionLayer = profile.layers.includes("section");
802
- if (hasSectionLayer && name === "section") return "section";
963
+ if (name === "section") return "section";
803
964
  const ptType = el.getAttribute("data-pt-type");
804
- if (ptType && profile.leafTypes.includes(ptType)) return "leaf";
965
+ if (ptType && LEAF_TYPE_SET.has(ptType)) return "leaf";
805
966
  if (el.hasAttribute("data-pt-component")) return "leaf";
806
967
  const opaque = closestOpaque(el);
807
968
  if (opaque && opaque.host === el) return "leaf";
@@ -809,19 +970,19 @@ function layerOf(el, profile) {
809
970
  return null;
810
971
  }
811
972
  var MAX_CONTAINER_DEPTH = 2;
812
- function containerDepth(el, profile) {
973
+ function containerDepth(el) {
813
974
  let depth = 0;
814
975
  let cur = el;
815
976
  while (cur) {
816
- if (layerOf(cur, profile) === "container") depth += 1;
977
+ if (layerOf(cur) === "container" && !isWrapLayer(cur)) depth += 1;
817
978
  cur = cur.parentElement;
818
979
  }
819
980
  return depth;
820
981
  }
821
- function canContain(parent, childLayer, profile) {
982
+ function canContain(parent, childLayer) {
822
983
  const opaque = closestOpaque(parent);
823
984
  if (opaque) return "opaque-subtree";
824
- const parentLayer = layerOf(parent, profile);
985
+ const parentLayer = layerOf(parent);
825
986
  if (childLayer === "section") {
826
987
  const isBody = tag(parent) === "body";
827
988
  return isBody ? null : "section-not-body-child";
@@ -829,23 +990,21 @@ function canContain(parent, childLayer, profile) {
829
990
  if (childLayer === "container") {
830
991
  if (parentLayer === "section") return null;
831
992
  if (parentLayer === "container") {
832
- return containerDepth(parent, profile) + 1 > MAX_CONTAINER_DEPTH ? "container-too-deep" : null;
993
+ return containerDepth(parent) + 1 > MAX_CONTAINER_DEPTH ? "container-too-deep" : null;
833
994
  }
834
- if (!profile.layers.includes("section") && parentLayer === null) return null;
835
995
  return parentLayer === "leaf" ? "leaf-cannot-contain" : "unknown-layer";
836
996
  }
837
997
  if (parentLayer === "container") return null;
838
998
  if (parentLayer === "leaf") return "leaf-cannot-contain";
839
- if (!profile.layers.includes("section") && parentLayer === null) return null;
840
999
  return "unknown-layer";
841
1000
  }
842
- function deleteTarget(el, profile) {
843
- const layer = layerOf(el, profile);
1001
+ function deleteTarget(el) {
1002
+ const layer = layerOf(el);
844
1003
  if (layer !== "container") return el;
845
1004
  const parent = el.parentElement;
846
- if (!parent || layerOf(parent, profile) !== "section") return el;
1005
+ if (!parent || layerOf(parent) !== "section") return el;
847
1006
  const siblingContainers = Array.from(parent.children).filter(
848
- (c) => c !== el && layerOf(c, profile) === "container"
1007
+ (c) => c !== el && layerOf(c) === "container"
849
1008
  );
850
1009
  return siblingContainers.length === 0 ? parent : el;
851
1010
  }
@@ -931,33 +1090,33 @@ function requireCanonicalFragment(doc, html) {
931
1090
 
932
1091
  // src/ops/apply.ts
933
1092
  var RAW_TEXT = /* @__PURE__ */ new Set(["style", "script", "xmp", "iframe", "noembed", "noframes", "plaintext"]);
934
- function apply(doc, ops, options) {
1093
+ function apply(doc, ops) {
935
1094
  if (!Array.isArray(ops)) throw new TypeError("apply(): ops \u5FC5\u987B\u662F\u6570\u7EC4");
936
1095
  if (ops.length === 0) return { ok: true, inverse: [] };
937
1096
  const rehearsal = doc.cloneNode(true);
938
- const dry = run(rehearsal, ops, options);
1097
+ const dry = run(rehearsal, ops);
939
1098
  if (!dry.ok) return dry;
940
- return run(doc, ops, options);
1099
+ return run(doc, ops);
941
1100
  }
942
- function run(doc, ops, options) {
1101
+ function run(doc, ops) {
943
1102
  const inverse = [];
944
1103
  for (let i = 0; i < ops.length; i++) {
945
- const result = applyOne(doc, ops[i], options);
1104
+ const result = applyOne(doc, ops[i]);
946
1105
  if (!result.ok) return { ok: false, error: result.error, failedIndex: i };
947
1106
  inverse.unshift(result.inverse);
948
1107
  }
949
1108
  return { ok: true, inverse };
950
1109
  }
951
- function applyOne(doc, op, options) {
1110
+ function applyOne(doc, op) {
952
1111
  switch (op.op) {
953
1112
  case "set":
954
1113
  return applySet(doc, op);
955
1114
  case "insert":
956
- return applyInsert(doc, op, options);
1115
+ return applyInsert(doc, op);
957
1116
  case "delete":
958
- return applyDelete(doc, op, options);
1117
+ return applyDelete(doc, op);
959
1118
  case "move":
960
- return applyMove(doc, op, options);
1119
+ return applyMove(doc, op);
961
1120
  case "replace":
962
1121
  return applyReplace(doc, op);
963
1122
  default:
@@ -969,10 +1128,15 @@ function applyOne(doc, op, options) {
969
1128
  };
970
1129
  }
971
1130
  }
1131
+ function rejectWrapTarget(el, ptId) {
1132
+ return isWrapLayer(el) ? editorError("STRUCTURE", { ptId, params: { reason: "wrap-layer-immutable" } }) : null;
1133
+ }
972
1134
  function applySet(doc, op) {
973
1135
  const miss = requireIdHit(doc, op.id);
974
1136
  if (miss) return { ok: false, error: miss };
975
1137
  const el = findById(doc, op.id);
1138
+ const wrapped = rejectWrapTarget(el, op.id);
1139
+ if (wrapped) return { ok: false, error: wrapped };
976
1140
  const opaque = closestOpaque(el);
977
1141
  if (opaque && opaque.host !== el && opaque.mode !== "text") {
978
1142
  return { ok: false, error: editorError("STRUCTURE", { ptId: op.id, params: { reason: "opaque-subtree" } }) };
@@ -1065,7 +1229,7 @@ function setChildren(doc, el, text) {
1065
1229
  }
1066
1230
  el.appendChild(parseFragment(doc, text));
1067
1231
  }
1068
- function applyInsert(doc, op, options) {
1232
+ function applyInsert(doc, op) {
1069
1233
  const miss = requireIdHit(doc, op.parentId);
1070
1234
  if (miss) return { ok: false, error: miss };
1071
1235
  const parent = findById(doc, op.parentId);
@@ -1079,11 +1243,11 @@ function applyInsert(doc, op, options) {
1079
1243
  const idErr = requireFragmentIds(frag, collectDocIds(doc));
1080
1244
  if (idErr) return { ok: false, error: idErr };
1081
1245
  const root = fragmentElementRoots(frag)[0];
1082
- const childLayer = layerOf(root, options.profile);
1246
+ const childLayer = layerOf(root);
1083
1247
  if (!childLayer) {
1084
1248
  return { ok: false, error: editorError("STRUCTURE", { params: { reason: "unknown-layer" } }) };
1085
1249
  }
1086
- const rejection = canContain(parent, childLayer, options.profile);
1250
+ const rejection = canContain(parent, childLayer);
1087
1251
  if (rejection) {
1088
1252
  return { ok: false, error: editorError("STRUCTURE", { ptId: op.parentId, params: { reason: rejection } }) };
1089
1253
  }
@@ -1092,15 +1256,17 @@ function applyInsert(doc, op, options) {
1092
1256
  parent.insertBefore(frag, parent.childNodes[at] ?? null);
1093
1257
  return { ok: true, inverse: { op: "delete", id: newId } };
1094
1258
  }
1095
- function applyDelete(doc, op, options) {
1259
+ function applyDelete(doc, op) {
1096
1260
  const miss = requireIdHit(doc, op.id);
1097
1261
  if (miss) return { ok: false, error: miss };
1098
1262
  const el = findById(doc, op.id);
1263
+ const wrapped = rejectWrapTarget(el, op.id);
1264
+ if (wrapped) return { ok: false, error: wrapped };
1099
1265
  const opaque = closestOpaque(el);
1100
1266
  if (opaque && opaque.host !== el) {
1101
1267
  return { ok: false, error: editorError("STRUCTURE", { ptId: op.id, params: { reason: "opaque-subtree" } }) };
1102
1268
  }
1103
- const target = deleteTarget(el, options.profile);
1269
+ const target = deleteTarget(el);
1104
1270
  const parent = target.parentElement;
1105
1271
  if (!parent) {
1106
1272
  return { ok: false, error: editorError("STRUCTURE", { ptId: op.id, params: { reason: "no-parent" } }) };
@@ -1118,21 +1284,23 @@ function applyDelete(doc, op, options) {
1118
1284
  inverse: { op: "insert", parentId, index: 0, html, nodeIndex }
1119
1285
  };
1120
1286
  }
1121
- function applyMove(doc, op, options) {
1287
+ function applyMove(doc, op) {
1122
1288
  const missSelf = requireIdHit(doc, op.id);
1123
1289
  if (missSelf) return { ok: false, error: missSelf };
1124
1290
  const missParent = requireIdHit(doc, op.parentId);
1125
1291
  if (missParent) return { ok: false, error: missParent };
1126
1292
  const el = findById(doc, op.id);
1127
1293
  const parent = findById(doc, op.parentId);
1294
+ const wrapped = rejectWrapTarget(el, op.id);
1295
+ if (wrapped) return { ok: false, error: wrapped };
1128
1296
  if (el === parent || el.contains(parent)) {
1129
1297
  return { ok: false, error: editorError("STRUCTURE", { ptId: op.id, params: { reason: "move-into-self" } }) };
1130
1298
  }
1131
- const layer = layerOf(el, options.profile);
1299
+ const layer = layerOf(el);
1132
1300
  if (!layer) {
1133
1301
  return { ok: false, error: editorError("STRUCTURE", { ptId: op.id, params: { reason: "unknown-layer" } }) };
1134
1302
  }
1135
- const rejection = canContain(parent, layer, options.profile);
1303
+ const rejection = canContain(parent, layer);
1136
1304
  if (rejection) {
1137
1305
  return { ok: false, error: editorError("STRUCTURE", { ptId: op.parentId, params: { reason: rejection } }) };
1138
1306
  }
@@ -1153,6 +1321,8 @@ function applyReplace(doc, op) {
1153
1321
  const miss = requireIdHit(doc, op.id);
1154
1322
  if (miss) return { ok: false, error: miss };
1155
1323
  const el = findById(doc, op.id);
1324
+ const wrapped = rejectWrapTarget(el, op.id);
1325
+ if (wrapped) return { ok: false, error: wrapped };
1156
1326
  const canonical = requireCanonicalFragment(doc, op.html);
1157
1327
  if (canonical) return { ok: false, error: canonical };
1158
1328
  const frag = parseFragment(doc, op.html);
@@ -1407,6 +1577,8 @@ function createCore(options) {
1407
1577
  return {
1408
1578
  parse,
1409
1579
  parseFragment,
1580
+ wrap: createWrap(parse),
1581
+ unwrap,
1410
1582
  serialize,
1411
1583
  normalize,
1412
1584
  validate,
@@ -1415,12 +1587,11 @@ function createCore(options) {
1415
1587
  compile: compile_exports,
1416
1588
  collectClasses,
1417
1589
  rules,
1418
- KIND_PROFILES,
1419
1590
  VERSION,
1420
1591
  COMPILER_VERSION
1421
1592
  };
1422
1593
  }
1423
1594
 
1424
- export { COMPILER_VERSION, EMPTY_THEME, ERROR_CODES, KIND_PROFILES, PUBLISH_BLOCKING_RULES, VERSION, apply, canContain, checkVariants, collectClasses, compile_exports as compile, createCore, deleteTarget, editorError, fragmentElementRoots, guards_exports as guards, isErrorCode, isNativePaletteClass, isPublishBlocking, layerOf, normalize, normalizeClassValue, parseFragment, rules, serialize, themeFromSource, themeOf, themeTokens, validate };
1595
+ export { COMPILER_VERSION, EMPTY_THEME, ERROR_CODES, MAX_CONTAINER_DEPTH, PUBLISH_BLOCKING_RULES, VERSION, apply, canContain, checkVariants, collectClasses, compile_exports as compile, containerDepth, createCore, deleteTarget, editorError, fragmentElementRoots, guards_exports as guards, isErrorCode, isNativePaletteClass, isPublishBlocking, isWrapLayer, layerOf, normalize, normalizeClassValue, parseFragment, rules, serialize, themeFromSource, themeOf, themeTokens, unwrap, validate };
1425
1596
  //# sourceMappingURL=index.js.map
1426
1597
  //# sourceMappingURL=index.js.map