@ptengine/inline-editor 0.0.0-stage → 0.1.1
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/CHANGELOG.md +42 -0
- package/README.md +286 -2
- package/dist/InlineEditor.d.ts +349 -0
- package/dist/InlineEditor.js +886 -0
- package/dist/PagePreview.d.ts +83 -0
- package/dist/PagePreview.js +111 -0
- package/dist/assets/AssetsPanel.d.ts +19 -0
- package/dist/assets/AssetsPanel.js +23 -0
- package/dist/assets/componentLibrary.d.ts +23 -0
- package/dist/assets/componentLibrary.js +12 -0
- package/dist/canvas-ui/index.d.ts +17 -0
- package/dist/canvas-ui/index.js +7 -0
- package/dist/canvas-ui/scope.d.ts +13 -0
- package/dist/canvas-ui/scope.js +1 -0
- package/dist/canvas-ui/selection/classNames.d.ts +30 -0
- package/dist/canvas-ui/selection/classNames.js +15 -0
- package/dist/canvas-ui/selection/tokens.css +204 -0
- package/dist/canvas-ui/tree/TreePanel.d.ts +47 -0
- package/dist/canvas-ui/tree/TreePanel.js +132 -0
- package/dist/canvas-ui/tree/classNames.d.ts +21 -0
- package/dist/canvas-ui/tree/classNames.js +8 -0
- package/dist/canvas-ui/tree/order.d.ts +38 -0
- package/dist/canvas-ui/tree/order.js +38 -0
- package/dist/canvas-ui/tree/tree.css +131 -0
- package/dist/chrome/EditorChrome.d.ts +83 -0
- package/dist/chrome/EditorChrome.js +10 -0
- package/dist/chrome/VersionMenu.d.ts +26 -0
- package/dist/chrome/VersionMenu.js +86 -0
- package/dist/chrome/topbarPrimitives.d.ts +69 -0
- package/dist/chrome/topbarPrimitives.js +39 -0
- package/dist/chrome/useDismissOnOutside.d.ts +23 -0
- package/dist/chrome/useDismissOnOutside.js +27 -0
- package/dist/dialogs/ClickActionDialog.d.ts +24 -0
- package/dist/dialogs/ClickActionDialog.js +35 -0
- package/dist/dialogs/HtmlEditDialog.d.ts +23 -0
- package/dist/dialogs/HtmlEditDialog.js +23 -0
- package/dist/dialogs/ImageEditDialog.d.ts +30 -0
- package/dist/dialogs/ImageEditDialog.js +57 -0
- package/dist/dialogs/ImageSettingDialog.d.ts +16 -0
- package/dist/dialogs/ImageSettingDialog.js +17 -0
- package/dist/dialogs/InsertElementDialog.d.ts +23 -0
- package/dist/dialogs/InsertElementDialog.js +28 -0
- package/dist/dialogs/ReplaceVideoDialog.d.ts +18 -0
- package/dist/dialogs/ReplaceVideoDialog.js +16 -0
- package/dist/dialogs/actionTypes.d.ts +53 -0
- package/dist/dialogs/actionTypes.js +74 -0
- package/dist/dialogs/htmlValidation.d.ts +24 -0
- package/dist/dialogs/htmlValidation.js +37 -0
- package/dist/dialogs/imageEdit.d.ts +49 -0
- package/dist/dialogs/imageEdit.js +30 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.js +53 -0
- package/dist/kernel/CanvasContextBar.d.ts +23 -0
- package/dist/kernel/CanvasContextBar.js +12 -0
- package/dist/kernel/CanvasFrame.d.ts +56 -0
- package/dist/kernel/CanvasFrame.js +53 -0
- package/dist/kernel/ai/aiInlineApply.d.ts +330 -0
- package/dist/kernel/ai/aiInlineApply.js +477 -0
- package/dist/kernel/ai/imageSource.d.ts +24 -0
- package/dist/kernel/ai/imageSource.js +19 -0
- package/dist/kernel/ai/insertHtmlGate.d.ts +71 -0
- package/dist/kernel/ai/insertHtmlGate.js +123 -0
- package/dist/kernel/ai/postApplyCheck.d.ts +56 -0
- package/dist/kernel/ai/postApplyCheck.js +74 -0
- package/dist/kernel/ai/replaceHtmlGate.d.ts +71 -0
- package/dist/kernel/ai/replaceHtmlGate.js +147 -0
- package/dist/kernel/blocks/BlockOverlay.d.ts +16 -0
- package/dist/kernel/blocks/BlockOverlay.js +66 -0
- package/dist/kernel/blocks/annotateAndTile.d.ts +106 -0
- package/dist/kernel/blocks/annotateAndTile.js +122 -0
- package/dist/kernel/blocks/resolveBlocks.d.ts +153 -0
- package/dist/kernel/blocks/resolveBlocks.js +233 -0
- package/dist/kernel/canvasCapabilities.d.ts +31 -0
- package/dist/kernel/canvasCapabilities.js +39 -0
- package/dist/kernel/canvasCommands.d.ts +126 -0
- package/dist/kernel/canvasCommands.js +146 -0
- package/dist/kernel/canvasErrors.d.ts +1 -0
- package/dist/kernel/canvasErrors.js +14 -0
- package/dist/kernel/captureGeometry.d.ts +35 -0
- package/dist/kernel/captureGeometry.js +25 -0
- package/dist/kernel/captureOrchestration.d.ts +48 -0
- package/dist/kernel/captureOrchestration.js +43 -0
- package/dist/kernel/captureSlices.d.ts +36 -0
- package/dist/kernel/captureSlices.js +20 -0
- package/dist/kernel/changelist/ChangeListPanel.d.ts +13 -0
- package/dist/kernel/changelist/ChangeListPanel.js +47 -0
- package/dist/kernel/changelist/ChangeListPopover.d.ts +20 -0
- package/dist/kernel/changelist/ChangeListPopover.js +10 -0
- package/dist/kernel/changelist/builders.d.ts +89 -0
- package/dist/kernel/changelist/builders.js +81 -0
- package/dist/kernel/changelist/changeSummary.d.ts +19 -0
- package/dist/kernel/changelist/changeSummary.js +85 -0
- package/dist/kernel/changelist/clipboard.d.ts +16 -0
- package/dist/kernel/changelist/clipboard.js +4 -0
- package/dist/kernel/changelist/exportForSave.d.ts +30 -0
- package/dist/kernel/changelist/exportForSave.js +11 -0
- package/dist/kernel/changelist/mergeForSave.d.ts +79 -0
- package/dist/kernel/changelist/mergeForSave.js +40 -0
- package/dist/kernel/changelist/moveObserverSafety.d.ts +70 -0
- package/dist/kernel/changelist/moveObserverSafety.js +39 -0
- package/dist/kernel/changelist/overrides.d.ts +22 -0
- package/dist/kernel/changelist/overrides.js +63 -0
- package/dist/kernel/changelist/useChangeList.d.ts +200 -0
- package/dist/kernel/changelist/useChangeList.js +282 -0
- package/dist/kernel/config.d.ts +29 -0
- package/dist/kernel/config.js +10 -0
- package/dist/kernel/dataUrlToBlob.d.ts +8 -0
- package/dist/kernel/dataUrlToBlob.js +17 -0
- package/dist/kernel/linkHref.d.ts +25 -0
- package/dist/kernel/linkHref.js +16 -0
- package/dist/kernel/mobileFit.d.ts +46 -0
- package/dist/kernel/mobileFit.js +44 -0
- package/dist/kernel/moveState.d.ts +35 -0
- package/dist/kernel/moveState.js +14 -0
- package/dist/kernel/selection/SelectionOverlay.d.ts +10 -0
- package/dist/kernel/selection/SelectionOverlay.js +25 -0
- package/dist/kernel/selection/SelectionToolbar.d.ts +30 -0
- package/dist/kernel/selection/SelectionToolbar.js +82 -0
- package/dist/kernel/selection/SelectorPathBar.d.ts +27 -0
- package/dist/kernel/selection/SelectorPathBar.js +55 -0
- package/dist/kernel/selection/buildDescendantShelf.d.ts +40 -0
- package/dist/kernel/selection/buildDescendantShelf.js +50 -0
- package/dist/kernel/selection/buildRootShelf.d.ts +26 -0
- package/dist/kernel/selection/buildRootShelf.js +149 -0
- package/dist/kernel/selection/elementAiContext.d.ts +324 -0
- package/dist/kernel/selection/elementAiContext.js +122 -0
- package/dist/kernel/selection/elementGeometryForAi.d.ts +9 -0
- package/dist/kernel/selection/elementGeometryForAi.js +15 -0
- package/dist/kernel/selection/geometry.d.ts +55 -0
- package/dist/kernel/selection/geometry.js +18 -0
- package/dist/kernel/selection/resolveAnchors.d.ts +116 -0
- package/dist/kernel/selection/resolveAnchors.js +173 -0
- package/dist/kernel/selection/shelfRow.d.ts +33 -0
- package/dist/kernel/selection/shelfRow.js +21 -0
- package/dist/kernel/selection/tagLabels.d.ts +9 -0
- package/dist/kernel/selection/tagLabels.js +46 -0
- package/dist/kernel/selection/toolbarButtons.d.ts +60 -0
- package/dist/kernel/selection/toolbarButtons.js +105 -0
- package/dist/kernel/selection/useAiSelectionContext.d.ts +26 -0
- package/dist/kernel/selection/useAiSelectionContext.js +26 -0
- package/dist/kernel/selection/useCanvasGeometry.d.ts +32 -0
- package/dist/kernel/selection/useCanvasGeometry.js +47 -0
- package/dist/kernel/selection/useSelectionRestore.d.ts +18 -0
- package/dist/kernel/selection/useSelectionRestore.js +25 -0
- package/dist/kernel/shrinkImageForUpload.d.ts +45 -0
- package/dist/kernel/shrinkImageForUpload.js +61 -0
- package/dist/kernel/useCanvasBridge.d.ts +36 -0
- package/dist/kernel/useCanvasBridge.js +41 -0
- package/dist/kernel/useCanvasGate.d.ts +22 -0
- package/dist/kernel/useCanvasGate.js +35 -0
- package/dist/kernel/useCanvasSession.d.ts +44 -0
- package/dist/kernel/useCanvasSession.js +182 -0
- package/dist/kernel/useCanvasStream.d.ts +39 -0
- package/dist/kernel/useCanvasStream.js +45 -0
- package/dist/kernel/useMobileFit.d.ts +40 -0
- package/dist/kernel/useMobileFit.js +139 -0
- package/dist/locales.d.ts +1094 -0
- package/dist/locales.js +545 -0
- package/dist/panels/StylePanel.d.ts +24 -0
- package/dist/panels/StylePanel.js +40 -0
- package/dist/panels/styleFields.d.ts +39 -0
- package/dist/panels/styleFields.js +91 -0
- package/dist/tree/LayersPanel.d.ts +30 -0
- package/dist/tree/LayersPanel.js +15 -0
- package/dist/tree/domTreeAdapter.d.ts +63 -0
- package/dist/tree/domTreeAdapter.js +90 -0
- package/dist/useInlineEditor.d.ts +161 -0
- package/dist/useInlineEditor.js +346 -0
- package/package.json +58 -3
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import type { CanvasDevice } from '@ptengine/inline-core/protocol';
|
|
2
|
+
import { type ChromeVariant } from './chrome/EditorChrome.js';
|
|
3
|
+
import type { PageModelBlock } from './kernel/blocks/resolveBlocks.js';
|
|
4
|
+
import type { AdaptDomTreeOptions } from './tree/domTreeAdapter.js';
|
|
5
|
+
import { type AnchorShot, type ElementAiContext } from './kernel/selection/elementAiContext.js';
|
|
6
|
+
import { type InlinePlanAnchor } from './kernel/selection/resolveAnchors.js';
|
|
7
|
+
import { type AiApplyOutcome, type AiScopeGrant, type AiWireChange } from './kernel/ai/aiInlineApply.js';
|
|
8
|
+
import { type LibraryComponent } from './assets/componentLibrary.js';
|
|
9
|
+
import { type UseInlineEditorResult } from './useInlineEditor.js';
|
|
10
|
+
import type { ChangeRecord, HydrateOutcome } from './kernel/changelist/useChangeList.js';
|
|
11
|
+
import type { InlineChange } from '@ptengine/inline-core/change-format';
|
|
12
|
+
/**
|
|
13
|
+
* 成品编辑器 —— 外壳 + 画布 + 选中层 + 编辑入口的**默认拼装**。
|
|
14
|
+
*
|
|
15
|
+
* 需要不一样的外壳时**不要改这里加开关**,直接用 `useInlineEditor()` 自己拼
|
|
16
|
+
* (见 README 的两层 API)。这个组件存在的意义是「大多数入口不用从零拼」,
|
|
17
|
+
* 不是「所有入口都必须用它」。
|
|
18
|
+
*
|
|
19
|
+
* 目标视口宽度按设备固定:客户页按 1440 设计,画布用 `zoom` 缩放去适应面板宽度,
|
|
20
|
+
* 而不是把 iframe 做窄 —— 做窄会触发客户页的响应式断点,看到的就不是 PC 版了。
|
|
21
|
+
*/
|
|
22
|
+
export interface InlineEditorProps {
|
|
23
|
+
url: string;
|
|
24
|
+
device: CanvasDevice;
|
|
25
|
+
onDeviceChange: (device: CanvasDevice) => void;
|
|
26
|
+
title: string;
|
|
27
|
+
/** 单版本入口的静态版本名。传了 `versions` 时不再展示它(顶栏换成选择器)。 */
|
|
28
|
+
versionLabel?: string;
|
|
29
|
+
/**
|
|
30
|
+
* 可切换的版本列表。**宿主持有数据,包只负责切换机制** —— 包里不存多版本状态,
|
|
31
|
+
* 每次切换都是「把当前清单整体换成另一份」。
|
|
32
|
+
*
|
|
33
|
+
* 不传(或空数组)= 与今天完全一致:顶栏还是 `versionLabel` 那个静态标签,
|
|
34
|
+
* 下面这一组回调一个都不会触发。
|
|
35
|
+
*/
|
|
36
|
+
versions?: {
|
|
37
|
+
id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
}[];
|
|
40
|
+
/** 当前版本。**由宿主决定**:包切换成功后只是回调通知,不自己改这个值。 */
|
|
41
|
+
activeVersionId?: string;
|
|
42
|
+
/**
|
|
43
|
+
* 各版本的**明文**改动,key = versionId。宿主持有(它才知道哪些版本、存过什么)。
|
|
44
|
+
*
|
|
45
|
+
* ⚠️ 切到某个版本时包读的是这里的**当前值**,不是切换那一刻的快照 ——
|
|
46
|
+
* 宿主在 `onVersionLeave` 里把 live 清单写回来之后,下次切回去拿到的才是最新那份。
|
|
47
|
+
*/
|
|
48
|
+
versionChanges?: Record<string, InlineChange[]>;
|
|
49
|
+
/**
|
|
50
|
+
* 版本变了(用户在顶栏选了另一个,或 AI 的这一批指名了另一个版本)。
|
|
51
|
+
* 宿主据此更新 `activeVersionId` —— 包不自己改,单一数据源仍在宿主手里。
|
|
52
|
+
*/
|
|
53
|
+
onVersionChange?: (id: string) => void;
|
|
54
|
+
/**
|
|
55
|
+
* **离开某个版本前**把它的 live 清单交还宿主。⚠️ 不接这个回调 = 用户在这个版本上
|
|
56
|
+
* 做的改动会在切走时被撤光且再也拿不回来(包不留副本)。
|
|
57
|
+
*/
|
|
58
|
+
onVersionLeave?: (id: string, records: ChangeRecord[]) => void;
|
|
59
|
+
/**
|
|
60
|
+
* 进入某个版本、改动回放完之后的**别名表**(旧 changeId → 本次新铸的 id)。
|
|
61
|
+
*
|
|
62
|
+
* 为什么必须有这个出口:回放每次都铸新 changeId(撤销闭包活在 agent 侧、随 iframe
|
|
63
|
+
* 重建而丢,见 `hydrate` 的注释),而 AI 卡片上记的是**旧** id。宿主拿这张表维护
|
|
64
|
+
* `resolveChangeId`,否则切走再切回来之后,卡片上的「撤销这一批」会一条都找不到。
|
|
65
|
+
*/
|
|
66
|
+
onVersionEnter?: (id: string, idMap: Map<string, string>) => void;
|
|
67
|
+
/**
|
|
68
|
+
* 卡片上的旧 changeId → 当前会话里的新 id(宿主用 `onVersionEnter` 的 `idMap` 维护)。
|
|
69
|
+
* 不传 = 不做映射(单版本入口本来就不需要)。
|
|
70
|
+
*/
|
|
71
|
+
resolveChangeId?: (id: string) => string;
|
|
72
|
+
/**
|
|
73
|
+
* `CHANGE_IMAGE` 的 origin 白名单(图片上传域等)。客户页自身的 origin 由包自动加上。
|
|
74
|
+
*
|
|
75
|
+
* 不传 = 只允许换成与客户页同源的图。**这是有意的 fail closed**:模型凭记忆敲出来的
|
|
76
|
+
* 域名会被每一个真实访客加载,等于我们替客户往他页面上挂了个第三方请求。
|
|
77
|
+
*/
|
|
78
|
+
allowedImageOrigins?: string[];
|
|
79
|
+
/**
|
|
80
|
+
* 本会话在这个页面上读到过的图片地址(宿主从发给 agent 的 `anchor-image:` / `element-image:`
|
|
81
|
+
* 行与 html 里的 `<img src>` 攒)。origin 白名单之外的第二条放行路,整串相等才算 ——
|
|
82
|
+
* 换图、整块重写、插入模块三处共用(见 `kernel/ai/imageSource.ts`)。不传 = 这一路不放行。
|
|
83
|
+
*/
|
|
84
|
+
allowedImageUrls?: string[];
|
|
85
|
+
/**
|
|
86
|
+
* `SET_LINK` 允许的**站外**地址 —— 用户在对话里逐字给过的那些(宿主从会话里攒)。
|
|
87
|
+
* 同源地址不需要进这张表。整串逐字相等,不是 origin 相等。
|
|
88
|
+
*/
|
|
89
|
+
allowedLinkUrls?: string[];
|
|
90
|
+
chrome?: ChromeVariant;
|
|
91
|
+
onExit: () => void;
|
|
92
|
+
onSave?: (editor: UseInlineEditorResult) => void;
|
|
93
|
+
/**
|
|
94
|
+
* 打开**已有实验**时要回显的改动(明文形态;存库的数值 tagData 由宿主经
|
|
95
|
+
* `fromWireFormat` 转过来)。画布就绪后逐条回放,清单也一并填好。
|
|
96
|
+
*
|
|
97
|
+
* 不传 = 空白新建。
|
|
98
|
+
*/
|
|
99
|
+
initialChanges?: InlineChange[];
|
|
100
|
+
/**
|
|
101
|
+
* 回显结果。**有失败项时宿主必须告诉用户** —— 客户页会改版,selector 不再命中是
|
|
102
|
+
* 常态;失败的条目仍留在清单里(不丢用户的数据),但页面上看不见它们的效果,
|
|
103
|
+
* 不说明的话用户会以为编辑器坏了。
|
|
104
|
+
*/
|
|
105
|
+
onHydrated?: (outcome: HydrateOutcome) => void;
|
|
106
|
+
/**
|
|
107
|
+
* 「问 AI」入口。**不传则工具条上不出现这个按钮** —— 包不知道产品里有没有 AI 面板,
|
|
108
|
+
* 渲染出来点了没反应比没有更让人困惑。
|
|
109
|
+
*
|
|
110
|
+
* 上下文里**不含截图**。第二个参数是绑定到该元素的**延迟**截图函数,宿主在用户真的
|
|
111
|
+
* 发送时才调它 —— 点按钮那刻就拍的话,用户如果接着又改了这个元素,图就对不上了。
|
|
112
|
+
*
|
|
113
|
+
* `capture()` 内部串起「抓图 → 宿主 uploadImage → URL」。返回 `null` 的三种情况:
|
|
114
|
+
* 宿主没注入 uploadImage、画布会话已失效(编辑器被关掉)、抓图或上传失败。
|
|
115
|
+
* **调用方不该因为它返回 null 就阻断发送** —— 一次网络抖动不该让用户发不出消息。
|
|
116
|
+
*/
|
|
117
|
+
onAskAi?: (ctx: ElementAiContext, capture: () => Promise<string | null>) => void;
|
|
118
|
+
/**
|
|
119
|
+
* **整页**上下文(以 `body` 为根)—— 给「AI 自己挑改哪儿」的首版生成用,
|
|
120
|
+
* 与 `onAskAi` 的元素级上下文是两件事:那份是用户已经选好了一个元素。
|
|
121
|
+
*
|
|
122
|
+
* `domReady` 且图层树拉到之后算一次。**只在传了这个 prop 时才算** ——
|
|
123
|
+
* 它要多一次跨域往返(整页 DOM 树 + body 的 outerHTML),没人用的话是纯浪费。
|
|
124
|
+
*
|
|
125
|
+
* ⚠️ **不改选中态**:这一步是背景采集,用户可能正看着自己刚点中的元素。
|
|
126
|
+
* `capture()` 与元素级同一支(对 body 就是整屏),失败回 `null`,别因此阻断发送。
|
|
127
|
+
*
|
|
128
|
+
* `captureAnchors()`(有 resolved 锚点时才给):每个锚点区块一张裁切截图。整页图告诉 agent
|
|
129
|
+
* 区块在哪,裁切图才看得清区块内文字的颜色、字重、按钮圆角 —— 首版要"融进去"的东西。
|
|
130
|
+
* 同样在发送那一刻才拍,失败的那块就少一张,不阻断。
|
|
131
|
+
*/
|
|
132
|
+
onPageContextReady?: (ctx: ElementAiContext, capture: () => Promise<string | null>, captureAnchors?: () => Promise<AnchorShot[]>) => void;
|
|
133
|
+
/**
|
|
134
|
+
* **方案锚点** —— 这条实验诞生时那份方案点名的页面区块(`InlinePlan.anchors`)。
|
|
135
|
+
*
|
|
136
|
+
* 存在的理由:假设是「B2 首屏的徽章」这么写的,而包交给 agent 的整页货架是一张扁平的
|
|
137
|
+
* selector 表,上面没有区块身份 —— agent 只能按关键词猜,猜错了也没有任何一道闸会拦
|
|
138
|
+
* (真机 trace:首屏那条被静默重锚到了页底另一个提到同样关键词的段落上)。
|
|
139
|
+
*
|
|
140
|
+
* 传了之后包会在**活页面上重新解析**它们(selector 优先,失效按 `label` 找回来),
|
|
141
|
+
* 把命中的锚点连同**它们的子树**排在整页货架最前 —— 于是 agent 既知道该改哪个容器,
|
|
142
|
+
* 也真的能改到容器里的孩子(货架是授权清单,不在货架里的 selector 一律 `OUT_OF_SCOPE`)。
|
|
143
|
+
*
|
|
144
|
+
* ⚠️ 只在 `onPageContextReady` 那条路上生效,且**每个会话读一次**(与整页货架同一次采集)。
|
|
145
|
+
* 不传 = 与今天完全一致。
|
|
146
|
+
*/
|
|
147
|
+
anchors?: InlinePlanAnchor[];
|
|
148
|
+
/**
|
|
149
|
+
* 编辑器可用了(画布就绪、命令能发了)——**每个会话交一次**把手。
|
|
150
|
+
*
|
|
151
|
+
* 换会话(切设备 / 重载)会再交一次:新会话里那些命令要带新的 sessionId,
|
|
152
|
+
* 宿主留着上一次那份也不会报错,只是发出去的命令没人应答。
|
|
153
|
+
*/
|
|
154
|
+
onEditorReady?: (handle: InlineEditorHandle) => void;
|
|
155
|
+
/**
|
|
156
|
+
* 画布会话就绪 → 交出 sessionId。**每个会话一次**,时机与 `onEditorReady` 相同
|
|
157
|
+
* (agent 报了 domReady):这是 frame 命令(`resolveHeatmapSelector` 等)保证有人
|
|
158
|
+
* 应答的最早时刻 —— 早于它发命令会 `FRAME_NOT_READY`。切设备 / 重载开新会话时再交一次。
|
|
159
|
+
*
|
|
160
|
+
* 宿主要它是为了调 `resolveBlocks(sessionId, …)`(`useInlineEditor()` 的内部状态不外露,
|
|
161
|
+
* 此前只能从 iframe 的 `name` 里反解 —— 那是 hack)。
|
|
162
|
+
*/
|
|
163
|
+
onSessionReady?: (sessionId: string) => void;
|
|
164
|
+
/**
|
|
165
|
+
* 按设备覆盖目标视口宽(只对**这一个实例**生效,合在 `TARGET_VIEWPORT_WIDTH` 之上)。
|
|
166
|
+
*
|
|
167
|
+
* 分析画布用:热图区块的 `yStart/yEnd` 是按 375 宽(mobile)量的,画布默认 390 ——
|
|
168
|
+
* 差 15px 足以让响应式断点换一套布局,区块框与页面对不上。
|
|
169
|
+
*/
|
|
170
|
+
viewportWidthOverride?: Partial<Record<CanvasDevice, number>>;
|
|
171
|
+
/**
|
|
172
|
+
* 分析画布的区块框层(`resolveBlocks` 的产出)。传了就画在画布之上,随几何帧走;
|
|
173
|
+
* `activeId` 那块高亮;`onHover` 报芯片的悬浮(宿主据此高亮聊天里对应的段)。
|
|
174
|
+
* 不传 = 没有这一层(普通编辑器)。
|
|
175
|
+
*/
|
|
176
|
+
blockOverlay?: {
|
|
177
|
+
blocks: PageModelBlock[];
|
|
178
|
+
activeId?: string | null;
|
|
179
|
+
onHover?: (id: string | null) => void;
|
|
180
|
+
};
|
|
181
|
+
/**
|
|
182
|
+
* 选中变化 → 新的 AI 上下文。`null` = 选中被清空。
|
|
183
|
+
*
|
|
184
|
+
* **只在 `trackAiSelection` 为真时触发**,因为算一次上下文要多一次跨域往返
|
|
185
|
+
* (取 outerHTML)—— AI 面板没开着的时候那次往返是纯浪费。
|
|
186
|
+
*
|
|
187
|
+
* 与 `onAskAi` 的分工:这个只**更新**上下文,宿主不该顺手把面板打开;
|
|
188
|
+
* `onAskAi` 是用户点了 ✨,那时才开面板。
|
|
189
|
+
*/
|
|
190
|
+
onAiContextChange?: (ctx: ElementAiContext | null, capture: () => Promise<string | null>) => void;
|
|
191
|
+
/**
|
|
192
|
+
* 把「应用 AI 改动」的入口交给宿主。`null` = 画布会话不可用(此时不该也无法应用)。
|
|
193
|
+
*
|
|
194
|
+
* 为什么是回调而不是宿主直接调:AI 面板在**另一棵组件树**里(dock 挂在 AppShell 上),
|
|
195
|
+
* 拿不到编辑器内部的 change list —— 与 `capture` 同一套分工,宿主把它存进 store。
|
|
196
|
+
*
|
|
197
|
+
* ⚠️ 这个 apply **自带作用域**:只允许改「注册这一刻选中的那个元素」。宿主不需要、
|
|
198
|
+
* 也不应该自己传 selector 进来 —— agent 编的 selector 正是这道闸要拦的东西。
|
|
199
|
+
*/
|
|
200
|
+
onAiApplyReady?: (api: AiApplyApi | null) => void;
|
|
201
|
+
/**
|
|
202
|
+
* 用户撤销(单条 / 整批 / 换版本)拿掉了 AI 插入的元素 → 回报它们的 selector。宿主据此把这些行
|
|
203
|
+
* 从 AI 的货架 / 授权票里删掉;包自己同时把它们从作用域里剔除。没有插入类时不调用。
|
|
204
|
+
*/
|
|
205
|
+
onAiInsertedRemoved?: (selectors: string[]) => void;
|
|
206
|
+
/** 回放把 AI 插入的元素放回画布(切版本 / 切设备)→ 回报它们的 selector;宿主把它们并回货架。 */
|
|
207
|
+
onAiInsertedRestored?: (selectors: string[]) => void;
|
|
208
|
+
/**
|
|
209
|
+
* 是否跟着选中实时刷新 AI 上下文。宿主在**右侧 AI 面板已打开**时给 true。
|
|
210
|
+
*
|
|
211
|
+
* 面板关着还刷的话,每点一个元素都白花一次往返;而面板开着不刷的话,用户以为
|
|
212
|
+
* 自己换了选中、AI 却还在聊上一个元素 —— 这种错位不会有任何提示。
|
|
213
|
+
*/
|
|
214
|
+
trackAiSelection?: boolean;
|
|
215
|
+
/**
|
|
216
|
+
* 组件库数据。宿主注入(包里不碰后端)—— **不传则左侧不出现「组件」页签**,
|
|
217
|
+
* 而不是出现一个空页签让用户以为库是空的。Task 6 填充。
|
|
218
|
+
*/
|
|
219
|
+
libraryComponents?: LibraryComponent[];
|
|
220
|
+
libraryLoading?: boolean;
|
|
221
|
+
/**
|
|
222
|
+
* 新增版本。**不传则顶栏不渲染那个入口** —— 版本是 experience 级状态
|
|
223
|
+
* (每个版本一份 change list),不归编辑器管。
|
|
224
|
+
*/
|
|
225
|
+
onAddVersion?: () => void;
|
|
226
|
+
/**
|
|
227
|
+
* 版本改名。**不传则下拉行里没有铅笔**(同 `onAddVersion`)。包只做交互与校验,
|
|
228
|
+
* 名字是 experience 级状态(保存时作为 `summary` 落库),改不改得成由宿主说了算。
|
|
229
|
+
*/
|
|
230
|
+
onRenameVersion?: (id: string, name: string) => void;
|
|
231
|
+
/**
|
|
232
|
+
* 真实页面预览。**不传则顶栏不渲染那个入口** —— 预览链接由后端按 experience + 版本
|
|
233
|
+
* 签发(同详情页的「真实页面预览」),包里没有 experience 的概念,也不知道
|
|
234
|
+
* uid / sid,所以整件事归宿主。创建流程里 experience 还没落库,就别渲染。
|
|
235
|
+
*/
|
|
236
|
+
onPreview?: () => void;
|
|
237
|
+
/**
|
|
238
|
+
* 开/关宿主的右侧 AI 面板。**不传则顶栏不渲染那个按钮** —— 同 `onPreview` 的处理。
|
|
239
|
+
*
|
|
240
|
+
* 包里没有 AI 面板,它是宿主布局的一部分(apps/x 的 `layout` store `aiVisible`)。
|
|
241
|
+
* apps/x 的宿主(`InlineEditorHost`,详情页与创建空白体验共用)接了;宿主没有 dock 可召唤时就别接。
|
|
242
|
+
*
|
|
243
|
+
* ⚠️ 纯开关:宿主实现里**不要**顺手切 agent 或开新会话(那是 `onAskAi` 的语义)。
|
|
244
|
+
*/
|
|
245
|
+
onToggleAi?: () => void;
|
|
246
|
+
/** 宿主的右侧 AI 面板当前开着 —— 顶栏按钮据此高亮。 */
|
|
247
|
+
aiOpen?: boolean;
|
|
248
|
+
/**
|
|
249
|
+
* 把截图字节换成一条 URL。
|
|
250
|
+
*
|
|
251
|
+
* **包里不碰后端端点** —— 包不知道 `VITE_BACKEND_URL`、不知道 `sid`,那些是宿主的事
|
|
252
|
+
* (与 README 的两层 API 分工一致)。不传则只在界面上显示截图结果,不上传。
|
|
253
|
+
*/
|
|
254
|
+
uploadImage?: (blob: Blob) => Promise<string>;
|
|
255
|
+
/**
|
|
256
|
+
* 图层树行首图标渲染器。**不传则树里不出图标**(不是出个占位方块)。
|
|
257
|
+
*
|
|
258
|
+
* 为什么由宿主给:lucide 字形表是「三代编辑器共用的唯一真值表」,住在
|
|
259
|
+
* `apps/x/src/components/landing-pages/editor/icons/` —— 包不能反向依赖 app。
|
|
260
|
+
* 包只交出事实(标签名 + 有没有子节点),挑哪个字形是宿主的事。
|
|
261
|
+
*/
|
|
262
|
+
renderNodeIcon?: AdaptDomTreeOptions['renderIcon'];
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* 交给宿主的编辑器把手 —— **每个画布会话交一次**(`onEditorReady`)。
|
|
266
|
+
*
|
|
267
|
+
* 为什么不是「把 `useInlineEditor()` 的结果整个交出去」:那是内核的全部内部状态,
|
|
268
|
+
* 交出去等于把包的实现细节变成契约。这里只开三件宿主真的做不到的事。
|
|
269
|
+
*/
|
|
270
|
+
export interface InlineEditorHandle {
|
|
271
|
+
/**
|
|
272
|
+
* 清空选中(等价于 `commands.select('')`)。
|
|
273
|
+
*
|
|
274
|
+
* 宿主要它是为了**回到整页作用域**:有选中时 AI 的 apply 闸只认那一个元素与它的货架,
|
|
275
|
+
* 而首版生成(AI 自己挑改哪儿)必须在没有选中的状态下跑 —— 用户点过一个元素之后,
|
|
276
|
+
* 只有宿主知道「现在要换成整页那档了」。
|
|
277
|
+
*/
|
|
278
|
+
clearSelection: () => Promise<void>;
|
|
279
|
+
/**
|
|
280
|
+
* **同步**读当前改动清单(不是渲染期那份 state)。
|
|
281
|
+
*
|
|
282
|
+
* 宿主保存时要的就是这一刻的清单;读渲染期那份会漏掉刚写进去、还没重渲染的那条。
|
|
283
|
+
*/
|
|
284
|
+
peekList: () => ChangeRecord[];
|
|
285
|
+
/** 有没有未保存的改动 —— 离开确认、保存按钮的禁用态用它。 */
|
|
286
|
+
hasUnsavedChanges: () => boolean;
|
|
287
|
+
/**
|
|
288
|
+
* 整页截图 → PNG Blob(分析画布:标注区块后切瓦片给模型)。
|
|
289
|
+
*
|
|
290
|
+
* = `captureSelectedElement('body')`:走现成的编排(先滚动测量 → 藏 fixed/sticky 与
|
|
291
|
+
* 产品页浮层 → 分屏抓 → 恢复),**不另写一套**。fixed/sticky 由既有的 `setFixedHidden`
|
|
292
|
+
* 全部藏掉 —— 吸顶导航在长图里重复三四次比少一条导航更误导模型。
|
|
293
|
+
*/
|
|
294
|
+
capturePage: () => Promise<Blob>;
|
|
295
|
+
/**
|
|
296
|
+
* 「定位」:把 selector 指向的元素滚进视野(= `commands.reveal`)。
|
|
297
|
+
* 分析画布点聊天里的某块 → 画布滚到那块。未命中不抛(agent 回 found:false)。
|
|
298
|
+
*/
|
|
299
|
+
scrollToSelector: (selector: string) => Promise<void>;
|
|
300
|
+
/**
|
|
301
|
+
* 当前**就绪**的画布会话 id;`null` = 画布还没起来(含切设备后新 frame 尚未报 domReady
|
|
302
|
+
* 的窗口 —— 此刻发 frame 命令没人应答,所以不给旧 id)。
|
|
303
|
+
*/
|
|
304
|
+
getSessionId: () => string | null;
|
|
305
|
+
/** 画布当前施加在 `<html>` 上的缩放比例(移动端超宽缩小;不缩为 1)。语义同 `PagePreviewHandle`。 */
|
|
306
|
+
getMobileFitScale: () => number;
|
|
307
|
+
}
|
|
308
|
+
/** 宿主拿到的 AI 改动入口。 */
|
|
309
|
+
export interface AiApplyApi {
|
|
310
|
+
/**
|
|
311
|
+
* 应用一批改动。
|
|
312
|
+
*
|
|
313
|
+
* `opts.versionId` 指名了另一个版本时**先切过去再应用**(切换与应用共用同一个串行
|
|
314
|
+
* 队列,所以 agent 连着给两个版本的两批不会交错)。切换失败则整批 reject,
|
|
315
|
+
* reason `VERSION_SWITCH_FAILED`,并停留在当前版本 —— 半批落在错版本上比不落更糟。
|
|
316
|
+
*
|
|
317
|
+
* 返回里的 `versionId` 是这一批**实际落在**哪个版本上,宿主拿它给卡片记账。
|
|
318
|
+
*
|
|
319
|
+
* `opts.grant` 是**发这条消息时交给 agent 的那份作用域**(见 `AiScopeGrant`):一轮要
|
|
320
|
+
* 60-120 秒,中途选中丢了的话包这边的实时作用域已经不是当时那个了。宿主自己记得当时
|
|
321
|
+
* 给出去的是什么,所以由它交回来 —— 与实时作用域取并集,不传则行为与今天逐字一致。
|
|
322
|
+
*/
|
|
323
|
+
apply: (changes: AiWireChange[], opts?: {
|
|
324
|
+
versionId?: string;
|
|
325
|
+
grant?: AiScopeGrant;
|
|
326
|
+
}) => Promise<AiApplyOutcome & {
|
|
327
|
+
versionId: string;
|
|
328
|
+
}>;
|
|
329
|
+
/**
|
|
330
|
+
* 撤销**指定的**几条(卡片上的「撤销这一批」)。
|
|
331
|
+
*
|
|
332
|
+
* ⚠️ 不能用 `revertAll` —— 那会把用户自己手改的一起撤掉。
|
|
333
|
+
* ⚠️ **倒序撤**:后面的 change 可能作用在前面那条造出来的现场上,顺序撤会让它基于
|
|
334
|
+
* 已被撤掉的状态还原(与 `revertAll` 同一个理由)。
|
|
335
|
+
*
|
|
336
|
+
* 先经 `resolveChangeId` 映射(切过版本之后 id 都换过了);映射完仍不在当前清单里,
|
|
337
|
+
* 说明这一批属于另一个版本 —— 返回 `VERSION_NOT_ACTIVE` 而不是硬撤:那些 id 在
|
|
338
|
+
* agent 侧早就没有闭包了,硬撤是静默的 no-op,用户只会看到「点了没反应」。
|
|
339
|
+
*/
|
|
340
|
+
revert: (changeIds: string[]) => Promise<{
|
|
341
|
+
ok: true;
|
|
342
|
+
} | {
|
|
343
|
+
ok: false;
|
|
344
|
+
reason: 'VERSION_NOT_ACTIVE' | 'EDITOR_CLOSED';
|
|
345
|
+
}>;
|
|
346
|
+
/** 当前版本 —— 宿主把 agent 给的版本**名**映射成 id 时要知道现在在哪一版。 */
|
|
347
|
+
readonly activeVersionId?: string;
|
|
348
|
+
}
|
|
349
|
+
export declare function InlineEditor({ url, device, onDeviceChange, title, versionLabel, chrome, onExit, onSave, libraryComponents, libraryLoading, onAddVersion, onRenameVersion, onPreview, onToggleAi, aiOpen, uploadImage, initialChanges, onHydrated, onAskAi, onPageContextReady, anchors, onEditorReady, onSessionReady, onAiContextChange, onAiApplyReady, onAiInsertedRemoved, onAiInsertedRestored, trackAiSelection, renderNodeIcon, versions, activeVersionId, versionChanges, onVersionChange, onVersionLeave, onVersionEnter, resolveChangeId, allowedImageOrigins, allowedImageUrls, allowedLinkUrls, viewportWidthOverride, blockOverlay }: InlineEditorProps): import("react").JSX.Element;
|