nudge-ui 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +872 -12
- package/dist/hosts/astro/astroRuntimeConfig.js +1 -1
- package/dist/hosts/astro/clientTransport.js +60 -11
- package/dist/hosts/next/sidecar.d.ts +4 -0
- package/dist/hosts/next/sidecar.js +49 -6
- package/dist/hosts/next/wrapper.js +30 -2
- package/dist/hosts/projectBridge.d.ts +20 -0
- package/dist/hosts/projectBridge.js +97 -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 +1 -1
- package/dist/hosts/static/server.js +44 -3
- package/dist/hosts/vite/vite.d.ts +5 -1
- package/dist/hosts/vite/vite.js +78 -14
- package/dist/inspector/agent/McpConnectionDialog.d.ts +2 -2
- package/dist/inspector/agent/McpConnectionDialog.js +11 -35
- package/dist/inspector/agent/client.d.ts +10 -3
- package/dist/inspector/agent/client.js +80 -9
- package/dist/inspector/agent/connectionStatus.js +3 -3
- package/dist/inspector/agent/httpTransport.d.ts +2 -0
- package/dist/inspector/agent/httpTransport.js +37 -17
- package/dist/inspector/agent/protocol.d.ts +8 -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 +246 -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 +392 -73
- 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 +69 -5
- package/dist/inspector/canvas/frameProtocol.js +56 -2
- package/dist/inspector/canvas/keyboardShortcuts.d.ts +3 -0
- package/dist/inspector/canvas/keyboardShortcuts.js +14 -0
- package/dist/inspector/canvas/projection.d.ts +7 -0
- package/dist/inspector/canvas/projection.js +118 -25
- package/dist/inspector/canvas/rendererBootstrap.js +29 -29
- package/dist/inspector/canvas/rendererElementSelector.js +341 -30
- 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/clientManifest.d.ts +5 -0
- package/dist/inspector/clientManifest.js +11 -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 +74 -24
- 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/selectedGeometry.js +21 -2
- package/dist/inspector/overlay/spacingGestures.d.ts +45 -0
- package/dist/inspector/overlay/spacingGestures.js +353 -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 +4 -0
- package/dist/inspector/runtime/runtimeConfig.js +4 -0
- package/dist/inspector/selection/selectionStore.js +2 -0
- package/dist/inspector/settings/SettingsDialog.js +10 -0
- package/dist/inspector/shell/AppShell.js +5 -1
- package/dist/inspector/shell/ChangesLog.js +8 -4
- package/dist/inspector/shell/CopyPromptButton.js +95 -19
- package/dist/inspector/shell/EmptyState.js +1 -1
- package/dist/inspector/shell/InspectorShell.d.ts +0 -1
- package/dist/inspector/shell/InspectorShell.js +37 -38
- 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 +409 -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 +23 -30
- 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 +91 -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 +111 -7
- 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/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/styles.js +13 -11
- package/dist/internal/agent-protocol.d.ts +65 -1
- package/dist/internal/agent-protocol.js +183 -3
- package/dist/nudge-ui.mjs +261 -57
- package/dist/transport/editor.d.ts +28 -0
- package/dist/transport/editor.js +132 -0
- package/dist/transport/index.d.ts +1 -0
- package/dist/transport/index.js +1 -0
- package/dist/transport/routes.d.ts +7 -0
- package/dist/transport/routes.js +7 -0
- package/package.json +3 -1
- package/dist/inspector/shell/panelLayout.d.ts +0 -2
- package/dist/inspector/shell/panelLayout.js +0 -29
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { SKETCH_ANNOTATION_RADIUS, } from "./model.js";
|
|
2
|
+
function distance(left, right) {
|
|
3
|
+
return Math.hypot(left.x - right.x, left.y - right.y);
|
|
4
|
+
}
|
|
5
|
+
export function distanceToSegment(point, start, end) {
|
|
6
|
+
const deltaX = end.x - start.x;
|
|
7
|
+
const deltaY = end.y - start.y;
|
|
8
|
+
const lengthSquared = deltaX * deltaX + deltaY * deltaY;
|
|
9
|
+
if (lengthSquared === 0)
|
|
10
|
+
return distance(point, start);
|
|
11
|
+
const projection = ((point.x - start.x) * deltaX + (point.y - start.y) * deltaY) / lengthSquared;
|
|
12
|
+
const position = Math.max(0, Math.min(1, projection));
|
|
13
|
+
return distance(point, {
|
|
14
|
+
x: start.x + position * deltaX,
|
|
15
|
+
y: start.y + position * deltaY,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function distanceToStroke(point, stroke) {
|
|
19
|
+
if (stroke.points.length === 1)
|
|
20
|
+
return distance(point, stroke.points[0]);
|
|
21
|
+
let closest = Number.POSITIVE_INFINITY;
|
|
22
|
+
for (let index = 1; index < stroke.points.length; index += 1) {
|
|
23
|
+
closest = Math.min(closest, distanceToSegment(point, stroke.points[index - 1], stroke.points[index]));
|
|
24
|
+
}
|
|
25
|
+
return closest;
|
|
26
|
+
}
|
|
27
|
+
function pointBounds(points) {
|
|
28
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
29
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
30
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
31
|
+
let maxY = Number.NEGATIVE_INFINITY;
|
|
32
|
+
for (const point of points) {
|
|
33
|
+
minX = Math.min(minX, point.x);
|
|
34
|
+
maxX = Math.max(maxX, point.x);
|
|
35
|
+
minY = Math.min(minY, point.y);
|
|
36
|
+
maxY = Math.max(maxY, point.y);
|
|
37
|
+
}
|
|
38
|
+
return { minX, maxX, minY, maxY };
|
|
39
|
+
}
|
|
40
|
+
/** Returns the topmost drawable object under a point in canvas coordinates. */
|
|
41
|
+
export function findSketchElementAt(point, strokes, annotations) {
|
|
42
|
+
for (let index = annotations.length - 1; index >= 0; index -= 1) {
|
|
43
|
+
const annotation = annotations[index];
|
|
44
|
+
if (distance(point, annotation.point) <= SKETCH_ANNOTATION_RADIUS * 1.5) {
|
|
45
|
+
return { kind: "annotation", id: annotation.id };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
for (let index = strokes.length - 1; index >= 0; index -= 1) {
|
|
49
|
+
const stroke = strokes[index];
|
|
50
|
+
const tolerance = Math.max(10, stroke.width / 2 + 6);
|
|
51
|
+
const bounds = pointBounds(stroke.points);
|
|
52
|
+
const insideRectangle = stroke.kind === "rectangle"
|
|
53
|
+
&& point.x >= bounds.minX - tolerance
|
|
54
|
+
&& point.x <= bounds.maxX + tolerance
|
|
55
|
+
&& point.y >= bounds.minY - tolerance
|
|
56
|
+
&& point.y <= bounds.maxY + tolerance;
|
|
57
|
+
if (insideRectangle || distanceToStroke(point, stroke) <= tolerance) {
|
|
58
|
+
return { kind: "stroke", id: stroke.id };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
function constrainedDelta(points, delta, bounds) {
|
|
64
|
+
if (points.length === 0)
|
|
65
|
+
return delta;
|
|
66
|
+
const { minX, maxX, minY, maxY } = pointBounds(points);
|
|
67
|
+
let x = delta.x;
|
|
68
|
+
let y = delta.y;
|
|
69
|
+
if (minX + x < 0)
|
|
70
|
+
x = -minX;
|
|
71
|
+
else if (maxX + x > bounds.width)
|
|
72
|
+
x = bounds.width - maxX;
|
|
73
|
+
if (minY + y < 0)
|
|
74
|
+
y = -minY;
|
|
75
|
+
else if (maxY + y > bounds.height)
|
|
76
|
+
y = bounds.height - maxY;
|
|
77
|
+
return { x, y };
|
|
78
|
+
}
|
|
79
|
+
export function translateSketchStroke(stroke, delta, bounds) {
|
|
80
|
+
const constrained = constrainedDelta(stroke.points, delta, bounds);
|
|
81
|
+
return {
|
|
82
|
+
...stroke,
|
|
83
|
+
points: stroke.points.map((point) => ({
|
|
84
|
+
x: point.x + constrained.x,
|
|
85
|
+
y: point.y + constrained.y,
|
|
86
|
+
})),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
export function translateSketchAnnotation(annotation, delta, bounds) {
|
|
90
|
+
const constrained = constrainedDelta([annotation.point], delta, bounds);
|
|
91
|
+
return {
|
|
92
|
+
...annotation,
|
|
93
|
+
point: {
|
|
94
|
+
x: annotation.point.x + constrained.x,
|
|
95
|
+
y: annotation.point.y + constrained.y,
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AgentSketchAttachment, AgentSketchMetadata } from "../agent/protocol.js";
|
|
2
|
+
import { type SketchQueueItem } from "./model.js";
|
|
3
|
+
export interface SketchHandoffEntry {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly revision: number;
|
|
6
|
+
readonly metadata: AgentSketchMetadata;
|
|
7
|
+
readonly annotatedImage: Blob;
|
|
8
|
+
}
|
|
9
|
+
export interface SketchClipboardHandoffSnapshot {
|
|
10
|
+
readonly localBatchId: string;
|
|
11
|
+
readonly entries: readonly SketchHandoffEntry[];
|
|
12
|
+
}
|
|
13
|
+
export declare function createSketchHandoffSnapshot(items: readonly SketchQueueItem[]): SketchClipboardHandoffSnapshot | null;
|
|
14
|
+
export declare function createSketchAttachments(handoff: SketchClipboardHandoffSnapshot): Promise<AgentSketchAttachment[]>;
|
|
15
|
+
export declare function sketchMetadataForHandoff(handoff: SketchClipboardHandoffSnapshot | null): readonly AgentSketchMetadata[];
|
|
16
|
+
export declare function getSketchClipboardHandoffSnapshot(): SketchClipboardHandoffSnapshot | null;
|
|
17
|
+
export declare function subscribeSketchClipboardHandoff(listener: () => void): () => void;
|
|
18
|
+
export declare function useSketchClipboardHandoff(): SketchClipboardHandoffSnapshot | null;
|
|
19
|
+
export declare function recordSketchClipboardHandoff(snapshot: SketchClipboardHandoffSnapshot | null): void;
|
|
20
|
+
export declare function clearSketchClipboardHandoff(): void;
|
|
21
|
+
export declare function resetSketchClipboardHandoff(): void;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
import { blobToBase64 } from "./raster.js";
|
|
3
|
+
import { toAgentSketchMetadata } from "./model.js";
|
|
4
|
+
const EMPTY_HANDOFF = null;
|
|
5
|
+
let handoffSnapshot = EMPTY_HANDOFF;
|
|
6
|
+
const listeners = new Set();
|
|
7
|
+
function notify() {
|
|
8
|
+
for (const listener of listeners) {
|
|
9
|
+
try {
|
|
10
|
+
listener();
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
// A handoff view must not prevent other subscribers from updating.
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function randomId() {
|
|
18
|
+
try {
|
|
19
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function")
|
|
20
|
+
return crypto.randomUUID();
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// Use the fallback below.
|
|
24
|
+
}
|
|
25
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
26
|
+
}
|
|
27
|
+
export function createSketchHandoffSnapshot(items) {
|
|
28
|
+
if (items.length === 0)
|
|
29
|
+
return null;
|
|
30
|
+
return {
|
|
31
|
+
localBatchId: randomId(),
|
|
32
|
+
entries: items.map((item) => ({
|
|
33
|
+
id: item.document.id,
|
|
34
|
+
revision: item.document.revision,
|
|
35
|
+
metadata: toAgentSketchMetadata(item.document),
|
|
36
|
+
annotatedImage: item.document.annotatedImage,
|
|
37
|
+
})),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export function createSketchAttachments(handoff) {
|
|
41
|
+
return Promise.all(handoff.entries.map(async (entry) => ({
|
|
42
|
+
...entry.metadata,
|
|
43
|
+
data: await blobToBase64(entry.annotatedImage),
|
|
44
|
+
})));
|
|
45
|
+
}
|
|
46
|
+
export function sketchMetadataForHandoff(handoff) {
|
|
47
|
+
return handoff?.entries.map((entry) => entry.metadata) ?? [];
|
|
48
|
+
}
|
|
49
|
+
export function getSketchClipboardHandoffSnapshot() {
|
|
50
|
+
return handoffSnapshot;
|
|
51
|
+
}
|
|
52
|
+
export function subscribeSketchClipboardHandoff(listener) {
|
|
53
|
+
listeners.add(listener);
|
|
54
|
+
return () => listeners.delete(listener);
|
|
55
|
+
}
|
|
56
|
+
export function useSketchClipboardHandoff() {
|
|
57
|
+
return useSyncExternalStore(subscribeSketchClipboardHandoff, getSketchClipboardHandoffSnapshot, getSketchClipboardHandoffSnapshot);
|
|
58
|
+
}
|
|
59
|
+
export function recordSketchClipboardHandoff(snapshot) {
|
|
60
|
+
handoffSnapshot = snapshot;
|
|
61
|
+
notify();
|
|
62
|
+
}
|
|
63
|
+
export function clearSketchClipboardHandoff() {
|
|
64
|
+
if (handoffSnapshot === null)
|
|
65
|
+
return;
|
|
66
|
+
handoffSnapshot = null;
|
|
67
|
+
notify();
|
|
68
|
+
}
|
|
69
|
+
export function resetSketchClipboardHandoff() {
|
|
70
|
+
handoffSnapshot = null;
|
|
71
|
+
notify();
|
|
72
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type CapturedSketch } from "./capture.js";
|
|
2
|
+
export type SketchCaptureState = "idle" | "sketching" | "capturing" | "ready" | "error";
|
|
3
|
+
export type SketchEntryTool = "pen" | "annotate";
|
|
4
|
+
export interface SketchInteractionSnapshot {
|
|
5
|
+
readonly captureState: SketchCaptureState;
|
|
6
|
+
readonly captured: CapturedSketch | null;
|
|
7
|
+
readonly editingId: string | null;
|
|
8
|
+
readonly error: string | null;
|
|
9
|
+
readonly initialTool: SketchEntryTool;
|
|
10
|
+
}
|
|
11
|
+
export declare function getSketchInteractionSnapshot(): SketchInteractionSnapshot;
|
|
12
|
+
export declare function subscribeSketchInteraction(listener: () => void): () => void;
|
|
13
|
+
export declare function useSketchInteraction(): SketchInteractionSnapshot;
|
|
14
|
+
export declare function isSketchInteractionActive(): boolean;
|
|
15
|
+
export declare function useSketchInteractionActive(): boolean;
|
|
16
|
+
export declare function beginSketchCapture(initialTool?: SketchEntryTool): void;
|
|
17
|
+
export declare function completeSketchCapture(hostElement: HTMLElement): Promise<CapturedSketch>;
|
|
18
|
+
export declare function cancelSketchInteraction(): void;
|
|
19
|
+
export declare function openSketchEditor(sketchId: string): void;
|
|
20
|
+
export declare function closeSketchEditor(): void;
|
|
21
|
+
export declare function resetSketchInteraction(): void;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
import { captureViewport, } from "./capture.js";
|
|
3
|
+
const EMPTY_SNAPSHOT = {
|
|
4
|
+
captureState: "idle",
|
|
5
|
+
captured: null,
|
|
6
|
+
editingId: null,
|
|
7
|
+
error: null,
|
|
8
|
+
initialTool: "pen",
|
|
9
|
+
};
|
|
10
|
+
let snapshot = EMPTY_SNAPSHOT;
|
|
11
|
+
let captureController = null;
|
|
12
|
+
const listeners = new Set();
|
|
13
|
+
function publish(next) {
|
|
14
|
+
snapshot = next;
|
|
15
|
+
for (const listener of listeners) {
|
|
16
|
+
try {
|
|
17
|
+
listener();
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// A view subscriber must not break the interaction state machine.
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function getSketchInteractionSnapshot() {
|
|
25
|
+
return snapshot;
|
|
26
|
+
}
|
|
27
|
+
export function subscribeSketchInteraction(listener) {
|
|
28
|
+
listeners.add(listener);
|
|
29
|
+
return () => listeners.delete(listener);
|
|
30
|
+
}
|
|
31
|
+
export function useSketchInteraction() {
|
|
32
|
+
return useSyncExternalStore(subscribeSketchInteraction, getSketchInteractionSnapshot, getSketchInteractionSnapshot);
|
|
33
|
+
}
|
|
34
|
+
export function isSketchInteractionActive() {
|
|
35
|
+
return snapshot.captureState !== "idle" || snapshot.captured !== null || snapshot.editingId !== null;
|
|
36
|
+
}
|
|
37
|
+
export function useSketchInteractionActive() {
|
|
38
|
+
const current = useSketchInteraction();
|
|
39
|
+
return current.captureState !== "idle" || current.captured !== null || current.editingId !== null;
|
|
40
|
+
}
|
|
41
|
+
export function beginSketchCapture(initialTool = "pen") {
|
|
42
|
+
captureController?.abort();
|
|
43
|
+
captureController = null;
|
|
44
|
+
publish({ captureState: "sketching", captured: null, editingId: null, error: null, initialTool });
|
|
45
|
+
}
|
|
46
|
+
export function completeSketchCapture(hostElement) {
|
|
47
|
+
captureController?.abort();
|
|
48
|
+
const controller = new AbortController();
|
|
49
|
+
captureController = controller;
|
|
50
|
+
const initialTool = snapshot.initialTool;
|
|
51
|
+
publish({ captureState: "capturing", captured: null, editingId: null, error: null, initialTool });
|
|
52
|
+
const options = { hostElement, signal: controller.signal };
|
|
53
|
+
return captureViewport(options)
|
|
54
|
+
.then((captured) => {
|
|
55
|
+
if (captureController !== controller)
|
|
56
|
+
return captured;
|
|
57
|
+
captureController = null;
|
|
58
|
+
publish({ captureState: "ready", captured, editingId: null, error: null, initialTool });
|
|
59
|
+
return captured;
|
|
60
|
+
})
|
|
61
|
+
.catch((error) => {
|
|
62
|
+
if (captureController !== controller)
|
|
63
|
+
throw error;
|
|
64
|
+
captureController = null;
|
|
65
|
+
if (controller.signal.aborted) {
|
|
66
|
+
publish(EMPTY_SNAPSHOT);
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
publish({
|
|
70
|
+
captureState: "error",
|
|
71
|
+
captured: null,
|
|
72
|
+
editingId: null,
|
|
73
|
+
error: error instanceof Error ? error.message : "The viewport could not be captured.",
|
|
74
|
+
initialTool,
|
|
75
|
+
});
|
|
76
|
+
throw error;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
export function cancelSketchInteraction() {
|
|
80
|
+
captureController?.abort();
|
|
81
|
+
captureController = null;
|
|
82
|
+
publish(EMPTY_SNAPSHOT);
|
|
83
|
+
}
|
|
84
|
+
export function openSketchEditor(sketchId) {
|
|
85
|
+
captureController?.abort();
|
|
86
|
+
captureController = null;
|
|
87
|
+
publish({ captureState: "idle", captured: null, editingId: sketchId, error: null, initialTool: "pen" });
|
|
88
|
+
}
|
|
89
|
+
export function closeSketchEditor() {
|
|
90
|
+
if (snapshot.captureState !== "ready" && snapshot.editingId === null)
|
|
91
|
+
return;
|
|
92
|
+
publish(EMPTY_SNAPSHOT);
|
|
93
|
+
}
|
|
94
|
+
export function resetSketchInteraction() {
|
|
95
|
+
captureController?.abort();
|
|
96
|
+
captureController = null;
|
|
97
|
+
snapshot = EMPTY_SNAPSHOT;
|
|
98
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { AgentSketchCaptureMetadata, AgentSketchMetadata } from "../agent/protocol.js";
|
|
2
|
+
export declare const SKETCH_SCHEMA_VERSION: 1;
|
|
3
|
+
export declare const SKETCH_DATABASE_NAME = "nudge-ui-sketches";
|
|
4
|
+
export declare const SKETCH_DATABASE_VERSION = 1;
|
|
5
|
+
export declare const SKETCH_DOCUMENTS_STORE = "documents";
|
|
6
|
+
export declare const SKETCH_HANDOFFS_STORE = "handoffs";
|
|
7
|
+
export declare const SKETCH_LIMITS: {
|
|
8
|
+
readonly completedSketches: 4;
|
|
9
|
+
readonly imageEdge: 2048;
|
|
10
|
+
readonly imageBytes: number;
|
|
11
|
+
readonly projectBytes: number;
|
|
12
|
+
readonly strokes: 500;
|
|
13
|
+
readonly points: 20000;
|
|
14
|
+
readonly annotations: 50;
|
|
15
|
+
readonly description: 2000;
|
|
16
|
+
readonly url: 2048;
|
|
17
|
+
readonly title: 512;
|
|
18
|
+
};
|
|
19
|
+
export declare const SKETCH_STROKE_WIDTH = 6;
|
|
20
|
+
export declare const SKETCH_STROKE_COLOR = "#0096ff";
|
|
21
|
+
export declare const SKETCH_STROKE_OUTLINE = "";
|
|
22
|
+
export declare const SKETCH_ANNOTATION_RADIUS = 16;
|
|
23
|
+
declare const LEGACY_SKETCH_STROKE_COLOR = "#ef4444";
|
|
24
|
+
declare const LEGACY_SKETCH_STROKE_OUTLINE = "#111827";
|
|
25
|
+
export type SketchStatus = "pending" | "dispatching" | "handing-off" | "needs-review" | "unknown";
|
|
26
|
+
export type SketchTransport = "local" | "clipboard" | "direct";
|
|
27
|
+
export type SketchHandoffState = SketchStatus;
|
|
28
|
+
export interface SketchPoint {
|
|
29
|
+
readonly x: number;
|
|
30
|
+
readonly y: number;
|
|
31
|
+
}
|
|
32
|
+
type SketchStrokeColor = typeof SKETCH_STROKE_COLOR | typeof LEGACY_SKETCH_STROKE_COLOR;
|
|
33
|
+
type SketchStrokeOutline = typeof SKETCH_STROKE_OUTLINE | typeof LEGACY_SKETCH_STROKE_OUTLINE;
|
|
34
|
+
export type SketchStrokeKind = "freehand" | "rectangle";
|
|
35
|
+
export interface SketchStroke {
|
|
36
|
+
readonly id: string;
|
|
37
|
+
/** Optional for compatibility with strokes saved before movable layers. */
|
|
38
|
+
readonly kind?: SketchStrokeKind;
|
|
39
|
+
readonly width: number;
|
|
40
|
+
readonly color: SketchStrokeColor;
|
|
41
|
+
readonly outlineColor: SketchStrokeOutline;
|
|
42
|
+
readonly points: readonly SketchPoint[];
|
|
43
|
+
}
|
|
44
|
+
export interface SketchAnnotation {
|
|
45
|
+
readonly id: string;
|
|
46
|
+
readonly number: number;
|
|
47
|
+
readonly point: SketchPoint;
|
|
48
|
+
readonly description: string;
|
|
49
|
+
}
|
|
50
|
+
export interface SketchCaptureMetadata extends AgentSketchCaptureMetadata {
|
|
51
|
+
readonly imageWidth: number;
|
|
52
|
+
readonly imageHeight: number;
|
|
53
|
+
}
|
|
54
|
+
export interface SketchDocument {
|
|
55
|
+
readonly schemaVersion: typeof SKETCH_SCHEMA_VERSION;
|
|
56
|
+
readonly projectId: string;
|
|
57
|
+
readonly id: string;
|
|
58
|
+
readonly revision: number;
|
|
59
|
+
readonly createdAt: number;
|
|
60
|
+
readonly updatedAt: number;
|
|
61
|
+
readonly capture: SketchCaptureMetadata;
|
|
62
|
+
readonly description: string;
|
|
63
|
+
readonly strokes: readonly SketchStroke[];
|
|
64
|
+
/** Optional for compatibility with sketches saved before annotations existed. */
|
|
65
|
+
readonly annotations?: readonly SketchAnnotation[];
|
|
66
|
+
readonly imageWidth: number;
|
|
67
|
+
readonly imageHeight: number;
|
|
68
|
+
readonly originalByteSize: number;
|
|
69
|
+
readonly annotatedByteSize: number;
|
|
70
|
+
readonly filename: string;
|
|
71
|
+
readonly originalImage: Blob;
|
|
72
|
+
readonly annotatedImage: Blob;
|
|
73
|
+
}
|
|
74
|
+
export interface SketchHandoffRecord {
|
|
75
|
+
readonly id: string;
|
|
76
|
+
readonly projectId: string;
|
|
77
|
+
readonly sketchId: string;
|
|
78
|
+
readonly sketchRevision: number;
|
|
79
|
+
readonly localBatchId: string;
|
|
80
|
+
readonly batchRevision?: number;
|
|
81
|
+
readonly transport: SketchTransport;
|
|
82
|
+
readonly agentRequestId?: string;
|
|
83
|
+
readonly timestamp: number;
|
|
84
|
+
readonly state: SketchHandoffState;
|
|
85
|
+
}
|
|
86
|
+
export interface SketchQueueItem {
|
|
87
|
+
readonly document: SketchDocument;
|
|
88
|
+
readonly handoff: SketchHandoffRecord | null;
|
|
89
|
+
readonly status: SketchStatus;
|
|
90
|
+
}
|
|
91
|
+
export declare function createSketchFilename(id: string, revision: number): string;
|
|
92
|
+
export declare function isFiniteNumber(value: unknown): value is number;
|
|
93
|
+
export declare function isSketchCaptureMetadata(value: unknown): value is SketchCaptureMetadata;
|
|
94
|
+
export declare function isSketchPoint(value: unknown): value is SketchPoint;
|
|
95
|
+
export declare function isSketchAnnotation(value: unknown): value is SketchAnnotation;
|
|
96
|
+
export declare function isSketchStroke(value: unknown): value is SketchStroke;
|
|
97
|
+
export declare function isSketchDocument(value: unknown): value is SketchDocument;
|
|
98
|
+
export declare function isSketchHandoffRecord(value: unknown): value is SketchHandoffRecord;
|
|
99
|
+
export declare function cloneSketchDocument(document: SketchDocument): SketchDocument;
|
|
100
|
+
export declare function cloneSketchHandoff(handoff: SketchHandoffRecord): SketchHandoffRecord;
|
|
101
|
+
export declare function sketchContentFingerprint(description: string, strokes: readonly SketchStroke[], annotations?: readonly SketchAnnotation[]): string;
|
|
102
|
+
export declare function sameSketchContent(document: Pick<SketchDocument, "description" | "strokes" | "annotations">, description: string, strokes: readonly SketchStroke[], annotations?: readonly SketchAnnotation[]): boolean;
|
|
103
|
+
export declare function toAgentSketchMetadata(document: SketchDocument): AgentSketchMetadata;
|
|
104
|
+
export {};
|