nudge-ui 0.2.3 → 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 +870 -212
- 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 +5 -7
- package/dist/inspector/agent/verification.js +67 -20
- 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 +23 -12
- package/dist/inspector/canvas/CanvasElementOverlay.js +97 -128
- package/dist/inspector/canvas/CanvasToolbar.js +2 -1
- package/dist/inspector/canvas/CanvasWorkspace.js +119 -162
- 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/frameScrollbarStyles.d.ts +3 -0
- package/dist/inspector/canvas/frameScrollbarStyles.js +21 -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 +2 -0
- package/dist/inspector/changes/codecs.js +27 -3
- package/dist/inspector/changes/draftPreview.d.ts +12 -0
- package/dist/inspector/changes/draftPreview.js +133 -0
- package/dist/inspector/changes/editModel.d.ts +18 -0
- package/dist/inspector/changes/editModel.js +16 -3
- package/dist/inspector/changes/managedStyleProjection.js +2 -1
- package/dist/inspector/changes/previewDiagnostics.js +1 -1
- package/dist/inspector/changes/types.d.ts +18 -1
- package/dist/inspector/comments/CommentsOverlay.js +18 -16
- package/dist/inspector/comments/element.js +10 -3
- 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/adapterRegistry.d.ts +6 -1
- package/dist/inspector/componentSemantics/adapterRegistry.js +23 -1
- package/dist/inspector/componentSemantics/changeAction.js +1 -1
- package/dist/inspector/componentSemantics/reactRuntime.d.ts +2 -1
- package/dist/inspector/componentSemantics/reactRuntime.js +38 -0
- package/dist/inspector/componentSemantics/runtimeBridge.d.ts +4 -2
- package/dist/inspector/componentSemantics/runtimeBridge.js +17 -0
- package/dist/inspector/componentSemantics/textBinding.d.ts +1 -2
- package/dist/inspector/componentSemantics/textBinding.js +4 -45
- package/dist/inspector/componentSemantics/types.d.ts +11 -0
- 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/capture.js +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.d.ts +15 -2
- package/dist/inspector/projection/renderedInstance.js +60 -7
- package/dist/inspector/projection/structuralProjection.d.ts +0 -9
- package/dist/inspector/projection/structuralProjection.js +16 -46
- package/dist/inspector/projection/textProjection.d.ts +8 -2
- package/dist/inspector/projection/textProjection.js +77 -24
- package/dist/inspector/prompt/clipboardHandoff.d.ts +14 -0
- package/dist/inspector/prompt/clipboardHandoff.js +47 -16
- package/dist/inspector/prompt/generatePrompt.d.ts +1 -1
- package/dist/inspector/prompt/generatePrompt.js +248 -148
- 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/selection/sourceSite.d.ts +12 -0
- package/dist/inspector/selection/sourceSite.js +28 -0
- 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 +74 -26
- 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 +3 -2
- 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 +40 -7
- package/dist/inspector/tokens/TokensPanel.js +2 -1
- package/dist/inspector/tokens/editActions.d.ts +3 -3
- package/dist/inspector/tokens/editActions.js +15 -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 +16 -0
- package/dist/inspector/workspace/sentItems.js +33 -0
- 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 +13 -3
- 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 -47
- package/dist/inspector/changes/changesLog.js +0 -247
- package/dist/inspector/changes/draftChanges.d.ts +0 -56
- package/dist/inspector/changes/draftChanges.js +0 -300
- 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);
|
|
@@ -23,10 +23,23 @@ export declare function captureRenderedInstance(el: HTMLElement): RenderedInstan
|
|
|
23
23
|
/**
|
|
24
24
|
* Resolves exactly one element, or declines to apply. Occurrence documents the
|
|
25
25
|
* captured placement, but structural previews can legitimately change it.
|
|
26
|
-
* Evidence
|
|
27
|
-
* be applied.
|
|
26
|
+
* Evidence, narrowed by a recorded invocation when present, must therefore
|
|
27
|
+
* identify one current candidate before an edit can be applied.
|
|
28
28
|
*/
|
|
29
29
|
export declare function resolveRenderedInstance(doc: Document, ref: RenderedInstanceRef): ResolutionResult;
|
|
30
|
+
/**
|
|
31
|
+
* Resolves a reference whose source position may have moved since capture.
|
|
32
|
+
* A relocated site still renders matching authored evidence, so an evidence
|
|
33
|
+
* miss there is reported as ambiguous rather than as proof of absence.
|
|
34
|
+
*/
|
|
35
|
+
export declare function resolveMovedRenderedInstance(doc: Document, ref: RenderedInstanceRef): ResolutionResult;
|
|
36
|
+
/**
|
|
37
|
+
* Captures identity for a structural target. When evidence matches several
|
|
38
|
+
* identical outputs, the nearest component invocation whose entire output is
|
|
39
|
+
* this element can still identify it. Otherwise the evidence-only reference
|
|
40
|
+
* is returned and resolves as ambiguous.
|
|
41
|
+
*/
|
|
42
|
+
export declare function captureStructuralTarget(el: HTMLElement): RenderedInstanceRef | null;
|
|
30
43
|
/** Checks stable source/evidence fields without treating a post-move ordinal as identity. */
|
|
31
44
|
export declare function matchesRenderedInstanceEvidence(el: HTMLElement, ref: RenderedInstanceRef): boolean;
|
|
32
45
|
/** Builds an instance override without changing the element's transient edit scope. */
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { getActiveDraftChanges, getDraftChanges } from "../
|
|
1
|
+
import { getActiveDraftChanges, getDraftChanges } from "../drafts/store.js";
|
|
2
|
+
import { inspectRootInvocations } from "../componentSemantics/adapterRegistry.js";
|
|
2
3
|
import { escapeAttrValue } from "./cssEscapes.js";
|
|
3
4
|
import { isNudgeUiDev } from "../runtime/devFlag.js";
|
|
4
|
-
import { sourceSiteSelector } from "../selection/sourceSite.js";
|
|
5
|
+
import { relocateSourceSite, sourceSiteSelector } from "../selection/sourceSite.js";
|
|
5
6
|
import { isRenderedInstanceOverride } from "../changes/editModel.js";
|
|
7
|
+
import { boundRuntimeEvidence, isRuntimeGeneratedSource, normalizeRuntimeTag, runtimeDomPath } from "../runtime/staticHtmlRuntimeIdentity.js";
|
|
6
8
|
export { isRenderedInstanceOverride, isRenderedInstanceRef } from "../changes/editModel.js";
|
|
7
9
|
const PROJECTION_ATTR = "data-projection-instance";
|
|
8
10
|
let nextOverrideId = 1;
|
|
@@ -44,25 +46,42 @@ export function captureRenderedInstance(el) {
|
|
|
44
46
|
props: el.getAttribute("data-cprops"),
|
|
45
47
|
text: normalizedText(el),
|
|
46
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
|
+
} : {}),
|
|
47
54
|
},
|
|
48
55
|
};
|
|
49
56
|
}
|
|
50
57
|
/**
|
|
51
58
|
* Resolves exactly one element, or declines to apply. Occurrence documents the
|
|
52
59
|
* captured placement, but structural previews can legitimately change it.
|
|
53
|
-
* Evidence
|
|
54
|
-
* be applied.
|
|
60
|
+
* Evidence, narrowed by a recorded invocation when present, must therefore
|
|
61
|
+
* identify one current candidate before an edit can be applied.
|
|
55
62
|
*/
|
|
56
63
|
export function resolveRenderedInstance(doc, ref) {
|
|
57
64
|
const sourceCandidates = candidates(doc, ref.sourceSite);
|
|
58
|
-
const { props, text, ariaLabel = null } = ref.locator;
|
|
65
|
+
const { props, text, ariaLabel = null, invocation } = ref.locator;
|
|
59
66
|
// An ordinal alone is not an identity for a repeated source site.
|
|
60
|
-
if (sourceCandidates.length > 1 && props === null && text === null && ariaLabel === null) {
|
|
67
|
+
if (!invocation && sourceCandidates.length > 1 && props === null && text === null && ariaLabel === null) {
|
|
61
68
|
return { status: "ambiguous" };
|
|
62
69
|
}
|
|
63
|
-
|
|
70
|
+
let matchingEvidence = sourceCandidates.filter((element) => element.getAttribute("data-cprops") === props
|
|
64
71
|
&& normalizedText(element) === text
|
|
65
72
|
&& element.getAttribute("aria-label") === ariaLabel);
|
|
73
|
+
if (invocation) {
|
|
74
|
+
const scoped = [];
|
|
75
|
+
for (const element of matchingEvidence) {
|
|
76
|
+
const invocations = inspectRootInvocations(element);
|
|
77
|
+
// Without readable ancestry, absence of the invocation proves nothing.
|
|
78
|
+
if (invocations === null)
|
|
79
|
+
return { status: "ambiguous" };
|
|
80
|
+
if (invocations.some((candidate) => candidate.callsiteId === invocation.callsiteId))
|
|
81
|
+
scoped.push(element);
|
|
82
|
+
}
|
|
83
|
+
matchingEvidence = scoped;
|
|
84
|
+
}
|
|
66
85
|
if (matchingEvidence.length === 0)
|
|
67
86
|
return { status: "missing" };
|
|
68
87
|
// Evidence alone is never enough to choose between two identical rendered
|
|
@@ -72,6 +91,40 @@ export function resolveRenderedInstance(doc, ref) {
|
|
|
72
91
|
return { status: "ambiguous" };
|
|
73
92
|
return { status: "resolved", element: matchingEvidence[0] };
|
|
74
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Resolves a reference whose source position may have moved since capture.
|
|
96
|
+
* A relocated site still renders matching authored evidence, so an evidence
|
|
97
|
+
* miss there is reported as ambiguous rather than as proof of absence.
|
|
98
|
+
*/
|
|
99
|
+
export function resolveMovedRenderedInstance(doc, ref) {
|
|
100
|
+
const exact = resolveRenderedInstance(doc, ref);
|
|
101
|
+
if (exact.status !== "missing")
|
|
102
|
+
return exact;
|
|
103
|
+
const { props, ariaLabel = null } = ref.locator;
|
|
104
|
+
const sourceSite = relocateSourceSite(doc, ref.sourceSite, (element) => element.getAttribute("data-cprops") === props && element.getAttribute("aria-label") === ariaLabel);
|
|
105
|
+
if (!sourceSite)
|
|
106
|
+
return exact;
|
|
107
|
+
const moved = resolveRenderedInstance(doc, { ...ref, sourceSite });
|
|
108
|
+
return moved.status === "missing" ? { status: "ambiguous" } : moved;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Captures identity for a structural target. When evidence matches several
|
|
112
|
+
* identical outputs, the nearest component invocation whose entire output is
|
|
113
|
+
* this element can still identify it. Otherwise the evidence-only reference
|
|
114
|
+
* is returned and resolves as ambiguous.
|
|
115
|
+
*/
|
|
116
|
+
export function captureStructuralTarget(el) {
|
|
117
|
+
const ref = captureRenderedInstance(el);
|
|
118
|
+
if (!ref || resolveRenderedInstance(el.ownerDocument, ref).status !== "ambiguous")
|
|
119
|
+
return ref;
|
|
120
|
+
for (const invocation of inspectRootInvocations(el) ?? []) {
|
|
121
|
+
const scoped = { ...ref, locator: { ...ref.locator, invocation } };
|
|
122
|
+
const resolved = resolveRenderedInstance(el.ownerDocument, scoped);
|
|
123
|
+
if (resolved.status === "resolved" && resolved.element === el)
|
|
124
|
+
return scoped;
|
|
125
|
+
}
|
|
126
|
+
return ref;
|
|
127
|
+
}
|
|
75
128
|
/** Checks stable source/evidence fields without treating a post-move ordinal as identity. */
|
|
76
129
|
export function matchesRenderedInstanceEvidence(el, ref) {
|
|
77
130
|
const { props, text, ariaLabel = null } = ref.locator;
|
|
@@ -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. */
|