nudge-ui 0.2.4 → 0.2.5
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/cli/agentCommand.js +4 -28
- package/dist/client.mjs +863 -213
- package/dist/hosts/next/wrapper.js +1 -7
- package/dist/hosts/projectBridge.js +3 -17
- package/dist/inspector/agent/McpConnectionDialog.js +7 -3
- package/dist/inspector/agent/activity.d.ts +1 -1
- package/dist/inspector/agent/activity.js +3 -2
- package/dist/inspector/agent/client.d.ts +2 -2
- package/dist/inspector/agent/client.js +28 -29
- package/dist/inspector/agent/connectionStatus.d.ts +3 -1
- package/dist/inspector/agent/connectionStatus.js +25 -0
- package/dist/inspector/agent/httpTransport.js +31 -147
- package/dist/inspector/agent/protocol.d.ts +1 -1
- package/dist/inspector/agent/protocol.js +1 -1
- package/dist/inspector/agent/verification.d.ts +1 -1
- package/dist/inspector/agent/verification.js +7 -4
- package/dist/inspector/boot.d.ts +3 -0
- package/dist/inspector/boot.js +297 -0
- package/dist/inspector/canvas/AgentActivityOverlay.d.ts +2 -1
- package/dist/inspector/canvas/AgentActivityOverlay.js +6 -3
- package/dist/inspector/canvas/CanvasCard.js +21 -12
- package/dist/inspector/canvas/CanvasElementOverlay.js +82 -127
- package/dist/inspector/canvas/CanvasToolbar.js +2 -1
- package/dist/inspector/canvas/CanvasWorkspace.js +74 -97
- package/dist/inspector/canvas/LockedWorkspaceNotice.d.ts +3 -2
- package/dist/inspector/canvas/LockedWorkspaceNotice.js +10 -6
- package/dist/inspector/canvas/PageCard.d.ts +10 -0
- package/dist/inspector/canvas/PageCard.js +51 -0
- package/dist/inspector/canvas/SketchToolOptions.d.ts +5 -0
- package/dist/inspector/canvas/SketchToolOptions.js +86 -0
- package/dist/inspector/canvas/StaleChangeIndicator.d.ts +1 -1
- package/dist/inspector/canvas/StaleChangeIndicator.js +1 -1
- package/dist/inspector/canvas/ToolOptionsDrawer.d.ts +21 -0
- package/dist/inspector/canvas/ToolOptionsDrawer.js +77 -0
- package/dist/inspector/canvas/activeCanvasDocument.d.ts +3 -2
- package/dist/inspector/canvas/assets/eraser.svg +28 -0
- package/dist/inspector/canvas/assets/pen.svg +25 -0
- package/dist/inspector/canvas/canvasFrame.d.ts +16 -0
- package/dist/inspector/canvas/canvasFrame.js +10 -0
- package/dist/inspector/canvas/canvasGestures.d.ts +0 -1
- package/dist/inspector/canvas/canvasGestures.js +0 -6
- package/dist/inspector/canvas/canvasStore.d.ts +6 -0
- package/dist/inspector/canvas/canvasStore.js +36 -1
- package/dist/inspector/canvas/frameConnection.d.ts +48 -0
- package/dist/inspector/canvas/frameConnection.js +73 -0
- package/dist/inspector/canvas/frameProtocol.d.ts +18 -1
- package/dist/inspector/canvas/frameProtocol.js +36 -0
- package/dist/inspector/canvas/pageSurface.d.ts +11 -0
- package/dist/inspector/canvas/pageSurface.js +34 -0
- package/dist/inspector/canvas/projection.d.ts +19 -9
- package/dist/inspector/canvas/projection.js +58 -31
- package/dist/inspector/canvas/rendererBootstrap.js +4 -1
- package/dist/inspector/canvas/rendererElementSelector.js +9 -1
- package/dist/inspector/canvas/rendererMessageRouter.d.ts +4 -5
- package/dist/inspector/canvas/rendererMessageRouter.js +12 -16
- package/dist/inspector/canvas/rendererSelectionProxy.d.ts +7 -1
- package/dist/inspector/canvas/rendererSelectionProxy.js +8 -36
- package/dist/inspector/canvas/rendererStylesheet.js +15 -0
- package/dist/inspector/canvas/sessionStore.d.ts +2 -2
- package/dist/inspector/canvas/sessionStore.js +12 -9
- package/dist/inspector/canvas/staleChangeDetector.d.ts +1 -1
- package/dist/inspector/canvas/staleChangeDetector.js +10 -22
- package/dist/inspector/changes/codecs.d.ts +1 -0
- package/dist/inspector/changes/codecs.js +20 -5
- package/dist/inspector/changes/draftPreview.d.ts +12 -0
- package/dist/inspector/changes/draftPreview.js +133 -0
- package/dist/inspector/changes/editModel.d.ts +8 -0
- package/dist/inspector/changes/editModel.js +8 -2
- package/dist/inspector/changes/managedStyleProjection.js +2 -1
- package/dist/inspector/changes/previewDiagnostics.js +1 -1
- package/dist/inspector/changes/types.d.ts +11 -1
- package/dist/inspector/comments/CommentsOverlay.js +18 -16
- package/dist/inspector/comments/store.js +3 -2
- package/dist/inspector/comments/verification.js +1 -1
- package/dist/inspector/componentSemantics/ComponentPropsSection.js +2 -1
- package/dist/inspector/componentSemantics/changeAction.js +1 -1
- package/dist/inspector/componentSemantics/textBinding.d.ts +1 -2
- package/dist/inspector/componentSemantics/textBinding.js +4 -45
- package/dist/inspector/drafts/draftStore.d.ts +109 -0
- package/dist/inspector/drafts/draftStore.js +451 -0
- package/dist/inspector/drafts/model.d.ts +9 -1
- package/dist/inspector/drafts/model.js +5 -1
- package/dist/inspector/drafts/store.d.ts +53 -15
- package/dist/inspector/drafts/store.js +143 -169
- package/dist/inspector/index.d.ts +2 -4
- package/dist/inspector/index.js +2 -264
- package/dist/inspector/inline-text/inlineTextEditor.d.ts +1 -1
- package/dist/inspector/inline-text/inlineTextEditor.js +1 -2
- package/dist/inspector/inline-text/textEditChange.d.ts +1 -1
- package/dist/inspector/inspection/bridge.d.ts +1 -1
- package/dist/inspector/inspection/bridge.js +2 -1
- package/dist/inspector/inspection/browserCssInspection.d.ts +8 -0
- package/dist/inspector/inspection/browserCssInspection.js +28 -6
- package/dist/inspector/inspection/inspectionSnapshot.d.ts +6 -0
- package/dist/inspector/inspection/inspectionSnapshot.js +10 -0
- package/dist/inspector/inspection/performanceDiagnostics.d.ts +18 -0
- package/dist/inspector/inspection/performanceDiagnostics.js +31 -0
- package/dist/inspector/inspection/useBrowserCssInspection.js +17 -38
- package/dist/inspector/iterations/capture.d.ts +2 -1
- package/dist/inspector/iterations/client.d.ts +2 -1
- package/dist/inspector/iterations/coordinator.d.ts +4 -3
- package/dist/inspector/iterations/coordinator.js +5 -3
- package/dist/inspector/iterations/prompt.js +9 -8
- package/dist/inspector/overlay/interactionStyles.js +17 -0
- package/dist/inspector/pageInspector.d.ts +42 -0
- package/dist/inspector/pageInspector.js +342 -0
- package/dist/inspector/projection/draftProjection.d.ts +10 -2
- package/dist/inspector/projection/draftProjection.js +9 -1
- package/dist/inspector/projection/managedStylesheet.js +24 -4
- package/dist/inspector/projection/renderedInstance.js +7 -1
- package/dist/inspector/projection/structuralProjection.d.ts +0 -9
- package/dist/inspector/projection/structuralProjection.js +14 -44
- package/dist/inspector/projection/textProjection.d.ts +8 -2
- package/dist/inspector/projection/textProjection.js +21 -13
- package/dist/inspector/prompt/clipboardHandoff.d.ts +9 -0
- package/dist/inspector/prompt/clipboardHandoff.js +42 -16
- package/dist/inspector/prompt/generatePrompt.d.ts +1 -1
- package/dist/inspector/prompt/generatePrompt.js +243 -147
- package/dist/inspector/prompt/promptDocument.d.ts +3 -0
- package/dist/inspector/prompt/promptDocument.js +8 -0
- package/dist/inspector/prompt/promptSettings.js +7 -5
- package/dist/inspector/runtime/inspectorStorage.d.ts +17 -0
- package/dist/inspector/runtime/inspectorStorage.js +42 -0
- package/dist/inspector/runtime/ownedStylesheets.d.ts +20 -0
- package/dist/inspector/runtime/ownedStylesheets.js +72 -0
- package/dist/inspector/runtime/runtimeConfig.d.ts +4 -0
- package/dist/inspector/runtime/runtimeConfig.js +10 -1
- package/dist/inspector/runtime/runtimeIdentityClaims.d.ts +29 -0
- package/dist/inspector/runtime/runtimeIdentityClaims.js +188 -0
- package/dist/inspector/runtime/staticHtmlRuntimeIdentity.d.ts +15 -0
- package/dist/inspector/runtime/staticHtmlRuntimeIdentity.js +113 -29
- package/dist/inspector/selection/editScope.d.ts +1 -0
- package/dist/inspector/selection/editScope.js +13 -2
- package/dist/inspector/shell/AgentStatusButton.js +2 -2
- package/dist/inspector/shell/AppShell.js +6 -2
- package/dist/inspector/shell/ChangesLog.js +27 -9
- package/dist/inspector/shell/CopyPromptButton.js +60 -54
- package/dist/inspector/shell/EmptyState.js +3 -3
- package/dist/inspector/shell/InspectorShell.d.ts +0 -3
- package/dist/inspector/shell/InspectorShell.js +21 -13
- package/dist/inspector/shell/PeekOriginalButton.js +3 -3
- package/dist/inspector/shell/interactionStatePreview.d.ts +9 -0
- package/dist/inspector/shell/interactionStatePreview.js +112 -0
- package/dist/inspector/shell/originalPreview.d.ts +3 -2
- package/dist/inspector/shell/originalPreview.js +10 -37
- package/dist/inspector/shell/stateValue.js +2 -3
- package/dist/inspector/sketch/SketchEditor.js +5 -4
- package/dist/inspector/sketch/SketchFrameOverlay.d.ts +2 -1
- package/dist/inspector/sketch/SketchFrameOverlay.js +5 -4
- package/dist/inspector/sketch/SketchOverlay.d.ts +3 -5
- package/dist/inspector/sketch/SketchOverlay.js +139 -263
- package/dist/inspector/sketch/SketchPromptPanel.d.ts +1 -1
- package/dist/inspector/sketch/SketchPromptPanel.js +8 -1
- package/dist/inspector/sketch/SketchThumbnail.d.ts +5 -0
- package/dist/inspector/sketch/SketchThumbnail.js +18 -0
- package/dist/inspector/sketch/SketchWorkspace.d.ts +1 -2
- package/dist/inspector/sketch/SketchWorkspace.js +69 -34
- package/dist/inspector/sketch/capture.js +19 -3
- package/dist/inspector/sketch/copySketch.d.ts +10 -0
- package/dist/inspector/sketch/copySketch.js +52 -0
- package/dist/inspector/sketch/drawingTools.d.ts +17 -0
- package/dist/inspector/sketch/drawingTools.js +47 -0
- package/dist/inspector/sketch/frameHeading.d.ts +9 -0
- package/dist/inspector/sketch/frameHeading.js +30 -0
- package/dist/inspector/sketch/freehand.js +3 -3
- package/dist/inspector/sketch/geometry.d.ts +6 -0
- package/dist/inspector/sketch/geometry.js +19 -0
- package/dist/inspector/sketch/history.d.ts +30 -0
- package/dist/inspector/sketch/history.js +58 -0
- package/dist/inspector/sketch/interaction.d.ts +1 -3
- package/dist/inspector/sketch/interaction.js +6 -9
- package/dist/inspector/sketch/model.d.ts +35 -1
- package/dist/inspector/sketch/model.js +116 -61
- package/dist/inspector/sketch/persistence.d.ts +14 -0
- package/dist/inspector/sketch/persistence.js +63 -7
- package/dist/inspector/sketch/raster.d.ts +6 -2
- package/dist/inspector/sketch/raster.js +43 -17
- package/dist/inspector/sketch/store.d.ts +1 -1
- package/dist/inspector/sketch/store.js +1 -1
- package/dist/inspector/sketch/videoFrames.d.ts +6 -0
- package/dist/inspector/sketch/videoFrames.js +81 -0
- package/dist/inspector/styleEditors/BackgroundEditor.js +2 -1
- package/dist/inspector/styleEditors/BorderEditor.js +30 -130
- package/dist/inspector/styleEditors/BorderRadiusEditor.js +8 -3
- package/dist/inspector/styleEditors/ImageBackgroundEditor.js +1 -1
- package/dist/inspector/styleEditors/LayoutSection.js +2 -2
- package/dist/inspector/styleEditors/borderModel.d.ts +42 -0
- package/dist/inspector/styleEditors/borderModel.js +114 -0
- package/dist/inspector/styleEditors/layoutValue.js +2 -3
- package/dist/inspector/tokens/TokenField.js +34 -3
- package/dist/inspector/tokens/TokensPanel.js +2 -1
- package/dist/inspector/tokens/editActions.d.ts +3 -3
- package/dist/inspector/tokens/editActions.js +9 -3
- package/dist/inspector/tokens/resolution/containerQueryEvaluator.d.ts +15 -0
- package/dist/inspector/tokens/resolution/containerQueryEvaluator.js +86 -0
- package/dist/inspector/tokens/resolution/cssomCollector.js +44 -9
- package/dist/inspector/tokens/resolution/nestedSelectors.d.ts +6 -0
- package/dist/inspector/tokens/resolution/nestedSelectors.js +67 -0
- package/dist/inspector/tokens/resolution/ruleMatching.js +23 -4
- package/dist/inspector/tokens/resolution.d.ts +6 -3
- package/dist/inspector/tokens/resolution.js +91 -112
- package/dist/inspector/tokens/tokenEdits.d.ts +1 -1
- package/dist/inspector/tokens/tokenEdits.js +1 -1
- package/dist/inspector/ui/InlineStyleWarning.js +2 -2
- package/dist/inspector/ui/InspectorStyle.d.ts +8 -0
- package/dist/inspector/ui/InspectorStyle.js +26 -0
- package/dist/inspector/ui/PopoverListbox.d.ts +2 -1
- package/dist/inspector/ui/PopoverListbox.js +3 -3
- package/dist/inspector/ui/Toast.d.ts +14 -0
- package/dist/inspector/ui/Toast.js +30 -0
- package/dist/inspector/ui/assets/canvasIllustration.d.ts +2 -0
- package/dist/inspector/ui/assets/canvasIllustration.js +21 -0
- package/dist/inspector/ui/assets/gridIllustration.d.ts +2 -0
- package/dist/inspector/ui/assets/{grid.svg → gridIllustration.js} +3 -2
- package/dist/inspector/ui/customCursors.d.ts +5 -0
- package/dist/inspector/ui/customCursors.js +32 -6
- package/dist/inspector/ui/styles.js +12 -10
- package/dist/inspector/workspace/commands.js +1 -2
- package/dist/inspector/workspace/controller.js +1 -2
- package/dist/inspector/workspace/handoff.js +3 -2
- package/dist/inspector/workspace/sentItems.d.ts +3 -6
- package/dist/inspector/workspace/sentItems.js +6 -24
- package/dist/inspector/workspace/timeline.d.ts +24 -10
- package/dist/inspector/workspace/timeline.js +118 -96
- package/dist/internal/agent-protocol.d.ts +50 -13
- package/dist/internal/agent-protocol.js +145 -19
- package/dist/nudge-ui.mjs +81 -65
- package/dist/project/mcpPackage.d.ts +8 -0
- package/dist/project/mcpPackage.js +60 -0
- package/package.json +12 -2
- package/dist/inspector/canvas/measurementProjection.d.ts +0 -8
- package/dist/inspector/canvas/measurementProjection.js +0 -16
- package/dist/inspector/changes/changesLog.d.ts +0 -49
- package/dist/inspector/changes/changesLog.js +0 -255
- package/dist/inspector/changes/draftChanges.d.ts +0 -58
- package/dist/inspector/changes/draftChanges.js +0 -304
- package/dist/inspector/conformance/projection.d.ts +0 -2
- package/dist/inspector/conformance/projection.js +0 -3
- package/dist/inspector/inline-text/textChangeBoundary.d.ts +0 -6
- package/dist/inspector/inline-text/textChangeBoundary.js +0 -1
- package/dist/inspector/overlay/InspectorOverlay.d.ts +0 -5
- package/dist/inspector/overlay/InspectorOverlay.js +0 -332
- package/dist/inspector/overlay/elementSelector.d.ts +0 -1
- package/dist/inspector/overlay/elementSelector.js +0 -111
- package/dist/inspector/sketch/SketchChanges.d.ts +0 -2
- package/dist/inspector/sketch/SketchChanges.js +0 -72
- package/dist/inspector/sketch/SketchEntryButton.d.ts +0 -4
- package/dist/inspector/sketch/SketchEntryButton.js +0 -11
- package/dist/inspector/sketch/SketchLayersPanel.d.ts +0 -2
- package/dist/inspector/sketch/SketchLayersPanel.js +0 -71
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entry for loading the inspector into any page without a host Adapter.
|
|
3
|
+
*
|
|
4
|
+
* Everything a host normally supplies is derived from the live document:
|
|
5
|
+
* runtime identity is assigned lazily under the pointer, and tokens come from
|
|
6
|
+
* readable stylesheets plus the root's computed custom properties. Source
|
|
7
|
+
* locations, component semantics, iterations, and the agent bridge are
|
|
8
|
+
* unavailable. In editor mode the application runs in Canvas frames;
|
|
9
|
+
* otherwise the page itself is the only Canvas card.
|
|
10
|
+
*/
|
|
11
|
+
import { bootstrapNudgeUi, configureNudgeUiRuntime, getNudgeUiRuntimeConfig, isCanvasRenderer, readNudgeUiEditorTarget, setInspectorOpen, unmountInspector, } from "./index.js";
|
|
12
|
+
import { CANVAS_RENDERER_ATTR } from "./canvas/roleDetection.js";
|
|
13
|
+
import { releaseLease } from "./canvas/workspaceLease.js";
|
|
14
|
+
import { enablePageSurface } from "./canvas/pageSurface.js";
|
|
15
|
+
import { setNudgeUiHostDevFlag } from "./runtime/devFlag.js";
|
|
16
|
+
import { configureInspectorStorage } from "./runtime/inspectorStorage.js";
|
|
17
|
+
import { configureSketchStorage } from "./sketch/persistence.js";
|
|
18
|
+
import { preferAdoptedStylesheets } from "./runtime/ownedStylesheets.js";
|
|
19
|
+
import { enableInspectionPerformanceDiagnostics } from "./inspection/performanceDiagnostics.js";
|
|
20
|
+
import { installLazyRuntimeIdentity } from "./runtime/staticHtmlRuntimeIdentity.js";
|
|
21
|
+
import { createTokenInventory } from "../css/token-inventory/inventory.js";
|
|
22
|
+
export { createMirroredStorage } from "./runtime/inspectorStorage.js";
|
|
23
|
+
const MOUNT_ID = "nudge-ui-root";
|
|
24
|
+
const LOADED_FLAG = "__NUDGE_UI_PAGE_INSPECTOR__";
|
|
25
|
+
const COMPUTED_ROOT_ID = "computed:root";
|
|
26
|
+
function isNudgeOwnedSheet(sheet) {
|
|
27
|
+
const owner = sheet.ownerNode;
|
|
28
|
+
return owner instanceof Element && owner.hasAttribute("data-nudge-ui");
|
|
29
|
+
}
|
|
30
|
+
function sheetId(sheet, index, base) {
|
|
31
|
+
const owner = sheet.ownerNode;
|
|
32
|
+
const viteId = owner instanceof HTMLElement ? owner.dataset.viteDevId : undefined;
|
|
33
|
+
if (viteId)
|
|
34
|
+
return viteId;
|
|
35
|
+
if (sheet.href) {
|
|
36
|
+
const url = new URL(sheet.href, base);
|
|
37
|
+
return url.origin === new URL(base).origin ? url.pathname : url.href;
|
|
38
|
+
}
|
|
39
|
+
return `inline-style-${index + 1}`;
|
|
40
|
+
}
|
|
41
|
+
function serializeRules(sheet) {
|
|
42
|
+
return Array.from(sheet.cssRules, (rule) => rule.cssText).join("\n");
|
|
43
|
+
}
|
|
44
|
+
async function collectSheet(sheet, index, base) {
|
|
45
|
+
const id = sheetId(sheet, index, base);
|
|
46
|
+
try {
|
|
47
|
+
return { id, content: serializeRules(sheet) };
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
if (!sheet.href)
|
|
51
|
+
return { id, readError: "stylesheet rules are not readable" };
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const response = await fetch(sheet.href, { mode: "cors", credentials: "omit" });
|
|
55
|
+
if (!response.ok)
|
|
56
|
+
return { id, readError: `HTTP ${response.status}` };
|
|
57
|
+
return { id, content: await response.text() };
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return { id, readError: "cross-origin stylesheet without CORS access" };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Custom properties visible on the root element but absent from readable
|
|
65
|
+
* stylesheets: definitions in cross-origin sheets without CORS, scoped theme
|
|
66
|
+
* rules the inventory rejects, or variables set from JavaScript.
|
|
67
|
+
*/
|
|
68
|
+
function computedRootDeclarations(doc, definedNames) {
|
|
69
|
+
const declarations = [];
|
|
70
|
+
const view = doc.defaultView ?? window;
|
|
71
|
+
for (const element of [doc.documentElement, doc.body]) {
|
|
72
|
+
if (!element)
|
|
73
|
+
continue;
|
|
74
|
+
const style = view.getComputedStyle(element);
|
|
75
|
+
for (let index = 0; index < style.length; index += 1) {
|
|
76
|
+
const name = style.item(index);
|
|
77
|
+
if (!name.startsWith("--") || definedNames.has(name))
|
|
78
|
+
continue;
|
|
79
|
+
const value = style.getPropertyValue(name).trim();
|
|
80
|
+
if (!value)
|
|
81
|
+
continue;
|
|
82
|
+
definedNames.add(name);
|
|
83
|
+
declarations.push(` ${name}: ${value};`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return declarations.length > 0 ? `:root {\n${declarations.join("\n")}\n}` : null;
|
|
87
|
+
}
|
|
88
|
+
function mapDiagnostic(diagnostic) {
|
|
89
|
+
return {
|
|
90
|
+
code: diagnostic.code,
|
|
91
|
+
message: diagnostic.message,
|
|
92
|
+
module: diagnostic.module ?? diagnostic.artifact ?? "document",
|
|
93
|
+
...(diagnostic.exportName !== undefined ? { exportName: diagnostic.exportName } : {}),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
async function collectDocumentTokens(doc) {
|
|
97
|
+
const sheets = Array.from(doc.styleSheets).filter((sheet) => !isNudgeOwnedSheet(sheet));
|
|
98
|
+
const collected = await Promise.all(sheets.map((sheet, index) => collectSheet(sheet, index, doc.location.href)));
|
|
99
|
+
const inventory = createTokenInventory();
|
|
100
|
+
for (const [order, sheet] of collected.entries()) {
|
|
101
|
+
const artifact = {
|
|
102
|
+
buildTool: "browser",
|
|
103
|
+
id: sheet.id,
|
|
104
|
+
stage: "authored",
|
|
105
|
+
provenance: "project",
|
|
106
|
+
order,
|
|
107
|
+
...(sheet.content !== undefined ? { content: sheet.content } : {}),
|
|
108
|
+
...(sheet.readError ? {
|
|
109
|
+
diagnostics: [{
|
|
110
|
+
code: "stylesheet-unreadable",
|
|
111
|
+
message: `Stylesheet "${sheet.id}" could not be read: ${sheet.readError}`,
|
|
112
|
+
module: sheet.id,
|
|
113
|
+
}],
|
|
114
|
+
} : {}),
|
|
115
|
+
};
|
|
116
|
+
inventory.apply(artifact);
|
|
117
|
+
}
|
|
118
|
+
const definedNames = new Set(inventory.snapshot().definitions.map((definition) => definition.cssName));
|
|
119
|
+
const computed = computedRootDeclarations(doc, definedNames);
|
|
120
|
+
if (computed) {
|
|
121
|
+
inventory.apply({
|
|
122
|
+
buildTool: "browser",
|
|
123
|
+
id: COMPUTED_ROOT_ID,
|
|
124
|
+
stage: "authored",
|
|
125
|
+
provenance: "project",
|
|
126
|
+
order: -1,
|
|
127
|
+
content: computed,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
const snapshot = inventory.snapshot();
|
|
131
|
+
return {
|
|
132
|
+
tokenCatalog: snapshot.definitions.map((definition) => ({
|
|
133
|
+
...definition,
|
|
134
|
+
declarations: definition.declarations.map((declaration) => ({
|
|
135
|
+
id: declaration.id,
|
|
136
|
+
order: declaration.order,
|
|
137
|
+
value: declaration.value,
|
|
138
|
+
source: declaration.source,
|
|
139
|
+
important: declaration.important,
|
|
140
|
+
context: declaration.context,
|
|
141
|
+
})),
|
|
142
|
+
})),
|
|
143
|
+
tokens: snapshot.tokens,
|
|
144
|
+
tokenDiagnostics: snapshot.diagnostics.map(mapDiagnostic),
|
|
145
|
+
tokenGeneration: `browser:${snapshot.generation}`,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
const NO_TOKENS = { tokenCatalog: [], tokens: [], tokenDiagnostics: [], tokenGeneration: "" };
|
|
149
|
+
function runtimeConfig(tokens, unavailableReason) {
|
|
150
|
+
return {
|
|
151
|
+
projectId: `page:${location.origin}`,
|
|
152
|
+
host: "static-html",
|
|
153
|
+
framework: "HTML",
|
|
154
|
+
stylingSystem: "CSS custom properties",
|
|
155
|
+
capabilities: { canvas: !unavailableReason, componentSemantics: false, domNavigation: !unavailableReason },
|
|
156
|
+
features: { canvasIterations: false, ...(unavailableReason ? { sketch: false } : {}) },
|
|
157
|
+
...(unavailableReason ? { inspectionUnavailableReason: unavailableReason } : {}),
|
|
158
|
+
componentContracts: [],
|
|
159
|
+
...tokens,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function createMount() {
|
|
163
|
+
const mount = document.createElement("div");
|
|
164
|
+
mount.id = MOUNT_ID;
|
|
165
|
+
document.body.append(mount);
|
|
166
|
+
return mount;
|
|
167
|
+
}
|
|
168
|
+
/** Mounts the inspector and returns a toggle that fully unmounts and remounts it. */
|
|
169
|
+
function mountPageInspector() {
|
|
170
|
+
let mount = null;
|
|
171
|
+
let removeIdentityListeners = null;
|
|
172
|
+
const enable = () => {
|
|
173
|
+
setNudgeUiHostDevFlag(true);
|
|
174
|
+
removeIdentityListeners = installLazyRuntimeIdentity(document);
|
|
175
|
+
mount = createMount();
|
|
176
|
+
bootstrapNudgeUi(mount);
|
|
177
|
+
setInspectorOpen(true);
|
|
178
|
+
};
|
|
179
|
+
const disable = (target) => {
|
|
180
|
+
unmountInspector();
|
|
181
|
+
removeIdentityListeners?.();
|
|
182
|
+
removeIdentityListeners = null;
|
|
183
|
+
releaseLease();
|
|
184
|
+
setInspectorOpen(false);
|
|
185
|
+
setNudgeUiHostDevFlag(false);
|
|
186
|
+
target.remove();
|
|
187
|
+
mount = null;
|
|
188
|
+
};
|
|
189
|
+
enable();
|
|
190
|
+
return () => {
|
|
191
|
+
if (mount)
|
|
192
|
+
disable(mount);
|
|
193
|
+
else
|
|
194
|
+
enable();
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Replaces the page's content with the iframe editor. The application runs in
|
|
199
|
+
* Canvas renderer frames, which the caller loads the inspector into.
|
|
200
|
+
*/
|
|
201
|
+
function mountEditor(onRendererFrameLoad) {
|
|
202
|
+
document.head.replaceChildren();
|
|
203
|
+
document.body.replaceChildren();
|
|
204
|
+
for (const element of [document.documentElement, document.body]) {
|
|
205
|
+
element.removeAttribute("style");
|
|
206
|
+
element.removeAttribute("hidden");
|
|
207
|
+
element.removeAttribute("inert");
|
|
208
|
+
}
|
|
209
|
+
document.title = "Nudge UI";
|
|
210
|
+
const layout = new CSSStyleSheet();
|
|
211
|
+
layout.replaceSync(`html, body, #${MOUNT_ID} { display: block; width: 100%; height: 100%; margin: 0; overflow: hidden; }`);
|
|
212
|
+
document.adoptedStyleSheets = [layout];
|
|
213
|
+
// A parsed meta policy remains active even after the original head is removed.
|
|
214
|
+
document.addEventListener("securitypolicyviolation", (event) => {
|
|
215
|
+
if (event.disposition !== "enforce" || event.effectiveDirective !== "frame-src")
|
|
216
|
+
return;
|
|
217
|
+
if (getNudgeUiRuntimeConfig().inspectionUnavailableReason)
|
|
218
|
+
return;
|
|
219
|
+
configureNudgeUiRuntime(runtimeConfig(NO_TOKENS, "its security policy"));
|
|
220
|
+
});
|
|
221
|
+
setNudgeUiHostDevFlag(true);
|
|
222
|
+
const mount = createMount();
|
|
223
|
+
bootstrapNudgeUi(mount);
|
|
224
|
+
setInspectorOpen(true);
|
|
225
|
+
// Storage hydration can delay the controller mount; watch its host now.
|
|
226
|
+
const root = mount.shadowRoot ?? mount.attachShadow({ mode: "open" });
|
|
227
|
+
const frames = () => root.querySelectorAll(`iframe[${CANVAS_RENDERER_ATTR}]`);
|
|
228
|
+
const applicationDocument = (frame) => {
|
|
229
|
+
const frameDocument = frame.contentDocument;
|
|
230
|
+
return frameDocument && frameDocument.location.href !== "about:blank" ? frameDocument : null;
|
|
231
|
+
};
|
|
232
|
+
// A frame's `load` waits for every image, so renderers start once the DOM is ready.
|
|
233
|
+
const announced = new WeakSet();
|
|
234
|
+
const announceReadyDocuments = () => {
|
|
235
|
+
for (const frame of frames()) {
|
|
236
|
+
const frameDocument = applicationDocument(frame);
|
|
237
|
+
if (!frameDocument || frameDocument.readyState === "loading" || announced.has(frameDocument))
|
|
238
|
+
continue;
|
|
239
|
+
announced.add(frameDocument);
|
|
240
|
+
onRendererFrameLoad?.();
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
window.setInterval(announceReadyDocuments, 100);
|
|
244
|
+
// Script-built styles exist only in the application frames, not in this document.
|
|
245
|
+
const collectFrameTokens = (frame) => {
|
|
246
|
+
const frameDocument = applicationDocument(frame);
|
|
247
|
+
if (!frameDocument)
|
|
248
|
+
return;
|
|
249
|
+
void collectDocumentTokens(frameDocument).then((tokens) => {
|
|
250
|
+
if (getNudgeUiRuntimeConfig().inspectionUnavailableReason)
|
|
251
|
+
return;
|
|
252
|
+
if (tokens.tokenGeneration !== getNudgeUiRuntimeConfig().tokenGeneration) {
|
|
253
|
+
configureNudgeUiRuntime(runtimeConfig(tokens));
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
};
|
|
257
|
+
const watched = new WeakSet();
|
|
258
|
+
const watch = () => {
|
|
259
|
+
for (const frame of frames()) {
|
|
260
|
+
if (watched.has(frame))
|
|
261
|
+
continue;
|
|
262
|
+
watched.add(frame);
|
|
263
|
+
frame.addEventListener("load", () => collectFrameTokens(frame));
|
|
264
|
+
collectFrameTokens(frame);
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
new MutationObserver(watch).observe(root, { childList: true, subtree: true });
|
|
268
|
+
watch();
|
|
269
|
+
}
|
|
270
|
+
/** Leaves the editor by loading the application URL it frames. */
|
|
271
|
+
function exitEditor() {
|
|
272
|
+
location.replace(readNudgeUiEditorTarget(location.href) ?? location.href);
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Starts the inspector on the current page. Running a second bundle copy in
|
|
276
|
+
* the same window toggles the first instance instead, because only the first
|
|
277
|
+
* copy's stores drive the UI.
|
|
278
|
+
*/
|
|
279
|
+
export async function startPageInspector(options = {}) {
|
|
280
|
+
const target = window;
|
|
281
|
+
const loaded = target[LOADED_FLAG];
|
|
282
|
+
if (loaded) {
|
|
283
|
+
loaded.toggle();
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
const editor = options.surface === "editor" && readNudgeUiEditorTarget(location.href) !== null;
|
|
287
|
+
let toggle = editor ? exitEditor : null;
|
|
288
|
+
target[LOADED_FLAG] = {
|
|
289
|
+
surface: editor ? "editor" : "page",
|
|
290
|
+
toggle: () => toggle?.(),
|
|
291
|
+
enablePerformanceDiagnostics: () => enableInspectionPerformanceDiagnostics(document),
|
|
292
|
+
};
|
|
293
|
+
if (options.storage)
|
|
294
|
+
configureInspectorStorage(options.storage);
|
|
295
|
+
if (options.sketchStorage)
|
|
296
|
+
configureSketchStorage(options.sketchStorage);
|
|
297
|
+
if (options.adoptStylesheets)
|
|
298
|
+
preferAdoptedStylesheets();
|
|
299
|
+
const tokens = options.unavailableReason ? NO_TOKENS : await collectDocumentTokens(document);
|
|
300
|
+
configureNudgeUiRuntime(runtimeConfig(tokens, options.unavailableReason));
|
|
301
|
+
if (editor) {
|
|
302
|
+
mountEditor(options.onRendererFrameLoad);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
if (!options.unavailableReason)
|
|
306
|
+
enablePageSurface();
|
|
307
|
+
toggle = mountPageInspector();
|
|
308
|
+
}
|
|
309
|
+
console.info(`[nudge-ui] Inspector loaded in ${editor ? "editor" : "page"} mode with ${tokens.tokenCatalog.length} tokens`
|
|
310
|
+
+ (tokens.tokenDiagnostics.length > 0 ? ` and ${tokens.tokenDiagnostics.length} stylesheet diagnostics.` : "."), tokens.tokenDiagnostics);
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Starts the renderer in an editor's Canvas frame. Does nothing in any other
|
|
314
|
+
* document, or when the frame already runs one.
|
|
315
|
+
*/
|
|
316
|
+
export function startCanvasRenderer(options = {}) {
|
|
317
|
+
const target = window;
|
|
318
|
+
if (!isCanvasRenderer() || target[LOADED_FLAG])
|
|
319
|
+
return;
|
|
320
|
+
target[LOADED_FLAG] = {
|
|
321
|
+
surface: "renderer",
|
|
322
|
+
toggle: () => undefined,
|
|
323
|
+
enablePerformanceDiagnostics: () => enableInspectionPerformanceDiagnostics(document),
|
|
324
|
+
};
|
|
325
|
+
if (options.adoptStylesheets)
|
|
326
|
+
preferAdoptedStylesheets();
|
|
327
|
+
setNudgeUiHostDevFlag(true);
|
|
328
|
+
installLazyRuntimeIdentity(document);
|
|
329
|
+
configureNudgeUiRuntime(runtimeConfig(NO_TOKENS));
|
|
330
|
+
bootstrapNudgeUi(createMount());
|
|
331
|
+
// Renderers inspect their own elements, so they need this document's tokens.
|
|
332
|
+
const collectTokens = () => {
|
|
333
|
+
void collectDocumentTokens(document).then((tokens) => {
|
|
334
|
+
if (tokens.tokenGeneration !== getNudgeUiRuntimeConfig().tokenGeneration) {
|
|
335
|
+
configureNudgeUiRuntime(runtimeConfig(tokens));
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
};
|
|
339
|
+
collectTokens();
|
|
340
|
+
if (document.readyState !== "complete")
|
|
341
|
+
window.addEventListener("load", collectTokens, { once: true });
|
|
342
|
+
}
|
|
@@ -3,7 +3,8 @@ import type { RenderedInstanceOverride } from "../changes/editModel.js";
|
|
|
3
3
|
import { type StructuralChange } from "./structuralProjection.js";
|
|
4
4
|
import type { ComponentOverride } from "../componentSemantics/types.js";
|
|
5
5
|
import { type TextContentChangeRecord } from "../changes/types.js";
|
|
6
|
-
import type { DraftContents } from "../
|
|
6
|
+
import type { DraftContents } from "../drafts/model.js";
|
|
7
|
+
import { type RuntimeIdentityClaim } from "../runtime/runtimeIdentityClaims.js";
|
|
7
8
|
export interface DraftProjectionSource extends DraftContents {
|
|
8
9
|
readonly revision: number;
|
|
9
10
|
}
|
|
@@ -22,9 +23,15 @@ export interface DraftProjectionPlan<ManagedStyles> {
|
|
|
22
23
|
readonly structuralChanges: readonly StructuralChange[];
|
|
23
24
|
readonly textContentChanges: readonly TextContentChangeRecord[];
|
|
24
25
|
readonly componentOverrides: readonly ComponentOverride[];
|
|
26
|
+
/**
|
|
27
|
+
* Generated identities the saved edits refer to. Omitted by plans that
|
|
28
|
+
* only hide edits (hold-to-view-original), which keep the attached ones.
|
|
29
|
+
*/
|
|
30
|
+
readonly runtimeIdentities?: readonly RuntimeIdentityClaim[];
|
|
25
31
|
}
|
|
26
32
|
/** Applies every projection dimension to one document-local runtime. */
|
|
27
33
|
export interface DocumentProjectionAdapter<ManagedStyles> {
|
|
34
|
+
applyRuntimeIdentities(claims: readonly RuntimeIdentityClaim[]): void;
|
|
28
35
|
applyStructural(changes: readonly StructuralChange[]): void;
|
|
29
36
|
applyRenderedInstances(overrides: readonly RenderedInstanceOverride[]): void;
|
|
30
37
|
applyText(changes: readonly TextContentChangeRecord[]): void;
|
|
@@ -35,7 +42,8 @@ export declare function compileDraftProjection(snapshot: DraftProjectionSource):
|
|
|
35
42
|
/**
|
|
36
43
|
* Replaces one document projection in the required order.
|
|
37
44
|
*
|
|
38
|
-
*
|
|
45
|
+
* Generated identities are attached first: every selector and resolver below
|
|
46
|
+
* looks elements up by them. Structural intent follows because later rendered-instance evidence
|
|
39
47
|
* can depend on the restored element order. Managed CSS is applied last so
|
|
40
48
|
* selectors can use the document-local instance markers installed above.
|
|
41
49
|
*/
|
|
@@ -6,6 +6,7 @@ import { replaceComponentOverrideProjection } from "../componentSemantics/index.
|
|
|
6
6
|
import { componentChangeToOverride } from "../componentSemantics/changeModel.js";
|
|
7
7
|
import { isComponentChange } from "../changes/types.js";
|
|
8
8
|
import { buildManagedStyleRules } from "../changes/managedStyleProjection.js";
|
|
9
|
+
import { applyRuntimeIdentityClaims, collectRuntimeIdentityClaims, } from "../runtime/runtimeIdentityClaims.js";
|
|
9
10
|
export function compileDraftProjection(snapshot) {
|
|
10
11
|
const changes = [...snapshot.changes];
|
|
11
12
|
const rules = buildManagedStyleRules(changes);
|
|
@@ -22,16 +23,20 @@ export function compileDraftProjection(snapshot) {
|
|
|
22
23
|
.filter(isComponentChange)
|
|
23
24
|
.map(componentChangeToOverride)
|
|
24
25
|
.filter((override) => override !== null),
|
|
26
|
+
runtimeIdentities: collectRuntimeIdentityClaims(snapshot),
|
|
25
27
|
};
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
30
|
* Replaces one document projection in the required order.
|
|
29
31
|
*
|
|
30
|
-
*
|
|
32
|
+
* Generated identities are attached first: every selector and resolver below
|
|
33
|
+
* looks elements up by them. Structural intent follows because later rendered-instance evidence
|
|
31
34
|
* can depend on the restored element order. Managed CSS is applied last so
|
|
32
35
|
* selectors can use the document-local instance markers installed above.
|
|
33
36
|
*/
|
|
34
37
|
export function applyDraftProjection(adapter, plan) {
|
|
38
|
+
if (plan.runtimeIdentities)
|
|
39
|
+
adapter.applyRuntimeIdentities(plan.runtimeIdentities);
|
|
35
40
|
adapter.applyStructural(plan.structuralChanges);
|
|
36
41
|
adapter.applyRenderedInstances(plan.instanceOverrides);
|
|
37
42
|
adapter.applyText(plan.textContentChanges);
|
|
@@ -39,6 +44,9 @@ export function applyDraftProjection(adapter, plan) {
|
|
|
39
44
|
adapter.applyManagedStyles(plan.managedStyles);
|
|
40
45
|
}
|
|
41
46
|
const hostDocumentProjectionAdapter = {
|
|
47
|
+
applyRuntimeIdentities: (claims) => {
|
|
48
|
+
applyRuntimeIdentityClaims(document, claims);
|
|
49
|
+
},
|
|
42
50
|
applyStructural: (changes) => {
|
|
43
51
|
applyStructuralProjection(document, changes);
|
|
44
52
|
},
|
|
@@ -2,6 +2,7 @@ import { getElementComputedStyle } from "../runtime/domRealm.js";
|
|
|
2
2
|
import { notifyBrowserStylesheetChange } from "../inspection/browserCssInspectionRegistry.js";
|
|
3
3
|
import { escapeAttrValue, escapeCssString } from "./cssEscapes.js";
|
|
4
4
|
import { isNudgeUiDev } from "../runtime/devFlag.js";
|
|
5
|
+
import { adoptStylesheet, allowsStyleElements, releaseAdoptedStylesheet } from "../runtime/ownedStylesheets.js";
|
|
5
6
|
export { escapeAttrValue, escapeCssString } from "./cssEscapes.js";
|
|
6
7
|
const SHEET_ID = "nudge-ui-styles";
|
|
7
8
|
let managedHeadGuardDocument = null;
|
|
@@ -25,6 +26,12 @@ function installManagedHeadGuard(doc) {
|
|
|
25
26
|
}
|
|
26
27
|
export function ensureManagedSheet() {
|
|
27
28
|
const doc = document;
|
|
29
|
+
if (!allowsStyleElements(doc)) {
|
|
30
|
+
// Adopted sheets already cascade after every document stylesheet.
|
|
31
|
+
adoptStylesheet(doc, SHEET_ID, rulesToCssText(managedRules));
|
|
32
|
+
exposeManagedSheetText(doc);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
28
35
|
// SAFETY: getElementById returns an Element; the managed style element is created as HTMLStyleElement when missing.
|
|
29
36
|
let el = doc.getElementById(SHEET_ID);
|
|
30
37
|
if (!el) {
|
|
@@ -53,6 +60,9 @@ export function ensureManagedSheet() {
|
|
|
53
60
|
rehydrateManagedSheet(doc, el);
|
|
54
61
|
}
|
|
55
62
|
installManagedHeadGuard(doc);
|
|
63
|
+
exposeManagedSheetText(doc);
|
|
64
|
+
}
|
|
65
|
+
function exposeManagedSheetText(doc) {
|
|
56
66
|
if (isNudgeUiDev() && doc.defaultView) {
|
|
57
67
|
// Keep the canonical CSS available to dev diagnostics.
|
|
58
68
|
doc.defaultView.__nudgeUiGetManagedSheetText = getManagedSheetText;
|
|
@@ -125,15 +135,24 @@ function rehydrateManagedSheet(doc, el) {
|
|
|
125
135
|
* copy for rehydration if a framework moves or reparses that element.
|
|
126
136
|
*/
|
|
127
137
|
function rebuildSheetText(rules) {
|
|
128
|
-
// SAFETY: getElementById returns an Element; the managed style element is created as HTMLStyleElement when missing.
|
|
129
|
-
const el = document.getElementById(SHEET_ID);
|
|
130
|
-
if (!el)
|
|
131
|
-
return;
|
|
132
138
|
const desired = rules.map((rule) => ({
|
|
133
139
|
...rule,
|
|
134
140
|
declarations: { ...rule.declarations },
|
|
135
141
|
}));
|
|
136
142
|
const cssText = rulesToCssText(desired);
|
|
143
|
+
if (!allowsStyleElements(document)) {
|
|
144
|
+
const rulesChanged = rulesToCssText(managedRules) !== cssText;
|
|
145
|
+
managedRules = desired;
|
|
146
|
+
if (!rulesChanged)
|
|
147
|
+
return;
|
|
148
|
+
adoptStylesheet(document, SHEET_ID, cssText);
|
|
149
|
+
notifyBrowserStylesheetChange(document);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
// SAFETY: getElementById returns an Element; the managed style element is created as HTMLStyleElement when missing.
|
|
153
|
+
const el = document.getElementById(SHEET_ID);
|
|
154
|
+
if (!el)
|
|
155
|
+
return;
|
|
137
156
|
const rulesChanged = rulesToCssText(managedRules) !== cssText;
|
|
138
157
|
const shouldRetryDroppedRules = el.sheet !== null
|
|
139
158
|
&& el.sheet.cssRules.length !== desired.length
|
|
@@ -237,6 +256,7 @@ export function removeManagedSheet() {
|
|
|
237
256
|
const el = document.getElementById(SHEET_ID);
|
|
238
257
|
if (el)
|
|
239
258
|
el.remove();
|
|
259
|
+
releaseAdoptedStylesheet(document, SHEET_ID);
|
|
240
260
|
managedRules = [];
|
|
241
261
|
failedRehydrationCssText = null;
|
|
242
262
|
notifyBrowserStylesheetChange(document);
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { getActiveDraftChanges, getDraftChanges } from "../
|
|
1
|
+
import { getActiveDraftChanges, getDraftChanges } from "../drafts/store.js";
|
|
2
2
|
import { inspectRootInvocations } from "../componentSemantics/adapterRegistry.js";
|
|
3
3
|
import { escapeAttrValue } from "./cssEscapes.js";
|
|
4
4
|
import { isNudgeUiDev } from "../runtime/devFlag.js";
|
|
5
5
|
import { relocateSourceSite, sourceSiteSelector } from "../selection/sourceSite.js";
|
|
6
6
|
import { isRenderedInstanceOverride } from "../changes/editModel.js";
|
|
7
|
+
import { boundRuntimeEvidence, isRuntimeGeneratedSource, normalizeRuntimeTag, runtimeDomPath } from "../runtime/staticHtmlRuntimeIdentity.js";
|
|
7
8
|
export { isRenderedInstanceOverride, isRenderedInstanceRef } from "../changes/editModel.js";
|
|
8
9
|
const PROJECTION_ATTR = "data-projection-instance";
|
|
9
10
|
let nextOverrideId = 1;
|
|
@@ -45,6 +46,11 @@ export function captureRenderedInstance(el) {
|
|
|
45
46
|
props: el.getAttribute("data-cprops"),
|
|
46
47
|
text: normalizedText(el),
|
|
47
48
|
ariaLabel: el.getAttribute("aria-label"),
|
|
49
|
+
...(isRuntimeGeneratedSource(src) ? {
|
|
50
|
+
tagName: normalizeRuntimeTag(el.tagName),
|
|
51
|
+
domPath: runtimeDomPath(el),
|
|
52
|
+
elementId: boundRuntimeEvidence(el.id || null),
|
|
53
|
+
} : {}),
|
|
48
54
|
},
|
|
49
55
|
};
|
|
50
56
|
}
|
|
@@ -47,15 +47,6 @@ export declare function getStructuralChanges(): readonly StructuralChange[];
|
|
|
47
47
|
export declare function getStructuralDeletes(): readonly StructuralDelete[];
|
|
48
48
|
/** Revert removes one canonical intent and leaves every other intent intact. */
|
|
49
49
|
export declare function revertStructuralChange(changeId: string): boolean;
|
|
50
|
-
/**
|
|
51
|
-
* Removes source-verified structural intents without leaving an undo path that
|
|
52
|
-
* can recreate their browser-only previews.
|
|
53
|
-
*
|
|
54
|
-
* Agent completion can verify a subset of one dispatched snapshot. The
|
|
55
|
-
* remaining records and their useful history stay intact while every verified
|
|
56
|
-
* ID is pruned from canonical state, undo/redo snapshots, and Canvas reports.
|
|
57
|
-
*/
|
|
58
|
-
export declare function reconcileVerifiedStructuralChanges(verifiedIds: ReadonlySet<string>): number;
|
|
59
50
|
/** State changes drive controller-to-renderer projection. Diagnostics do not. */
|
|
60
51
|
export declare function subscribeStructuralChanges(listener: () => void): () => void;
|
|
61
52
|
/** Compatibility name retained while the controller moved to a full union. */
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { getActiveDraftChanges, getDraftChanges } from "../
|
|
1
|
+
import { commitStructuralChange, getActiveDraftChanges, getDraftChanges, revertStructuralChange as revertDraftStructuralChange, subscribeActiveDraftChanges, } from "../drafts/store.js";
|
|
2
2
|
import { captureRenderedInstance, captureStructuralTarget, matchesRenderedInstanceEvidence, resolveRenderedInstance, } from "./renderedInstance.js";
|
|
3
3
|
import { isStructuralProjectionReport } from "./structuralProjectionBoundary.js";
|
|
4
|
-
import { resetDraftChanges, draftChangeStore, } from "../changes/draftChanges.js";
|
|
5
4
|
export { isStructuralChange, isStructuralDelete, isStructuralMove, isStructuralProjectionReport, } from "./structuralProjectionBoundary.js";
|
|
6
5
|
const VOID_PARENT_TAGS = new Set([
|
|
7
6
|
"area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr",
|
|
@@ -177,8 +176,11 @@ function cloneSnapshot(snapshot) {
|
|
|
177
176
|
// array is enough: no operation mutates a change or its nested references.
|
|
178
177
|
return [...snapshot];
|
|
179
178
|
}
|
|
180
|
-
|
|
181
|
-
|
|
179
|
+
/** The Draft store already re-projected the host; this covers every other known document. */
|
|
180
|
+
function projectStructuralChanges() {
|
|
181
|
+
const changes = getStructuralChanges();
|
|
182
|
+
for (const doc of documentStates.keys())
|
|
183
|
+
applyStructuralProjection(doc, changes);
|
|
182
184
|
}
|
|
183
185
|
/** Captures a delete intent once, in the controller, at the user gesture. */
|
|
184
186
|
export function createStructuralDelete(element, id = structuralId()) {
|
|
@@ -194,9 +196,9 @@ export function createStructuralDelete(element, id = structuralId()) {
|
|
|
194
196
|
...(route ? { route } : {}),
|
|
195
197
|
...(state ? { state } : {}),
|
|
196
198
|
};
|
|
197
|
-
if (!
|
|
199
|
+
if (!commitStructuralChange(change))
|
|
198
200
|
return null;
|
|
199
|
-
projectStructuralChanges(
|
|
201
|
+
projectStructuralChanges();
|
|
200
202
|
return change;
|
|
201
203
|
}
|
|
202
204
|
/**
|
|
@@ -237,51 +239,27 @@ export function createStructuralMove(element, destination, id = structuralId())
|
|
|
237
239
|
: destinationChildren.length - (sameParent ? 1 : 0),
|
|
238
240
|
},
|
|
239
241
|
};
|
|
240
|
-
if (!
|
|
242
|
+
if (!commitStructuralChange(change))
|
|
241
243
|
return null;
|
|
242
|
-
projectStructuralChanges(
|
|
244
|
+
projectStructuralChanges();
|
|
243
245
|
return change;
|
|
244
246
|
}
|
|
245
247
|
export function getStructuralChanges() {
|
|
246
|
-
return
|
|
248
|
+
return getActiveDraftChanges().structuralChanges;
|
|
247
249
|
}
|
|
248
250
|
export function getStructuralDeletes() {
|
|
249
251
|
return getStructuralChanges().filter((change) => change.kind === "delete");
|
|
250
252
|
}
|
|
251
253
|
/** Revert removes one canonical intent and leaves every other intent intact. */
|
|
252
254
|
export function revertStructuralChange(changeId) {
|
|
253
|
-
const changed =
|
|
255
|
+
const changed = revertDraftStructuralChange(changeId);
|
|
254
256
|
if (changed)
|
|
255
|
-
projectStructuralChanges(
|
|
257
|
+
projectStructuralChanges();
|
|
256
258
|
return changed;
|
|
257
259
|
}
|
|
258
|
-
/**
|
|
259
|
-
* Removes source-verified structural intents without leaving an undo path that
|
|
260
|
-
* can recreate their browser-only previews.
|
|
261
|
-
*
|
|
262
|
-
* Agent completion can verify a subset of one dispatched snapshot. The
|
|
263
|
-
* remaining records and their useful history stay intact while every verified
|
|
264
|
-
* ID is pruned from canonical state, undo/redo snapshots, and Canvas reports.
|
|
265
|
-
*/
|
|
266
|
-
export function reconcileVerifiedStructuralChanges(verifiedIds) {
|
|
267
|
-
if (verifiedIds.size === 0)
|
|
268
|
-
return 0;
|
|
269
|
-
const removed = draftChangeStore.reconcileActiveDraftChanges(new Set(), verifiedIds);
|
|
270
|
-
if (removed === 0)
|
|
271
|
-
return 0;
|
|
272
|
-
projectStructuralChanges(draftChangeStore.getSnapshot());
|
|
273
|
-
for (const [cardId, canvasReports] of reportsByCanvasCard) {
|
|
274
|
-
reportsByCanvasCard.set(cardId, {
|
|
275
|
-
...canvasReports,
|
|
276
|
-
reports: canvasReports.reports.filter((report) => !verifiedIds.has(report.changeId)),
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
|
-
notifyDiagnostics();
|
|
280
|
-
return removed;
|
|
281
|
-
}
|
|
282
260
|
/** State changes drive controller-to-renderer projection. Diagnostics do not. */
|
|
283
261
|
export function subscribeStructuralChanges(listener) {
|
|
284
|
-
return
|
|
262
|
+
return subscribeActiveDraftChanges(listener);
|
|
285
263
|
}
|
|
286
264
|
/** Compatibility name retained while the controller moved to a full union. */
|
|
287
265
|
export const subscribeStructuralDeletes = subscribeStructuralChanges;
|
|
@@ -503,13 +481,6 @@ function validationStatus(local) {
|
|
|
503
481
|
? "applied"
|
|
504
482
|
: "overridden";
|
|
505
483
|
}
|
|
506
|
-
/** Rebuild already-mounted document adapters from canonical data only. */
|
|
507
|
-
function reprojectKnownDocuments(changes = getStructuralChanges()) {
|
|
508
|
-
for (const [doc, state] of documentStates) {
|
|
509
|
-
rebuildForSnapshot(doc, state, changes);
|
|
510
|
-
storeReports(doc, reportsForSnapshot(state, state.snapshot));
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
484
|
function validateAppliedPreview(doc, state) {
|
|
514
485
|
let changed = false;
|
|
515
486
|
for (const local of state.applied.values()) {
|
|
@@ -619,7 +590,6 @@ export function resetStructuralDeleteProjection() {
|
|
|
619
590
|
reportsByCanvasCard.clear();
|
|
620
591
|
nextStructuralId = 1;
|
|
621
592
|
diagnosticRevision = 0;
|
|
622
|
-
resetDraftChanges();
|
|
623
593
|
notifyDiagnostics();
|
|
624
594
|
}
|
|
625
595
|
/**
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { FrameProjection } from "../canvas/projection.js";
|
|
2
|
-
import { isTextProjectionTargetValue, type TextContentChangeRecord, type TextProjectionTarget, type TextProjectionScope, type TextBindingEvidence } from "../
|
|
2
|
+
import { isTextProjectionTargetValue, type TextContentChangeRecord, type TextProjectionTarget, type TextProjectionScope, type TextBindingEvidence } from "../changes/editModel.js";
|
|
3
3
|
/** Strict JSON boundary guard for a text projection target. */
|
|
4
4
|
export declare const isTextProjectionTarget: typeof isTextProjectionTargetValue;
|
|
5
|
-
export type { TextProjectionTarget } from "../
|
|
5
|
+
export type { TextProjectionTarget } from "../changes/editModel.js";
|
|
6
6
|
export type TextProjectionStatus = "applied" | "missing" | "ambiguous" | "overridden";
|
|
7
7
|
export interface TextProjectionReport {
|
|
8
8
|
changeId: string;
|
|
@@ -30,6 +30,12 @@ export type TextProjectionResolution = {
|
|
|
30
30
|
/** Find the exact text node represented by a target, tolerating a changed
|
|
31
31
|
* child path only when one bounded before/after text node remains unique. */
|
|
32
32
|
export declare function resolveTextProjectionTextNode(element: HTMLElement, target: Pick<TextProjectionTarget, "textNodePath"> & Partial<Pick<TextProjectionTarget, "beforeText">>, expectedText?: string | undefined): Text | null;
|
|
33
|
+
/** Whether an element's text is code, form state, or other non-prose content. */
|
|
34
|
+
export declare function isUnsafeTextHost(element: Element): boolean;
|
|
35
|
+
/** Whether an application-owned editing region contains the element. */
|
|
36
|
+
export declare function isInApplicationEditingHost(element: Element): boolean;
|
|
37
|
+
/** Whether replacing one text node inside the element keeps its authored markup. */
|
|
38
|
+
export declare function hasSafeMixedDescendants(element: HTMLElement): boolean;
|
|
33
39
|
/** Capture stable source/evidence identity without retaining a DOM reference. */
|
|
34
40
|
export declare function captureTextProjectionTarget(element: HTMLElement, beforeText?: string, selectedTextNode?: Text): TextProjectionTarget | null;
|
|
35
41
|
/**
|