nudge-ui 0.2.0 → 0.2.2
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/bin/nudge-ui.mjs +3 -1
- package/dist/cli/agentCommand.d.ts +8 -0
- package/dist/cli/agentCommand.js +59 -0
- package/dist/client.mjs +878 -11
- package/dist/hosts/astro/astroRuntimeConfig.js +1 -1
- package/dist/hosts/astro/clientTransport.js +63 -11
- package/dist/hosts/astro/integration.d.ts +2 -2
- package/dist/hosts/astro/integration.js +4 -3
- package/dist/hosts/environment.d.ts +15 -0
- package/dist/hosts/environment.js +16 -0
- package/dist/hosts/next/sidecar.d.ts +4 -0
- package/dist/hosts/next/sidecar.js +56 -7
- package/dist/hosts/next/wrapper.d.ts +2 -0
- package/dist/hosts/next/wrapper.js +32 -3
- package/dist/hosts/projectBridge.d.ts +21 -0
- package/dist/hosts/projectBridge.js +98 -0
- package/dist/hosts/static/cli.d.ts +1 -1
- package/dist/hosts/static/cli.js +6 -1
- package/dist/hosts/static/manifest.d.ts +1 -1
- package/dist/hosts/static/manifest.js +3 -1
- package/dist/hosts/static/server.js +45 -3
- package/dist/hosts/vite/vite.d.ts +6 -1
- package/dist/hosts/vite/vite.js +82 -15
- package/dist/inspector/agent/McpConnectionDialog.d.ts +5 -4
- package/dist/inspector/agent/McpConnectionDialog.js +20 -37
- package/dist/inspector/agent/client.d.ts +16 -3
- package/dist/inspector/agent/client.js +114 -11
- package/dist/inspector/agent/connectionStatus.d.ts +3 -3
- package/dist/inspector/agent/connectionStatus.js +11 -4
- package/dist/inspector/agent/httpTransport.d.ts +8 -0
- package/dist/inspector/agent/httpTransport.js +78 -18
- package/dist/inspector/agent/protocol.d.ts +11 -3
- package/dist/inspector/agent/protocol.js +1 -1
- package/dist/inspector/agent/verification.d.ts +1 -1
- package/dist/inspector/agent/verification.js +69 -12
- package/dist/inspector/canvas/CanvasCard.d.ts +5 -3
- package/dist/inspector/canvas/CanvasCard.js +181 -91
- package/dist/inspector/canvas/CanvasElementOverlay.js +288 -52
- package/dist/inspector/canvas/CanvasToolbar.d.ts +12 -0
- package/dist/inspector/canvas/CanvasToolbar.js +24 -0
- package/dist/inspector/canvas/CanvasWorkspace.d.ts +4 -1
- package/dist/inspector/canvas/CanvasWorkspace.js +410 -72
- package/dist/inspector/canvas/activeCanvasDocument.d.ts +5 -0
- package/dist/inspector/canvas/activeCanvasDocument.js +23 -0
- package/dist/inspector/canvas/canvasResize.d.ts +30 -0
- package/dist/inspector/canvas/canvasResize.js +52 -0
- package/dist/inspector/canvas/canvasStore.d.ts +30 -6
- package/dist/inspector/canvas/canvasStore.js +128 -61
- package/dist/inspector/canvas/frameProtocol.d.ts +82 -5
- package/dist/inspector/canvas/frameProtocol.js +63 -2
- package/dist/inspector/canvas/keyboardShortcuts.d.ts +4 -0
- package/dist/inspector/canvas/keyboardShortcuts.js +16 -0
- package/dist/inspector/canvas/linkEligibility.d.ts +0 -5
- package/dist/inspector/canvas/linkEligibility.js +0 -29
- package/dist/inspector/canvas/projection.d.ts +7 -0
- package/dist/inspector/canvas/projection.js +118 -25
- package/dist/inspector/canvas/rendererBootstrap.js +42 -29
- package/dist/inspector/canvas/rendererElementSelector.d.ts +1 -1
- package/dist/inspector/canvas/rendererElementSelector.js +385 -58
- package/dist/inspector/canvas/rendererMessageRouter.d.ts +11 -0
- package/dist/inspector/canvas/rendererMessageRouter.js +43 -0
- package/dist/inspector/canvas/rendererSelectionProxy.js +6 -2
- package/dist/inspector/canvas/sessionStore.d.ts +1 -0
- package/dist/inspector/canvas/sessionStore.js +12 -4
- package/dist/inspector/canvas/staleChangeDetector.js +16 -14
- package/dist/inspector/changes/changesLog.js +31 -1
- package/dist/inspector/changes/managedStyleProjection.d.ts +1 -1
- package/dist/inspector/changes/managedStyleProjection.js +3 -3
- package/dist/inspector/changes/structuralTypes.d.ts +4 -0
- package/dist/inspector/changes/workspaceChanges.d.ts +4 -0
- package/dist/inspector/changes/workspaceChanges.js +29 -3
- package/dist/inspector/clientManifest.d.ts +7 -0
- package/dist/inspector/clientManifest.js +12 -0
- package/dist/inspector/componentSemantics/adapterRegistry.js +4 -3
- package/dist/inspector/componentSemantics/runtimeBridge.d.ts +2 -2
- package/dist/inspector/componentSemantics/runtimeBridge.js +16 -3
- package/dist/inspector/index.d.ts +2 -0
- package/dist/inspector/index.js +80 -32
- package/dist/inspector/inline-text/inlineTextDiagnostics.d.ts +10 -0
- package/dist/inspector/inline-text/inlineTextDiagnostics.js +65 -0
- package/dist/inspector/inline-text/inlineTextEditor.d.ts +3 -5
- package/dist/inspector/inline-text/inlineTextEditor.js +74 -206
- package/dist/inspector/inline-text/inlineTextFeedback.d.ts +5 -0
- package/dist/inspector/inline-text/inlineTextFeedback.js +27 -0
- package/dist/inspector/inline-text/inlineTextLifecycle.js +2 -0
- package/dist/inspector/inline-text/textEditChange.d.ts +14 -0
- package/dist/inspector/inline-text/textEditChange.js +165 -0
- package/dist/inspector/inspection/selectionProperty.d.ts +1 -0
- package/dist/inspector/inspection/selectionProperty.js +1 -0
- package/dist/inspector/overlay/DomNavigator.d.ts +10 -0
- package/dist/inspector/overlay/DomNavigator.js +40 -0
- package/dist/inspector/overlay/InspectorOverlay.js +6 -2
- package/dist/inspector/overlay/clickPolicy.d.ts +18 -2
- package/dist/inspector/overlay/clickPolicy.js +34 -3
- package/dist/inspector/overlay/elementSelector.d.ts +1 -1
- package/dist/inspector/overlay/elementSelector.js +18 -7
- package/dist/inspector/overlay/selectedGeometry.js +21 -2
- package/dist/inspector/overlay/spacingGestures.d.ts +45 -0
- package/dist/inspector/overlay/spacingGestures.js +351 -0
- package/dist/inspector/overlay/structuralGestures.d.ts +2 -2
- package/dist/inspector/overlay/structuralGestures.js +12 -10
- package/dist/inspector/projection/managedStylesheet.js +4 -1
- package/dist/inspector/projection/renderedInstance.d.ts +2 -0
- package/dist/inspector/projection/renderedInstance.js +5 -1
- package/dist/inspector/projection/structuralProjection.d.ts +2 -0
- package/dist/inspector/projection/structuralProjection.js +85 -1
- package/dist/inspector/projection/structuralProjectionBoundary.js +17 -1
- package/dist/inspector/projection/textProjection.d.ts +2 -0
- package/dist/inspector/projection/textProjection.js +10 -4
- package/dist/inspector/prompt/clipboardHandoff.d.ts +1 -1
- package/dist/inspector/prompt/clipboardHandoff.js +3 -3
- package/dist/inspector/prompt/generatePrompt.d.ts +2 -1
- package/dist/inspector/prompt/generatePrompt.js +19 -2
- package/dist/inspector/runtime/editorShell.d.ts +2 -0
- package/dist/inspector/runtime/editorShell.js +4 -0
- package/dist/inspector/runtime/runtimeConfig.d.ts +5 -1
- package/dist/inspector/runtime/runtimeConfig.js +4 -0
- package/dist/inspector/selection/hierarchy.d.ts +6 -0
- package/dist/inspector/selection/hierarchy.js +8 -0
- package/dist/inspector/selection/selectionStore.js +2 -0
- package/dist/inspector/settings/SettingsDialog.d.ts +1 -1
- package/dist/inspector/settings/SettingsDialog.js +12 -2
- package/dist/inspector/shell/AppShell.js +5 -1
- package/dist/inspector/shell/ChangesLog.js +26 -22
- package/dist/inspector/shell/CopyPromptButton.js +102 -19
- package/dist/inspector/shell/EmptyState.js +1 -1
- package/dist/inspector/shell/InspectorShell.d.ts +0 -1
- package/dist/inspector/shell/InspectorShell.js +38 -42
- package/dist/inspector/shell/PeekOriginalButton.d.ts +7 -0
- package/dist/inspector/shell/PeekOriginalButton.js +57 -0
- package/dist/inspector/shell/PeekOriginalIcon.d.ts +7 -0
- package/dist/inspector/shell/PeekOriginalIcon.js +9 -0
- package/dist/inspector/shell/originalPreview.d.ts +9 -0
- package/dist/inspector/shell/originalPreview.js +61 -0
- package/dist/inspector/shell/shortcuts.d.ts +3 -0
- package/dist/inspector/shell/shortcuts.js +15 -0
- package/dist/inspector/sketch/SketchChanges.d.ts +2 -0
- package/dist/inspector/sketch/SketchChanges.js +72 -0
- package/dist/inspector/sketch/SketchEditor.d.ts +21 -0
- package/dist/inspector/sketch/SketchEditor.js +402 -0
- package/dist/inspector/sketch/SketchEntryButton.d.ts +4 -0
- package/dist/inspector/sketch/SketchEntryButton.js +11 -0
- package/dist/inspector/sketch/SketchFrameOverlay.d.ts +11 -0
- package/dist/inspector/sketch/SketchFrameOverlay.js +119 -0
- package/dist/inspector/sketch/SketchLayersPanel.d.ts +2 -0
- package/dist/inspector/sketch/SketchLayersPanel.js +63 -0
- package/dist/inspector/sketch/SketchOverlay.d.ts +19 -0
- package/dist/inspector/sketch/SketchOverlay.js +420 -0
- package/dist/inspector/sketch/SketchPromptPanel.d.ts +15 -0
- package/dist/inspector/sketch/SketchPromptPanel.js +18 -0
- package/dist/inspector/sketch/SketchWorkspace.d.ts +13 -0
- package/dist/inspector/sketch/SketchWorkspace.js +152 -0
- package/dist/inspector/sketch/capture.d.ts +55 -0
- package/dist/inspector/sketch/capture.js +350 -0
- package/dist/inspector/sketch/freehand.d.ts +13 -0
- package/dist/inspector/sketch/freehand.js +64 -0
- package/dist/inspector/sketch/geometry.d.ts +17 -0
- package/dist/inspector/sketch/geometry.js +98 -0
- package/dist/inspector/sketch/handoff.d.ts +21 -0
- package/dist/inspector/sketch/handoff.js +72 -0
- package/dist/inspector/sketch/interaction.d.ts +21 -0
- package/dist/inspector/sketch/interaction.js +98 -0
- package/dist/inspector/sketch/model.d.ts +104 -0
- package/dist/inspector/sketch/model.js +282 -0
- package/dist/inspector/sketch/persistence.d.ts +21 -0
- package/dist/inspector/sketch/persistence.js +205 -0
- package/dist/inspector/sketch/raster.d.ts +22 -0
- package/dist/inspector/sketch/raster.js +203 -0
- package/dist/inspector/sketch/sketchNote.d.ts +10 -0
- package/dist/inspector/sketch/sketchNote.js +30 -0
- package/dist/inspector/sketch/store.d.ts +47 -0
- package/dist/inspector/sketch/store.js +434 -0
- package/dist/inspector/styleEditors/BorderEditor.js +15 -19
- package/dist/inspector/styleEditors/BorderRadiusEditor.js +6 -6
- package/dist/inspector/styleEditors/BoxShadowEditor.js +12 -1
- package/dist/inspector/styleEditors/ColorPicker.js +11 -36
- package/dist/inspector/styleEditors/GapField.d.ts +3 -2
- package/dist/inspector/styleEditors/GapField.js +2 -2
- package/dist/inspector/styleEditors/GridSection.js +1 -1
- package/dist/inspector/styleEditors/LayoutSection.js +11 -8
- package/dist/inspector/styleEditors/SpacingBox.js +31 -33
- package/dist/inspector/styleEditors/layoutPreviewState.d.ts +5 -0
- package/dist/inspector/styleEditors/layoutPreviewState.js +19 -0
- package/dist/inspector/styleEditors/layoutValue.js +3 -0
- package/dist/inspector/styleEditors/nudgeValue.d.ts +11 -0
- package/dist/inspector/styleEditors/nudgeValue.js +93 -5
- package/dist/inspector/styleEditors/stylePresence.d.ts +7 -0
- package/dist/inspector/styleEditors/stylePresence.js +22 -0
- package/dist/inspector/styleEditors/textRelevance.d.ts +3 -0
- package/dist/inspector/styleEditors/textRelevance.js +35 -0
- package/dist/inspector/styleEditors/useFieldVisibility.d.ts +6 -0
- package/dist/inspector/styleEditors/useFieldVisibility.js +26 -0
- package/dist/inspector/tokens/TokenField.js +130 -7
- package/dist/inspector/tokens/TokensPanel.js +2 -1
- package/dist/inspector/tokens/dragPointerLock.d.ts +8 -0
- package/dist/inspector/tokens/dragPointerLock.js +70 -0
- package/dist/inspector/tokens/editActions.d.ts +2 -0
- package/dist/inspector/tokens/editActions.js +2 -2
- package/dist/inspector/tokens/resolution/cssomCollector.d.ts +1 -1
- package/dist/inspector/tokens/resolution/cssomCollector.js +9 -5
- package/dist/inspector/tokens/resolution/ruleMatching.d.ts +40 -0
- package/dist/inspector/tokens/resolution/ruleMatching.js +423 -0
- package/dist/inspector/tokens/resolution/selectorSemantics.d.ts +19 -3
- package/dist/inspector/tokens/resolution/selectorSemantics.js +378 -4
- package/dist/inspector/tokens/resolution.d.ts +3 -26
- package/dist/inspector/tokens/resolution.js +44 -735
- package/dist/inspector/tokens/tokenAvailability.d.ts +18 -0
- package/dist/inspector/tokens/tokenAvailability.js +204 -0
- package/dist/inspector/ui/Button.d.ts +1 -1
- package/dist/inspector/ui/Disclosure.d.ts +22 -0
- package/dist/inspector/ui/Disclosure.js +13 -0
- package/dist/inspector/ui/SideValuesField.js +2 -2
- package/dist/inspector/ui/StatusCallout.d.ts +4 -1
- package/dist/inspector/ui/StatusCallout.js +2 -2
- package/dist/inspector/ui/dragCursor.d.ts +8 -0
- package/dist/inspector/ui/dragCursor.js +21 -0
- package/dist/inspector/ui/styles.js +21 -17
- package/dist/internal/agent-protocol.d.ts +65 -1
- package/dist/internal/agent-protocol.js +183 -3
- package/dist/nudge-ui.mjs +276 -58
- package/dist/transport/editor.d.ts +47 -0
- package/dist/transport/editor.js +163 -0
- package/dist/transport/index.d.ts +1 -0
- package/dist/transport/index.js +1 -0
- package/dist/transport/routes.d.ts +10 -0
- package/dist/transport/routes.js +10 -0
- package/package.json +3 -1
- package/dist/inspector/shell/DomNavigation.d.ts +0 -8
- package/dist/inspector/shell/DomNavigation.js +0 -30
- package/dist/inspector/shell/panelLayout.d.ts +0 -2
- package/dist/inspector/shell/panelLayout.js +0 -29
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { createComponentPropChange } from "../componentSemantics/changeModel.js";
|
|
2
|
+
import { captureTextProjectionTarget, textProjectionSelector } from "../projection/textProjection.js";
|
|
3
|
+
export function initialTextEditDecision(candidate) {
|
|
4
|
+
return {
|
|
5
|
+
bindingIndex: candidate.bindingChoices?.length === 1 ? 0 : null,
|
|
6
|
+
scope: candidate.scope ?? (candidate.binding.kind === "rendered-text" ? "rendered-instance" : "source-site"),
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export function chooseTextEditBinding(candidate, index) {
|
|
10
|
+
const choice = candidate.bindingChoices?.[index];
|
|
11
|
+
if (!choice)
|
|
12
|
+
return null;
|
|
13
|
+
return {
|
|
14
|
+
bindingIndex: index,
|
|
15
|
+
scope: choice.mountedCount > 1 ? "rendered-instance" : "source-site",
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function selectedBinding(candidate, decision) {
|
|
19
|
+
return decision.bindingIndex === null ? null : candidate.bindingChoices?.[decision.bindingIndex] ?? null;
|
|
20
|
+
}
|
|
21
|
+
export function getTextEditScopeChoices(candidate, decision) {
|
|
22
|
+
const choice = selectedBinding(candidate, decision);
|
|
23
|
+
if (!choice)
|
|
24
|
+
return candidate.scopeChoices ?? [];
|
|
25
|
+
return choice.mountedCount > 1 && choice.authoredAs === "literal"
|
|
26
|
+
? ["rendered-instance", "source-site"]
|
|
27
|
+
: [];
|
|
28
|
+
}
|
|
29
|
+
export function getTextEditBinding(candidate, decision, capturedTarget) {
|
|
30
|
+
const choice = selectedBinding(candidate, decision);
|
|
31
|
+
if (!choice)
|
|
32
|
+
return candidate.binding;
|
|
33
|
+
if (choice.mountedCount > 1 && choice.authoredAs !== "literal") {
|
|
34
|
+
const target = choice.renderedTarget ?? candidate.renderedTarget ?? capturedTarget;
|
|
35
|
+
return target ? { kind: "rendered-text", target } : choice.binding;
|
|
36
|
+
}
|
|
37
|
+
return choice.binding;
|
|
38
|
+
}
|
|
39
|
+
function sourceForChoice(candidate, choice) {
|
|
40
|
+
if (choice?.renderedSource)
|
|
41
|
+
return choice.renderedSource;
|
|
42
|
+
if (candidate.renderedSource
|
|
43
|
+
&& (!choice || candidate.renderedSource.evidence?.callsiteId === choice.binding.target.callsiteId
|
|
44
|
+
&& candidate.renderedSource.evidence.property === choice.binding.property)) {
|
|
45
|
+
return candidate.renderedSource;
|
|
46
|
+
}
|
|
47
|
+
const parsed = /^(.*):(\d+):(\d+)$/.exec(candidate.element.getAttribute("data-src") ?? "");
|
|
48
|
+
const target = choice?.binding.target;
|
|
49
|
+
const authoredAs = choice?.authoredAs === "literal"
|
|
50
|
+
? "literal"
|
|
51
|
+
: choice?.authoredAs === "expression" || choice?.authoredAs === "spread"
|
|
52
|
+
? "expression"
|
|
53
|
+
: "unknown";
|
|
54
|
+
return {
|
|
55
|
+
file: target?.file ?? parsed?.[1] ?? candidate.element.getAttribute("data-src") ?? "",
|
|
56
|
+
line: target?.line ?? Number(parsed?.[2] ?? 0),
|
|
57
|
+
column: target?.column ?? Number(parsed?.[3] ?? 0),
|
|
58
|
+
component: target?.componentName ?? candidate.element.getAttribute("data-cid") ?? "Rendered text",
|
|
59
|
+
selector: candidate.binding.kind === "rendered-text"
|
|
60
|
+
? textProjectionSelector(candidate.binding.target) ?? ""
|
|
61
|
+
: "",
|
|
62
|
+
authoredAs,
|
|
63
|
+
evidence: choice ? {
|
|
64
|
+
callsiteId: choice.binding.target.callsiteId,
|
|
65
|
+
componentName: choice.binding.target.componentName,
|
|
66
|
+
property: choice.binding.property,
|
|
67
|
+
mountedCount: choice.mountedCount,
|
|
68
|
+
} : undefined,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function componentEvidence(candidate, choice) {
|
|
72
|
+
const target = choice.renderedTarget
|
|
73
|
+
?? candidate.renderedTarget
|
|
74
|
+
?? captureTextProjectionTarget(candidate.element, candidate.before, candidate.textNode);
|
|
75
|
+
return {
|
|
76
|
+
occurrence: target?.occurrence ?? 0,
|
|
77
|
+
props: target?.props ?? candidate.element.getAttribute("data-cprops"),
|
|
78
|
+
ariaLabel: target?.ariaLabel ?? candidate.element.getAttribute("aria-label"),
|
|
79
|
+
beforeText: candidate.before,
|
|
80
|
+
mountedCount: choice.mountedCount,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function textTargetFor(candidate, binding, choice) {
|
|
84
|
+
if (choice?.renderedTarget)
|
|
85
|
+
return choice.renderedTarget;
|
|
86
|
+
if (candidate.renderedTarget)
|
|
87
|
+
return candidate.renderedTarget;
|
|
88
|
+
if (binding.kind === "rendered-text")
|
|
89
|
+
return binding.target;
|
|
90
|
+
return captureTextProjectionTarget(candidate.element, candidate.before, candidate.textNode);
|
|
91
|
+
}
|
|
92
|
+
function choiceForCommit(candidate, selectedChoice) {
|
|
93
|
+
const choice = selectedChoice ?? candidate.bindingChoices?.[0];
|
|
94
|
+
const target = candidate.editableTarget;
|
|
95
|
+
if (choice || !target || candidate.mountedCount === undefined)
|
|
96
|
+
return choice ?? null;
|
|
97
|
+
const property = candidate.binding.kind === "component-prop"
|
|
98
|
+
? candidate.binding.property
|
|
99
|
+
: "children";
|
|
100
|
+
return {
|
|
101
|
+
binding: candidate.binding.kind === "component-prop"
|
|
102
|
+
? candidate.binding
|
|
103
|
+
: {
|
|
104
|
+
kind: "component-prop",
|
|
105
|
+
property,
|
|
106
|
+
target: {
|
|
107
|
+
framework: target.framework,
|
|
108
|
+
componentId: target.contract.componentId,
|
|
109
|
+
callsiteId: target.meta.callsiteId,
|
|
110
|
+
componentName: target.meta.componentName,
|
|
111
|
+
file: target.meta.file,
|
|
112
|
+
line: target.meta.line,
|
|
113
|
+
column: target.meta.column,
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
editableTarget: target,
|
|
117
|
+
mountedCount: candidate.mountedCount,
|
|
118
|
+
authoredAs: target.meta.authoredProps[property] ?? "default",
|
|
119
|
+
renderedTarget: candidate.renderedTarget ?? null,
|
|
120
|
+
renderedSource: candidate.renderedSource,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/** Builds a canonical record without changing the DOM, appending history, or ending a draft. */
|
|
124
|
+
export function prepareTextEditChange(candidate, decision, capturedTarget, after) {
|
|
125
|
+
if ((candidate.bindingChoices?.length ?? 0) > 1 && decision.bindingIndex === null)
|
|
126
|
+
return null;
|
|
127
|
+
const binding = getTextEditBinding(candidate, decision, capturedTarget);
|
|
128
|
+
const choice = choiceForCommit(candidate, selectedBinding(candidate, decision));
|
|
129
|
+
if (binding.kind === "component-prop" && decision.scope === "source-site") {
|
|
130
|
+
const editableTarget = choice?.editableTarget ?? candidate.editableTarget;
|
|
131
|
+
const prop = editableTarget?.contract.props.find((item) => item.name === binding.property && item.control === "text");
|
|
132
|
+
if (!editableTarget || !prop)
|
|
133
|
+
return null;
|
|
134
|
+
return createComponentPropChange(editableTarget, prop, after, {
|
|
135
|
+
scope: "source-site",
|
|
136
|
+
evidence: choice && choice.mountedCount > 1
|
|
137
|
+
? componentEvidence(candidate, choice)
|
|
138
|
+
: undefined,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
const textTarget = textTargetFor(candidate, binding, choice);
|
|
142
|
+
const source = sourceForChoice(candidate, choice);
|
|
143
|
+
const renderedSource = source.selector || !textTarget
|
|
144
|
+
? source
|
|
145
|
+
: { ...source, selector: textProjectionSelector(textTarget) ?? "" };
|
|
146
|
+
if (!textTarget || !renderedSource.selector)
|
|
147
|
+
return null;
|
|
148
|
+
return {
|
|
149
|
+
kind: "text-content",
|
|
150
|
+
id: `text-${globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`}`,
|
|
151
|
+
target: textTarget,
|
|
152
|
+
source: {
|
|
153
|
+
file: renderedSource.file,
|
|
154
|
+
line: renderedSource.line,
|
|
155
|
+
column: renderedSource.column,
|
|
156
|
+
component: renderedSource.component,
|
|
157
|
+
},
|
|
158
|
+
selector: renderedSource.selector,
|
|
159
|
+
before: candidate.before,
|
|
160
|
+
after,
|
|
161
|
+
authoredAs: renderedSource.authoredAs,
|
|
162
|
+
scope: decision.scope,
|
|
163
|
+
evidence: renderedSource.evidence,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
@@ -19,6 +19,7 @@ export interface SelectionProperty {
|
|
|
19
19
|
value: SelectionValue;
|
|
20
20
|
token: SelectionToken;
|
|
21
21
|
primaryRow: ResolvedProperty | null;
|
|
22
|
+
rows: readonly (ResolvedProperty | null)[];
|
|
22
23
|
}
|
|
23
24
|
/**
|
|
24
25
|
* Projects browser values and authored inspection rows into group-safe facts.
|
|
@@ -22,6 +22,7 @@ export function projectSelectionProperty(property, rows, values, primaryIndex) {
|
|
|
22
22
|
value: common ? { kind: "common", value: first } : { kind: "mixed" },
|
|
23
23
|
token: tokenFor(rows),
|
|
24
24
|
primaryRow: rows[primaryIndex] ?? null,
|
|
25
|
+
rows,
|
|
25
26
|
};
|
|
26
27
|
}
|
|
27
28
|
/** Returns the token entries available to every inspected target. */
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import type { SelectedElement } from "../selection/selectionStore.js";
|
|
3
|
+
import type { Rect } from "./overlayGeometry.js";
|
|
4
|
+
export interface DomNavigatorProps {
|
|
5
|
+
selected: SelectedElement;
|
|
6
|
+
hierarchy: HTMLElement[];
|
|
7
|
+
anchor: Rect;
|
|
8
|
+
project: (element: HTMLElement) => Rect | null;
|
|
9
|
+
}
|
|
10
|
+
export declare function DomNavigator({ selected, hierarchy, anchor, project }: DomNavigatorProps): ReactElement | null;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { setSelectedElement } from "../selection/selectionStore.js";
|
|
4
|
+
import { computeNavigationNodes } from "../selection/hierarchy.js";
|
|
5
|
+
import { resolveSelectionFromElement } from "../selection/resolveSelection.js";
|
|
6
|
+
function nodeLabel(node) {
|
|
7
|
+
return node.getAttribute("data-cid") ?? node.localName;
|
|
8
|
+
}
|
|
9
|
+
function nodeDescription(node) {
|
|
10
|
+
const id = node.id ? `#${node.id}` : "";
|
|
11
|
+
const className = typeof node.className === "string"
|
|
12
|
+
? node.className.trim().split(/\s+/).filter(Boolean).slice(0, 2).map((name) => `.${name}`).join("")
|
|
13
|
+
: "";
|
|
14
|
+
const source = node.getAttribute("data-src");
|
|
15
|
+
return `${node.localName}${id}${className}${source ? ` — ${source}` : ""}`;
|
|
16
|
+
}
|
|
17
|
+
function selectNode(node) {
|
|
18
|
+
const resolved = resolveSelectionFromElement(node);
|
|
19
|
+
if (resolved)
|
|
20
|
+
setSelectedElement(resolved);
|
|
21
|
+
}
|
|
22
|
+
export function DomNavigator({ selected, hierarchy, anchor, project }) {
|
|
23
|
+
const nodes = computeNavigationNodes(selected.domElement, hierarchy);
|
|
24
|
+
const [expanded, setExpanded] = useState(false);
|
|
25
|
+
const [hovered, setHovered] = useState(null);
|
|
26
|
+
if (nodes.length === 0)
|
|
27
|
+
return null;
|
|
28
|
+
const preview = hovered ? project(hovered) : null;
|
|
29
|
+
const close = () => {
|
|
30
|
+
setExpanded(false);
|
|
31
|
+
setHovered(null);
|
|
32
|
+
};
|
|
33
|
+
return (_jsxs(_Fragment, { children: [preview ? _jsx("div", { className: "dom-navigator-preview", "data-test": "dom-navigator-preview", style: preview, "aria-hidden": "true" }) : null, _jsxs("div", { className: "dom-navigator", "data-test": "dom-navigator", "aria-label": "DOM navigator", style: { left: Math.max(4, anchor.left), top: Math.max(4, anchor.top) }, onMouseEnter: () => setExpanded(true), onMouseLeave: close, onFocus: () => setExpanded(true), onBlur: (event) => {
|
|
34
|
+
if (!(event.relatedTarget instanceof Node) || !event.currentTarget.contains(event.relatedTarget))
|
|
35
|
+
close();
|
|
36
|
+
}, children: [_jsxs("button", { type: "button", className: "dom-navigator__trigger", "data-test": "dom-navigator-trigger", "aria-expanded": expanded, "aria-haspopup": "menu", title: nodeDescription(selected.domElement), onMouseEnter: () => setHovered(null), children: [_jsx("span", { children: nodeLabel(selected.domElement) }), _jsx("span", { "aria-hidden": "true", children: "\u2304" })] }), expanded ? (_jsx("div", { className: "dom-navigator__menu", role: "menu", children: nodes.map((node) => (_jsxs("button", { type: "button", className: "dom-navigator__item", "data-test": "dom-navigator-item", "data-direction": node.direction, "data-depth": node.depth, "data-cid": node.element.getAttribute("data-cid") ?? undefined, title: nodeDescription(node.element), role: "menuitem", onMouseEnter: () => setHovered(node.element), onClick: () => {
|
|
37
|
+
selectNode(node.element);
|
|
38
|
+
close();
|
|
39
|
+
}, children: [_jsx("span", { "aria-hidden": "true", children: node.direction === "up" ? "↑" : "↓" }), _jsx("span", { children: nodeLabel(node.element) })] }, `${node.direction}-${node.depth}-${node.element.getAttribute("data-cid") ?? node.element.localName}`))) })) : null] })] }));
|
|
40
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useRef, useState } from "react";
|
|
3
3
|
import { useInspectorOpen } from "../shell/openStore.js";
|
|
4
|
-
import { getSelectedElements, useSelectedElement, useSelectedElements } from "../selection/selectionStore.js";
|
|
4
|
+
import { getSelectedElements, useHierarchy, useSelectedElement, useSelectedElements } from "../selection/selectionStore.js";
|
|
5
5
|
import { installElementSelector } from "./elementSelector.js";
|
|
6
6
|
import { getMarginFills, getMarginGuides, readBorderWidths, readMargins, toRect, } from "./overlayGeometry.js";
|
|
7
7
|
import { observeSelectedGeometry } from "./selectedGeometry.js";
|
|
@@ -17,6 +17,8 @@ import { MeasurementGuideOverlay } from "./MeasurementGuideOverlay.js";
|
|
|
17
17
|
import { resolveSelectionTarget, selectionTargetMode } from "../selection/selectionTarget.js";
|
|
18
18
|
import { isInlineTextEditingActive, useInlineTextSession } from "../inline-text/inlineTextEditor.js";
|
|
19
19
|
import { EMPTY_TEXT_PROJECTION_ATTR } from "../projection/textProjection.js";
|
|
20
|
+
import { useNudgeUiRuntimeConfig } from "../runtime/useRuntimeConfig.js";
|
|
21
|
+
import { DomNavigator } from "./DomNavigator.js";
|
|
20
22
|
export { getMarginFills, getMarginGuides, } from "./overlayGeometry.js";
|
|
21
23
|
function overlayStyle(rect) {
|
|
22
24
|
return {
|
|
@@ -32,6 +34,8 @@ export function InspectorOverlay({ host }) {
|
|
|
32
34
|
const open = useInspectorOpen();
|
|
33
35
|
const selected = useSelectedElement();
|
|
34
36
|
const selectedElements = useSelectedElements();
|
|
37
|
+
const hierarchy = useHierarchy();
|
|
38
|
+
const domNavigationEnabled = useNudgeUiRuntimeConfig().capabilities.domNavigation === true;
|
|
35
39
|
const inlineTextSession = useInlineTextSession();
|
|
36
40
|
const [hoverRect, setHoverRect] = useState(null);
|
|
37
41
|
const [hoverMargins, setHoverMargins] = useState(null);
|
|
@@ -322,7 +326,7 @@ export function InspectorOverlay({ host }) {
|
|
|
322
326
|
width: guide.width,
|
|
323
327
|
height: guide.height,
|
|
324
328
|
pointerEvents: "none",
|
|
325
|
-
}, "aria-hidden": "true" }, guide.side)))] })) : null, open && !inlineTextSession ? selectedGeometry.map(({ element, rect }, index) => (_jsx("div", { className: "selected-outline", "data-test": "selected-outline", "data-selected-cid": element.cid, "data-selected-index": index, "data-selected-src": element.src, style: overlayStyle(rect), "aria-hidden": "true" }, `${element.domElement.getAttribute("data-cid") ?? "element"}-${index}`))) : null, open && selectedElements.length === 1 ? _jsx(DropGuideOverlay, { guide: dropGuide?.document === document
|
|
329
|
+
}, "aria-hidden": "true" }, guide.side)))] })) : null, open && !inlineTextSession ? selectedGeometry.map(({ element, rect }, index) => (_jsx("div", { className: "selected-outline", "data-test": "selected-outline", "data-selected-cid": element.cid, "data-selected-index": index, "data-selected-src": element.src, style: overlayStyle(rect), "aria-hidden": "true" }, `${element.domElement.getAttribute("data-cid") ?? "element"}-${index}`))) : null, open && domNavigationEnabled && !inlineTextSession && selectedElements.length === 1 && selected && selectedRect ? (_jsx(DomNavigator, { selected: selected, hierarchy: hierarchy, anchor: selectedRect, project: (element) => toRect(element.getBoundingClientRect()) })) : null, open && selectedElements.length === 1 ? _jsx(DropGuideOverlay, { guide: dropGuide?.document === document
|
|
326
330
|
? { orientation: dropGuide.orientation, line: dropGuide.line, target: dropGuide.target }
|
|
327
331
|
: null, lineClassName: "dom-drop-line", lineTestId: "dom-drop-line", targetClassName: "dom-drop-target", targetTestId: "dom-drop-target" }) : null] }));
|
|
328
332
|
}
|
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
export type ClickModifiers = Pick<MouseEvent, "ctrlKey" | "metaKey" | "shiftKey">;
|
|
2
|
+
/**
|
|
3
|
+
* Press and release gestures that application widgets use to open menus,
|
|
4
|
+
* dialogs, and popovers before any `click` fires. The Design tool keeps them
|
|
5
|
+
* from reaching the application.
|
|
6
|
+
*/
|
|
7
|
+
export declare const APPLICATION_GESTURE_EVENTS: readonly ["pointerdown", "pointerup", "mousedown", "mouseup", "touchstart", "touchend", "auxclick", "contextmenu"];
|
|
2
8
|
/** Command/Ctrl-click selects the deepest tracked element unless Shift is held. */
|
|
3
9
|
export declare function isDeepSelectionClick(event: ClickModifiers): boolean;
|
|
4
|
-
/**
|
|
5
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Only input from a person becomes inspector selection. Script events such
|
|
12
|
+
* as `element.click()` keep reaching the application.
|
|
13
|
+
*/
|
|
14
|
+
export declare function isUserClick(event: Pick<Event, "isTrusted">): boolean;
|
|
15
|
+
/** The active inline text editor needs native press events for caret placement. */
|
|
16
|
+
export declare function isInlineEditorTarget(target: EventTarget | null): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Keeps an application press gesture from reaching application listeners.
|
|
19
|
+
* Listeners on the document itself, including the inspector's own, still run.
|
|
20
|
+
*/
|
|
21
|
+
export declare function blockApplicationGesture(event: Event): void;
|
|
6
22
|
/** Prevent an inspected application click from reaching the host application. */
|
|
7
23
|
export declare function blockApplicationClick(event: MouseEvent): void;
|
|
@@ -1,10 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Press and release gestures that application widgets use to open menus,
|
|
3
|
+
* dialogs, and popovers before any `click` fires. The Design tool keeps them
|
|
4
|
+
* from reaching the application.
|
|
5
|
+
*/
|
|
6
|
+
export const APPLICATION_GESTURE_EVENTS = [
|
|
7
|
+
"pointerdown",
|
|
8
|
+
"pointerup",
|
|
9
|
+
"mousedown",
|
|
10
|
+
"mouseup",
|
|
11
|
+
"touchstart",
|
|
12
|
+
"touchend",
|
|
13
|
+
"auxclick",
|
|
14
|
+
"contextmenu",
|
|
15
|
+
];
|
|
1
16
|
/** Command/Ctrl-click selects the deepest tracked element unless Shift is held. */
|
|
2
17
|
export function isDeepSelectionClick(event) {
|
|
3
18
|
return (event.ctrlKey || event.metaKey) && !event.shiftKey;
|
|
4
19
|
}
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Only input from a person becomes inspector selection. Script events such
|
|
22
|
+
* as `element.click()` keep reaching the application.
|
|
23
|
+
*/
|
|
24
|
+
export function isUserClick(event) {
|
|
25
|
+
return event.isTrusted;
|
|
26
|
+
}
|
|
27
|
+
/** The active inline text editor needs native press events for caret placement. */
|
|
28
|
+
export function isInlineEditorTarget(target) {
|
|
29
|
+
return typeof Element !== "undefined"
|
|
30
|
+
&& target instanceof Element
|
|
31
|
+
&& target.closest('[data-inline-editor="true"]') !== null;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Keeps an application press gesture from reaching application listeners.
|
|
35
|
+
* Listeners on the document itself, including the inspector's own, still run.
|
|
36
|
+
*/
|
|
37
|
+
export function blockApplicationGesture(event) {
|
|
38
|
+
event.stopPropagation();
|
|
8
39
|
}
|
|
9
40
|
/** Prevent an inspected application click from reaching the host application. */
|
|
10
41
|
export function blockApplicationClick(event) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function installElementSelector(inspectorHost: HTMLElement): () => void;
|
|
1
|
+
export declare function installElementSelector(inspectorHost: HTMLElement, acceptsClick?: (event: Event) => boolean): () => void;
|
|
@@ -3,8 +3,8 @@ import { getOpen } from "../shell/openStore.js";
|
|
|
3
3
|
import { resolveSelectionFromEvent } from "../selection/resolveSelection.js";
|
|
4
4
|
import { handleInlineTextEditIntent, isInlineTextEditingActive, } from "../inline-text/inlineTextEditor.js";
|
|
5
5
|
import { EMPTY_TEXT_PROJECTION_ATTR } from "../projection/textProjection.js";
|
|
6
|
-
import { blockApplicationClick,
|
|
7
|
-
export function installElementSelector(inspectorHost) {
|
|
6
|
+
import { APPLICATION_GESTURE_EVENTS, blockApplicationClick, blockApplicationGesture, isInlineEditorTarget, isUserClick, } from "./clickPolicy.js";
|
|
7
|
+
export function installElementSelector(inspectorHost, acceptsClick = isUserClick) {
|
|
8
8
|
function applyInlineTextDisposition(event, disposition) {
|
|
9
9
|
if (disposition === "pass-through")
|
|
10
10
|
return;
|
|
@@ -43,7 +43,7 @@ export function installElementSelector(inspectorHost) {
|
|
|
43
43
|
return root instanceof ShadowRoot && root.host === inspectorHost;
|
|
44
44
|
}
|
|
45
45
|
function onClick(e) {
|
|
46
|
-
if (!getOpen())
|
|
46
|
+
if (!getOpen() || !acceptsClick(e))
|
|
47
47
|
return;
|
|
48
48
|
if (isInsideInspectorUi(e)) {
|
|
49
49
|
// The selector guards the inspected application only. Clicks on the
|
|
@@ -61,13 +61,10 @@ export function installElementSelector(inspectorHost) {
|
|
|
61
61
|
blockApplicationClick(e);
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
|
-
if (isApplicationActivationClick(e))
|
|
65
|
-
return;
|
|
66
64
|
// The inspector is an editing surface while open. Capture every ordinary
|
|
67
65
|
// application click so buttons, links, and untracked controls cannot run
|
|
68
66
|
// alongside selection. Shift-click toggles the primary target in the
|
|
69
|
-
// ordered group; Command/Ctrl-click
|
|
70
|
-
// element, and Command/Ctrl+Shift-click remains the activation escape hatch.
|
|
67
|
+
// ordered group; Command/Ctrl-click selects the deepest tracked element.
|
|
71
68
|
const sel = resolveSelectionFromEvent(e, inspectorHost);
|
|
72
69
|
blockApplicationClick(e);
|
|
73
70
|
if (sel) {
|
|
@@ -89,12 +86,26 @@ export function installElementSelector(inspectorHost) {
|
|
|
89
86
|
clickCount: e.detail,
|
|
90
87
|
}));
|
|
91
88
|
}
|
|
89
|
+
function onApplicationGesture(e) {
|
|
90
|
+
if (!getOpen() || !acceptsClick(e) || isInlineEditorTarget(e.target))
|
|
91
|
+
return;
|
|
92
|
+
if (e.target instanceof Element
|
|
93
|
+
&& (e.target === inspectorHost || inspectorHost.contains(e.target)))
|
|
94
|
+
return;
|
|
95
|
+
blockApplicationGesture(e);
|
|
96
|
+
}
|
|
92
97
|
document.addEventListener("mousedown", onMouseDown, true);
|
|
93
98
|
document.addEventListener("dblclick", onDoubleClick, true);
|
|
94
99
|
document.addEventListener("click", onClick, true);
|
|
100
|
+
for (const type of APPLICATION_GESTURE_EVENTS) {
|
|
101
|
+
document.addEventListener(type, onApplicationGesture, true);
|
|
102
|
+
}
|
|
95
103
|
return () => {
|
|
96
104
|
document.removeEventListener("mousedown", onMouseDown, true);
|
|
97
105
|
document.removeEventListener("dblclick", onDoubleClick, true);
|
|
98
106
|
document.removeEventListener("click", onClick, true);
|
|
107
|
+
for (const type of APPLICATION_GESTURE_EVENTS) {
|
|
108
|
+
document.removeEventListener(type, onApplicationGesture, true);
|
|
109
|
+
}
|
|
99
110
|
};
|
|
100
111
|
}
|
|
@@ -20,6 +20,24 @@ export function observeSelectedGeometry(element, onChange) {
|
|
|
20
20
|
onChange();
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
|
+
let scrollTargets = [];
|
|
24
|
+
function unbindScrollTargets() {
|
|
25
|
+
for (const target of scrollTargets)
|
|
26
|
+
target.removeEventListener("scroll", schedule, true);
|
|
27
|
+
scrollTargets = [];
|
|
28
|
+
}
|
|
29
|
+
function bindScrollTargets() {
|
|
30
|
+
unbindScrollTargets();
|
|
31
|
+
const targets = [view, view.document];
|
|
32
|
+
let ancestor = element.parentElement;
|
|
33
|
+
while (ancestor) {
|
|
34
|
+
targets.push(ancestor);
|
|
35
|
+
ancestor = ancestor.parentElement;
|
|
36
|
+
}
|
|
37
|
+
scrollTargets = [...new Set(targets)];
|
|
38
|
+
for (const target of scrollTargets)
|
|
39
|
+
target.addEventListener("scroll", schedule, true);
|
|
40
|
+
}
|
|
23
41
|
const resizeObserver = ResizeObserverCtor
|
|
24
42
|
? new ResizeObserverCtor(schedule)
|
|
25
43
|
: null;
|
|
@@ -32,6 +50,7 @@ export function observeSelectedGeometry(element, onChange) {
|
|
|
32
50
|
mutationObserver?.disconnect();
|
|
33
51
|
if (observedParent)
|
|
34
52
|
mutationObserver?.observe(observedParent, { childList: true });
|
|
53
|
+
bindScrollTargets();
|
|
35
54
|
}
|
|
36
55
|
schedule();
|
|
37
56
|
}) : null;
|
|
@@ -39,13 +58,13 @@ export function observeSelectedGeometry(element, onChange) {
|
|
|
39
58
|
if (observedParent)
|
|
40
59
|
mutationObserver?.observe(observedParent, { childList: true });
|
|
41
60
|
view.addEventListener("resize", schedule);
|
|
42
|
-
|
|
61
|
+
bindScrollTargets();
|
|
43
62
|
return () => {
|
|
44
63
|
if (frame !== null)
|
|
45
64
|
view.cancelAnimationFrame(frame);
|
|
46
65
|
resizeObserver?.disconnect();
|
|
47
66
|
mutationObserver?.disconnect();
|
|
48
67
|
view.removeEventListener("resize", schedule);
|
|
49
|
-
|
|
68
|
+
unbindScrollTargets();
|
|
50
69
|
};
|
|
51
70
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Rect } from "./overlayGeometry.js";
|
|
2
|
+
export type PaddingSide = "top" | "right" | "bottom" | "left";
|
|
3
|
+
export type SpacingKind = "padding" | "gap";
|
|
4
|
+
export type SpacingAxis = "horizontal" | "vertical";
|
|
5
|
+
export type SpacingDragAxis = "x" | "y";
|
|
6
|
+
export type SpacingProperty = `padding-${PaddingSide}` | "row-gap" | "column-gap";
|
|
7
|
+
export interface SpacingGuideData {
|
|
8
|
+
kind: SpacingKind;
|
|
9
|
+
property: SpacingProperty;
|
|
10
|
+
side: PaddingSide | null;
|
|
11
|
+
axis: SpacingAxis;
|
|
12
|
+
dragAxis: SpacingDragAxis;
|
|
13
|
+
value: number;
|
|
14
|
+
direction: 1 | -1;
|
|
15
|
+
cursor: "ew-resize" | "ns-resize";
|
|
16
|
+
guide: Rect;
|
|
17
|
+
affectedGuides: Rect[];
|
|
18
|
+
affectedAreas: Rect[];
|
|
19
|
+
/** A 16px-thick pointer target centred on the visible, up-to-40px guide handle. */
|
|
20
|
+
hit: Rect;
|
|
21
|
+
}
|
|
22
|
+
export interface SpacingAffordance extends SpacingGuideData {
|
|
23
|
+
element: HTMLElement;
|
|
24
|
+
}
|
|
25
|
+
export interface SpacingDescriptor {
|
|
26
|
+
kind: SpacingKind;
|
|
27
|
+
property: SpacingProperty;
|
|
28
|
+
side: PaddingSide | null;
|
|
29
|
+
}
|
|
30
|
+
export declare const SPACING_GUIDE_HANDLE_LENGTH = 40;
|
|
31
|
+
/** Finds the spacing target under a document-local pointer location. */
|
|
32
|
+
export declare function getSpacingAffordanceAtPoint(doc: Document, x: number, y: number): SpacingAffordance | null;
|
|
33
|
+
/** Re-resolves a renderer-reported spacing descriptor in its owner document. */
|
|
34
|
+
export declare function getSpacingAffordanceForDescriptor(element: HTMLElement, descriptor: SpacingDescriptor): SpacingAffordance | null;
|
|
35
|
+
/** Calculates a direct-manipulation value, optionally stepping changes by 8px. */
|
|
36
|
+
export declare function spacingValueForDrag(affordance: Pick<SpacingAffordance, "dragAxis" | "direction" | "value">, start: {
|
|
37
|
+
x: number;
|
|
38
|
+
y: number;
|
|
39
|
+
}, point: {
|
|
40
|
+
x: number;
|
|
41
|
+
y: number;
|
|
42
|
+
}, shiftKey?: boolean): number;
|
|
43
|
+
export declare function spacingValueCss(value: number): string;
|
|
44
|
+
/** Serializes the stable part of an affordance for renderer-to-controller messages. */
|
|
45
|
+
export declare function toSpacingDescriptor(affordance: SpacingAffordance): SpacingDescriptor;
|