@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.d.ts CHANGED
@@ -83,6 +83,59 @@ interface NormalizeOptions {
83
83
  */
84
84
  declare function normalize(root: Document | DocumentFragment | Element, options?: NormalizeOptions): number;
85
85
 
86
+ /**
87
+ * 片段型来源的规范化包裹 / 剥离。
88
+ *
89
+ * **界线(这个文件存在的判据)**:core 可以知道「文档与片段的关系」,
90
+ * **不可以**知道「某个宿主的运行时要什么标记」。前者是格式问题 —— 单一三层树里
91
+ * leaf 必须落在 container 中,而片段顶层就是有裸 leaf,这条只与 v4 格式有关;
92
+ * 后者是宿主问题,归调用方在进出边界上翻译(弹窗的 Engage 契约、rem→px、`:host`)。
93
+ * 往这个文件里加任何一个具体产品的 DOM 约定,这条界线就没了。
94
+ *
95
+ * 为什么放 core 而不是全归调用方:往返无损是这条路上最容易出事的地方 ——
96
+ * 每存一次多一层或少一层,前几次完全看不出来,症状滞后于原因数天。放在 core
97
+ * 就落在已有的 golden 基建那一侧,有 19 份 fixture 与随包发布的复算脚本兜着。
98
+ *
99
+ * ## 两条必须记住的语义
100
+ *
101
+ * 1. **片段的根元素就是文档的 `<body>`**,不是被包在 body 里的一层。
102
+ * `ROOT_PT_ID = 'root'` 本来就是 body 的保留字面量,而片段顶层那个 div 恒带这个
103
+ * id —— 它们是同一个节点,所以「认领」而不是「再套一层」。不认领的坏法不止
104
+ * 「两个 root → ID_DUPLICATE」一种:`normalize.ts` 是
105
+ * `if (tag === 'body' && !used.has(ROOT_PT_ID))`,div 先占了 `root`,body 会掉进
106
+ * `nextId()` 拿到 `e1`,于是 **body 带着普通 id、`root` 长在一个 div 上,而
107
+ * validate 全绿** —— 这种更难查。
108
+ *
109
+ * 2. **`unwrap` 只保留 theme 块 + body 内容**,`<html lang>` / `<title>` / 其余 head
110
+ * 一律丢。片段型来源没有「文档头」这个概念,这是设计不是遗漏。同理**不存原始
111
+ * tag**(不加 `data-pt-wrap-tag`):存 tag 等于把宿主形态信息写回 core 文档,
112
+ * 正是要赶走的东西。`unwrap` 恒出 `<div>`,真遇到 `<section>` 根再放。
113
+ *
114
+ * ## 三道闸
115
+ *
116
+ * 一律**抛错**,不修复、不改名、不绕开。野生 / 历史形状由调用方的 adapter 在边界上
117
+ * 先规整 —— 那本来就是它的活。
118
+ *
119
+ * 1. 入参形状:可选 theme 块(若有必须排在最前)+ 单一根元素,且 `div` + `id=root`
120
+ * 2. 保留字面量占用:`root` 只许在根元素上、`theme` 只许在主题 style 上、
121
+ * 合成层的标记与两个保留 id 一次都不许出现
122
+ * 3. 剥离前的结构断言:body 恰有一个带标记的子元素,它里面也恰有一个带标记的子元素
123
+ */
124
+ /** 合成层由 `wrap` 造,也只由 `wrap` 造 —— 判定一律只看这个标记。 */
125
+ declare function isWrapLayer(el: Element): boolean;
126
+ /**
127
+ * 文档 → 片段,`wrap` 的逆。
128
+ *
129
+ * 纯函数(在克隆体上操作,入参文档一个字节都不动),**不吐字符串** ——
130
+ * 让它自己产字节等于开第二条产字节路径,而「`serialize` 是唯一的规范序列化出口」
131
+ * 正是这个包存在要守的东西。调用方 `serialize(unwrap(doc))`。
132
+ *
133
+ * 定位**只凭 `data-pt-wrap` 标记**,不用「取第一个 section」这类位置猜测:
134
+ * `unwrap` 必须可证明是 `wrap` 的逆,而标记是两者之间唯一显式的耦合;位置只是
135
+ * 今天恰好成立的巧合。
136
+ */
137
+ declare function unwrap(doc: Document): DocumentFragment;
138
+
86
139
  /**
87
140
  * 错误码与校验条目的形状。
88
141
  *
@@ -90,7 +143,7 @@ declare function normalize(root: Document | DocumentFragment | Element, options?
90
143
  * iam 发布拒绝按 `rule` 出后端文案,mastra 回给模型的结构化报错复用同一枚举。
91
144
  * 三处各一份措辞,但没有两份真源 —— 这也是 core 能作为公开包发布的前提之一。
92
145
  */
93
- declare const ERROR_CODES: readonly ["FORMAT_MISSING", "ID_DUPLICATE", "ID_CONFLICT", "ID_FORMAT", "ID_NOT_FOUND", "SCRIPT_FORBIDDEN", "INLINE_STYLE", "NATIVE_PALETTE", "CLASS_UNCOMPILABLE", "VARIANT_FORBIDDEN", "STRUCTURE", "MULTI_ROOT", "REPLACE_ID_CHANGED", "STALE_BASE_VERSION", "FRAGMENT_NOT_CANONICAL", "PLACEHOLDER_UNRESOLVED"];
146
+ declare const ERROR_CODES: readonly ["FORMAT_MISSING", "ID_DUPLICATE", "ID_CONFLICT", "ID_FORMAT", "ID_NOT_FOUND", "SCRIPT_FORBIDDEN", "INLINE_STYLE", "NATIVE_PALETTE", "UNIT_FORBIDDEN", "CLASS_UNCOMPILABLE", "VARIANT_FORBIDDEN", "STRUCTURE", "MULTI_ROOT", "REPLACE_ID_CHANGED", "STALE_BASE_VERSION", "FRAGMENT_NOT_CANONICAL", "PLACEHOLDER_UNRESOLVED"];
94
147
  type ErrorCode = (typeof ERROR_CODES)[number];
95
148
  declare function isErrorCode(value: unknown): value is ErrorCode;
96
149
  /** 校验条目。**不带 message** —— 文案归消费端。 */
@@ -117,169 +170,28 @@ interface EditorError {
117
170
  }
118
171
  declare function editorError(code: ErrorCode, extra?: Omit<EditorError, 'code'>): EditorError;
119
172
 
120
- /**
121
- * 规则**数据表**。
122
- *
123
- * 这里只有数据,没有一句提示词措辞 —— 措辞在 mastra 的
124
- * `page-designer/segments/v4.ts`,从这张表渲染。core 因此可以作为公开包发布,
125
- * 措辞微调也不需要 core 发版。
126
- *
127
- * 代价是语义变更要两仓配对改。mastra 侧靠**双向**覆盖测试兜住:
128
- * 正向:规则段必须提到这里的每一项(防 core 新增、mastra 没跟)
129
- * 反向:规则段提到的每一项都能在这里找到(防 core 删除、mastra 还在讲)
130
- * 只做正向的话,删一个开关后测试仍是绿的。
131
- */
132
- /** 设备变体。`md:` 是 PC 覆盖,`max-md:` 是手机独占(两者无缝无重叠)。 */
133
- declare const DEVICE_VARIANTS: readonly ["md", "max-md"];
134
- /**
135
- * 状态变体。
136
- *
137
- * 有意不含 `focus:` —— 统一用 `focus-visible:`。
138
- * 有意不含 `group-*` / `peer-*`:它们把样式绑到**别的元素**的状态上,
139
- * 面板表达不了、属性回显放不进(基线 / md / max-md)三槽。
140
- * 这两类 Tailwind 都能编译,拒绝它们是产品决定,不是能力限制。
141
- */
142
- declare const STATE_VARIANTS: readonly ["hover", "focus-visible", "active", "disabled"];
143
- type DeviceVariant = (typeof DEVICE_VARIANTS)[number];
144
- type StateVariant = (typeof STATE_VARIANTS)[number];
145
- /** 属性回显的三个槽位。 */
146
- declare const PROPERTY_SLOTS: readonly ["base", "md", "max-md"];
147
- type PropertySlot = (typeof PROPERTY_SLOTS)[number];
148
- /** 结构层级。弹窗没有 section 层。 */
149
- declare const LAYER_NAMES: readonly ["section", "container", "leaf"];
150
- type LayerName = (typeof LAYER_NAMES)[number];
151
- /** leaf 的类型。 */
152
- declare const LEAF_TYPES: readonly ["text", "media", "button", "shape"];
153
- type LeafType = (typeof LEAF_TYPES)[number];
154
- /** 不透明子树的两档。 */
155
- declare const OPAQUE_MODES: readonly ["strict", "text"];
156
- type OpaqueMode = (typeof OPAQUE_MODES)[number];
157
- /**
158
- * 整张表。mastra 的规则段渲染它,双向覆盖测试也比对它。
159
- * 加一项就要同步 mastra —— 这正是双向断言要暴露的事。
160
- */
161
- declare const rules: {
162
- readonly deviceVariants: readonly ["md", "max-md"];
163
- readonly stateVariants: readonly ["hover", "focus-visible", "active", "disabled"];
164
- readonly propertySlots: readonly ["base", "md", "max-md"];
165
- readonly layers: readonly ["section", "container", "leaf"];
166
- readonly leafTypes: readonly ["text", "media", "button", "shape"];
167
- readonly idPattern: "[a-z][a-z0-9_-]{1,31}";
168
- readonly themePtId: "theme";
169
- readonly rootPtId: "root";
170
- readonly formatMetaName: "lpx-format";
171
- readonly formatVersion: "4";
172
- readonly switches: readonly [{
173
- readonly key: "hide";
174
- readonly attr: "data-pt-hide";
175
- readonly values: readonly ["mobile", "pc"];
176
- readonly summary: "一端隐藏";
177
- }, {
178
- readonly key: "layout-mobile";
179
- readonly attr: "data-pt-layout-mobile";
180
- readonly values: readonly ["stack", "scroll"];
181
- readonly summary: "PC 轮播→手机纵向平铺 / PC 网格→手机横滑";
182
- }, {
183
- readonly key: "swap-image";
184
- readonly attr: null;
185
- readonly values: readonly [];
186
- readonly summary: "<picture> 双 source,(min-width:768px) 分界";
187
- }, {
188
- readonly key: "direction";
189
- readonly attr: null;
190
- readonly values: readonly [];
191
- readonly summary: "flex-col md:flex-row";
192
- }, {
193
- readonly key: "columns";
194
- readonly attr: null;
195
- readonly values: readonly [];
196
- readonly summary: "grid-cols-1 md:grid-cols-{n}";
197
- }, {
198
- readonly key: "placeholder";
199
- readonly attr: "data-pt-placeholder";
200
- readonly values: readonly [];
201
- readonly summary: "未落图占位;必带 aspect-*,src 为空";
202
- }];
203
- readonly crossDeviceConsistentProperties: readonly ["color", "font-weight", "border", "box-shadow", "font-family"];
204
- readonly opaqueModes: readonly ["strict", "text"];
205
- readonly opaqueTextEditableTags: readonly ["td", "th"];
206
- readonly inlineNoIdTags: readonly ["a", "abbr", "b", "bdi", "bdo", "br", "cite", "code", "data", "dfn", "em", "i", "kbd", "mark", "q", "rp", "rt", "ruby", "s", "samp", "small", "span", "strong", "sub", "sup", "time", "u", "var", "wbr"];
207
- readonly inlineStyleAllowedPrefix: "--pt-";
208
- readonly editOpKinds: readonly ["set", "insert", "delete", "move", "replace"];
209
- readonly arbitraryValueAllowedProperties: readonly ["width", "height", "aspect-ratio", "background-image", "max-width", "min-height"];
210
- };
211
- type Rules = typeof rules;
173
+ declare function isNativePaletteClass(className: string): boolean;
212
174
 
213
175
  /**
214
- * 两种文档类型的能力档。宿主把其中一档作为 `capabilities` 传给编辑器,
215
- * mastra 也读同一份来判断结构规则。
216
- */
217
- /** 组件运行时由谁提供。 */
218
- type ComponentRuntime =
219
- /** 渲染器自带脚本(落地页)。 */
220
- 'self'
221
- /**
222
- * 只出声明式标记、零脚本,行为归 Engage SDK(弹窗的表单与倒计时)。
223
- * core 给弹窗表单出脚本会和 SDK 抢同一张表单。
176
+ * 校验开关。**扁平的可选项,不是「宿主档位」** —— core 不区分落地页与弹窗,
177
+ * 它只知道「有一条可选规则叫禁视口单位」,不知道谁会用它。
178
+ *
179
+ * 全部默认**最宽松**:不传任何开关时只跑格式本身的硬规则。
224
180
  */
225
- | 'engage-sdk';
226
- interface KindProfile {
227
- /** 文档形态:完整文档(落地页)还是片段(弹窗)。 */
228
- root: 'document' | 'fragment';
229
- /** 结构层级。弹窗没有 section 层。 */
230
- layers: readonly LayerName[];
231
- /** 编译目标:完整文档 CSS,还是 Shadow DOM 内的 px 化 CSS。 */
232
- compile: 'document' | 'shadow-px';
233
- leafTypes: readonly LeafType[];
234
- /** 允许的内置组件 → 其运行时策略。 */
235
- components: Readonly<Record<string, ComponentRuntime>>;
236
- units: {
237
- vh: boolean;
238
- };
239
- customCode: boolean;
240
- }
241
- declare const KIND_PROFILES: {
242
- readonly page: {
243
- readonly root: "document";
244
- readonly layers: readonly ["section", "container", "leaf"];
245
- readonly compile: "document";
246
- readonly leafTypes: readonly ["text", "media", "button", "shape"];
247
- readonly components: {
248
- readonly carousel: "self";
249
- readonly faq: "self";
250
- readonly tabs: "self";
251
- readonly 'sticky-cta': "self";
252
- readonly form: "self";
253
- };
254
- readonly units: {
255
- readonly vh: true;
256
- };
257
- readonly customCode: true;
258
- };
259
- readonly popup: {
260
- readonly root: "fragment";
261
- readonly layers: readonly ["container", "leaf"];
262
- readonly compile: "shadow-px";
263
- readonly leafTypes: readonly ["text", "media", "button", "shape"];
264
- readonly components: {
265
- readonly form: "engage-sdk";
266
- readonly countdown: "engage-sdk";
267
- readonly carousel: "self";
268
- readonly faq: "self";
269
- readonly tabs: "self";
270
- };
271
- readonly units: {
272
- readonly vh: false;
273
- };
274
- readonly customCode: false;
275
- };
276
- };
277
- type KindName = keyof typeof KIND_PROFILES;
278
-
279
- declare function isNativePaletteClass(className: string): boolean;
280
-
281
181
  interface ValidateOptions {
282
- profile: KindProfile;
182
+ /**
183
+ * 允许视口相对单位(`vh` / `vw` / `dvh`… 以及 `h-screen` 这类等价刻度)。默认允许。
184
+ *
185
+ * 传 `false` 的场合:文档被装在一个比视口小的框里(片段型来源的宿主信封)。
186
+ * 那里的视口单位按**整个浏览器视口**算,不是框自身 —— 数值看着对、显示全错。
187
+ */
188
+ allowVhUnits?: boolean;
189
+ /**
190
+ * 限定整份文档只有一个 `section`。默认不限。
191
+ *
192
+ * UI 挡得住人,挡不住 AI 和别的调用路径,所以这条兜底在校验侧。
193
+ */
194
+ singleSection?: boolean;
283
195
  /**
284
196
  * 判定单个 class 在当前 @theme 下是否能编译出 CSS。
285
197
  * 由调用方注入(编译器在另一个模块,validate 不直接依赖它)。
@@ -291,7 +203,17 @@ interface ValidateResult {
291
203
  ok: boolean;
292
204
  issues: Issue[];
293
205
  }
294
- declare function validate(root: Document | DocumentFragment | Element, options: ValidateOptions): ValidateResult;
206
+ /**
207
+ * 校验一份文档,或一段子树。
208
+ *
209
+ * **入参语义有区分,这条是硬约定**:只有 `Document` 入参才参与文档级规则(今天是
210
+ * 格式标记)的判定;`DocumentFragment` / `Element` 入参一律按**子树**处理,文档级
211
+ * 规则不参与 —— 所以拿一段尚未包裹的片段来校验**不会**报 `FORMAT_MISSING`。
212
+ *
213
+ * 保留子树入口是为了「在 apply 之前单独校验一段 AI 片段」这类用法;收窄成只吃
214
+ * Document 的话,那种场合只能 apply 到克隆体再校验。
215
+ */
216
+ declare function validate(root: Document | DocumentFragment | Element, options?: ValidateOptions): ValidateResult;
295
217
 
296
218
  /**
297
219
  * EditOp:人的面板操作、拖拽、富文本、AI 指令,最终都变成这五种操作之一,
@@ -351,9 +273,6 @@ interface Transaction {
351
273
  source: 'user' | 'ai';
352
274
  }
353
275
 
354
- interface ApplyOptions {
355
- profile: KindProfile;
356
- }
357
276
  type ApplyResult = {
358
277
  ok: true;
359
278
  inverse: EditOp[];
@@ -373,7 +292,7 @@ type ApplyResult = {
373
292
  * 而失败时恰恰是最容易触发边角情况的时刻 —— 把原子性压在最脆弱的那条路径上
374
293
  * 不是好交易。克隆一次的代价(原生 cloneNode)远小于一次编译。
375
294
  */
376
- declare function apply(doc: Document, ops: EditOp[], options: ApplyOptions): ApplyResult;
295
+ declare function apply(doc: Document, ops: EditOp[]): ApplyResult;
377
296
 
378
297
  /** 操作引用的 id 必须在文档里。用得最多的一条。 */
379
298
  declare function requireIdHit(doc: Document | DocumentFragment, id: string): EditorError | null;
@@ -517,10 +436,109 @@ interface CoreOptions {
517
436
  DOMParser: DOMParserCtor;
518
437
  }
519
438
 
520
- declare function layerOf(el: Element, profile: KindProfile): LayerName | null;
439
+ /**
440
+ * 规则**数据表**。
441
+ *
442
+ * 这里只有数据,没有一句提示词措辞 —— 措辞在 mastra 的
443
+ * `page-designer/segments/v4.ts`,从这张表渲染。core 因此可以作为公开包发布,
444
+ * 措辞微调也不需要 core 发版。
445
+ *
446
+ * 代价是语义变更要两仓配对改。mastra 侧靠**双向**覆盖测试兜住:
447
+ * 正向:规则段必须提到这里的每一项(防 core 新增、mastra 没跟)
448
+ * 反向:规则段提到的每一项都能在这里找到(防 core 删除、mastra 还在讲)
449
+ * 只做正向的话,删一个开关后测试仍是绿的。
450
+ */
451
+ /** 设备变体。`md:` 是 PC 覆盖,`max-md:` 是手机独占(两者无缝无重叠)。 */
452
+ declare const DEVICE_VARIANTS: readonly ["md", "max-md"];
453
+ /**
454
+ * 状态变体。
455
+ *
456
+ * 有意不含 `focus:` —— 统一用 `focus-visible:`。
457
+ * 有意不含 `group-*` / `peer-*`:它们把样式绑到**别的元素**的状态上,
458
+ * 面板表达不了、属性回显放不进(基线 / md / max-md)三槽。
459
+ * 这两类 Tailwind 都能编译,拒绝它们是产品决定,不是能力限制。
460
+ */
461
+ declare const STATE_VARIANTS: readonly ["hover", "focus-visible", "active", "disabled"];
462
+ type DeviceVariant = (typeof DEVICE_VARIANTS)[number];
463
+ type StateVariant = (typeof STATE_VARIANTS)[number];
464
+ /** 属性回显的三个槽位。 */
465
+ declare const PROPERTY_SLOTS: readonly ["base", "md", "max-md"];
466
+ type PropertySlot = (typeof PROPERTY_SLOTS)[number];
467
+ /** 结构层级。**唯一**一套,不按宿主分档。 */
468
+ declare const LAYER_NAMES: readonly ["section", "container", "leaf"];
469
+ type LayerName = (typeof LAYER_NAMES)[number];
470
+ /** leaf 的类型。 */
471
+ declare const LEAF_TYPES: readonly ["text", "media", "button", "shape"];
472
+ type LeafType = (typeof LEAF_TYPES)[number];
473
+ /** 不透明子树的两档。 */
474
+ declare const OPAQUE_MODES: readonly ["strict", "text"];
475
+ type OpaqueMode = (typeof OPAQUE_MODES)[number];
476
+ /**
477
+ * 整张表。mastra 的规则段渲染它,双向覆盖测试也比对它。
478
+ * 加一项就要同步 mastra —— 这正是双向断言要暴露的事。
479
+ */
480
+ declare const rules: {
481
+ readonly deviceVariants: readonly ["md", "max-md"];
482
+ readonly stateVariants: readonly ["hover", "focus-visible", "active", "disabled"];
483
+ readonly propertySlots: readonly ["base", "md", "max-md"];
484
+ readonly layers: readonly ["section", "container", "leaf"];
485
+ readonly leafTypes: readonly ["text", "media", "button", "shape"];
486
+ readonly idPattern: "[a-z][a-z0-9_-]{1,31}";
487
+ readonly themePtId: "theme";
488
+ readonly rootPtId: "root";
489
+ readonly formatMetaName: "lpx-format";
490
+ readonly formatVersion: "4";
491
+ readonly wrapAttr: "data-pt-wrap";
492
+ readonly wrapSectionPtId: "ptwrap-section";
493
+ readonly wrapContainerPtId: "ptwrap-container";
494
+ readonly switches: readonly [{
495
+ readonly key: "hide";
496
+ readonly attr: "data-pt-hide";
497
+ readonly values: readonly ["mobile", "pc"];
498
+ readonly summary: "一端隐藏";
499
+ }, {
500
+ readonly key: "layout-mobile";
501
+ readonly attr: "data-pt-layout-mobile";
502
+ readonly values: readonly ["stack", "scroll"];
503
+ readonly summary: "PC 轮播→手机纵向平铺 / PC 网格→手机横滑";
504
+ }, {
505
+ readonly key: "swap-image";
506
+ readonly attr: null;
507
+ readonly values: readonly [];
508
+ readonly summary: "<picture> 双 source,(min-width:768px) 分界";
509
+ }, {
510
+ readonly key: "direction";
511
+ readonly attr: null;
512
+ readonly values: readonly [];
513
+ readonly summary: "flex-col md:flex-row";
514
+ }, {
515
+ readonly key: "columns";
516
+ readonly attr: null;
517
+ readonly values: readonly [];
518
+ readonly summary: "grid-cols-1 md:grid-cols-{n}";
519
+ }, {
520
+ readonly key: "placeholder";
521
+ readonly attr: "data-pt-placeholder";
522
+ readonly values: readonly [];
523
+ readonly summary: "未落图占位;必带 aspect-*,src 为空";
524
+ }];
525
+ readonly crossDeviceConsistentProperties: readonly ["color", "font-weight", "border", "box-shadow", "font-family"];
526
+ readonly opaqueModes: readonly ["strict", "text"];
527
+ readonly opaqueTextEditableTags: readonly ["td", "th"];
528
+ readonly inlineNoIdTags: readonly ["a", "abbr", "b", "bdi", "bdo", "br", "cite", "code", "data", "dfn", "em", "i", "kbd", "mark", "q", "rp", "rt", "ruby", "s", "samp", "small", "span", "strong", "sub", "sup", "time", "u", "var", "wbr"];
529
+ readonly inlineStyleAllowedPrefix: "--pt-";
530
+ readonly editOpKinds: readonly ["set", "insert", "delete", "move", "replace"];
531
+ readonly arbitraryValueAllowedProperties: readonly ["width", "height", "aspect-ratio", "background-image", "max-width", "min-height"];
532
+ };
533
+ type Rules = typeof rules;
534
+
535
+ declare function layerOf(el: Element): LayerName | null;
536
+ /** container 允许再嵌一层,不能更深。 */
537
+ declare const MAX_CONTAINER_DEPTH = 2;
538
+ declare function containerDepth(el: Element): number;
521
539
  type StructureRejection = 'section-not-body-child' | 'container-too-deep' | 'leaf-cannot-contain' | 'opaque-subtree' | 'unknown-layer';
522
540
  /** 某个父节点能否接纳某一层的子节点。 */
523
- declare function canContain(parent: Element, childLayer: LayerName, profile: KindProfile): StructureRejection | null;
541
+ declare function canContain(parent: Element, childLayer: LayerName): StructureRejection | null;
524
542
  /**
525
543
  * 删除的级联语义。
526
544
  *
@@ -528,8 +546,11 @@ declare function canContain(parent: Element, childLayer: LayerName, profile: Kin
528
546
  * 删掉 section 的最后一个 container —— 连 section 一起删(空区块没有意义)。
529
547
  *
530
548
  * 返回**真正要从树上摘掉的那个节点**。
549
+ *
550
+ * ⚠️ 这条永远吃不到合成 section:`wrap` 恒合成 container + section 两层,用户容器
551
+ * 的父永远是那个合成 container 而不是 section。见 wrap.ts 里同一条不变量。
531
552
  */
532
- declare function deleteTarget(el: Element, profile: KindProfile): Element;
553
+ declare function deleteTarget(el: Element): Element;
533
554
 
534
555
  interface VariantCheck {
535
556
  ok: boolean;
@@ -564,7 +585,7 @@ declare function checkVariants(className: string): VariantCheck;
564
585
  * 护栏:export golden 断言「输出变了而 COMPILER_VERSION 没变就红」。
565
586
  * 递增它是一次显式动作,不要顺手跟着包版本一起改。
566
587
  */
567
- declare const VERSION = "1.0.0-alpha.2";
588
+ declare const VERSION = "1.0.0-alpha.3";
568
589
  declare const COMPILER_VERSION = "1";
569
590
 
570
591
  /**
@@ -577,6 +598,8 @@ declare const COMPILER_VERSION = "1";
577
598
  declare function createCore(options: CoreOptions): {
578
599
  parse: (html: string) => Document;
579
600
  parseFragment: typeof parseFragment;
601
+ wrap: (fragmentHtml: string) => Document;
602
+ unwrap: typeof unwrap;
580
603
  serialize: typeof serialize;
581
604
  normalize: typeof normalize;
582
605
  validate: typeof validate;
@@ -595,6 +618,9 @@ declare function createCore(options: CoreOptions): {
595
618
  readonly rootPtId: "root";
596
619
  readonly formatMetaName: "lpx-format";
597
620
  readonly formatVersion: "4";
621
+ readonly wrapAttr: "data-pt-wrap";
622
+ readonly wrapSectionPtId: "ptwrap-section";
623
+ readonly wrapContainerPtId: "ptwrap-container";
598
624
  readonly switches: readonly [{
599
625
  readonly key: "hide";
600
626
  readonly attr: "data-pt-hide";
@@ -634,45 +660,9 @@ declare function createCore(options: CoreOptions): {
634
660
  readonly editOpKinds: readonly ["set", "insert", "delete", "move", "replace"];
635
661
  readonly arbitraryValueAllowedProperties: readonly ["width", "height", "aspect-ratio", "background-image", "max-width", "min-height"];
636
662
  };
637
- KIND_PROFILES: {
638
- readonly page: {
639
- readonly root: "document";
640
- readonly layers: readonly ["section", "container", "leaf"];
641
- readonly compile: "document";
642
- readonly leafTypes: readonly ["text", "media", "button", "shape"];
643
- readonly components: {
644
- readonly carousel: "self";
645
- readonly faq: "self";
646
- readonly tabs: "self";
647
- readonly 'sticky-cta': "self";
648
- readonly form: "self";
649
- };
650
- readonly units: {
651
- readonly vh: true;
652
- };
653
- readonly customCode: true;
654
- };
655
- readonly popup: {
656
- readonly root: "fragment";
657
- readonly layers: readonly ["container", "leaf"];
658
- readonly compile: "shadow-px";
659
- readonly leafTypes: readonly ["text", "media", "button", "shape"];
660
- readonly components: {
661
- readonly form: "engage-sdk";
662
- readonly countdown: "engage-sdk";
663
- readonly carousel: "self";
664
- readonly faq: "self";
665
- readonly tabs: "self";
666
- };
667
- readonly units: {
668
- readonly vh: false;
669
- };
670
- readonly customCode: false;
671
- };
672
- };
673
663
  VERSION: string;
674
664
  COMPILER_VERSION: string;
675
665
  };
676
666
  type Core = ReturnType<typeof createCore>;
677
667
 
678
- export { type ApplyOptions, type ApplyResult, COMPILER_VERSION, type ComponentRuntime, type Core, type CoreOptions, type DOMParserCtor, type DOMParserLike, type DeleteOp, type DeviceVariant, EMPTY_THEME, ERROR_CODES, type EditOp, type EditorError, type ErrorCode, type InsertOp, type Issue, KIND_PROFILES, type KindName, type KindProfile, type LayerName, type LeafType, type MoveOp, type NormalizeOptions, type OpaqueMode, PUBLISH_BLOCKING_RULES, type PropertySlot, type ReplaceOp, type Rules, type SetOp, type StateVariant, type Theme, type ThemeTokens, type Transaction, VERSION, type ValidateOptions, type ValidateResult$1 as ValidateResult, apply, canContain, checkVariants, collectClasses, compile, createCore, deleteTarget, editorError, fragmentElementRoots, guards, isErrorCode, isNativePaletteClass, isPublishBlocking, layerOf, normalize, normalizeClassValue, parseFragment, rules, serialize, themeFromSource, themeOf, themeTokens, validate };
668
+ export { type ApplyResult, COMPILER_VERSION, type Core, type CoreOptions, type DOMParserCtor, type DOMParserLike, type DeleteOp, type DeviceVariant, EMPTY_THEME, ERROR_CODES, type EditOp, type EditorError, type ErrorCode, type InsertOp, type Issue, type LayerName, type LeafType, MAX_CONTAINER_DEPTH, type MoveOp, type NormalizeOptions, type OpaqueMode, PUBLISH_BLOCKING_RULES, type PropertySlot, type ReplaceOp, type Rules, type SetOp, type StateVariant, type StructureRejection, type Theme, type ThemeTokens, type Transaction, VERSION, type ValidateOptions, type ValidateResult$1 as ValidateResult, apply, canContain, checkVariants, collectClasses, compile, containerDepth, createCore, deleteTarget, editorError, fragmentElementRoots, guards, isErrorCode, isNativePaletteClass, isPublishBlocking, isWrapLayer, layerOf, normalize, normalizeClassValue, parseFragment, rules, serialize, themeFromSource, themeOf, themeTokens, unwrap, validate };