iterate-ui-overlay 0.1.0
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/LICENSE +21 -0
- package/dist/index.d.ts +344 -0
- package/dist/index.js +4873 -0
- package/dist/standalone.global.js +123 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Connor White
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { SelectedElement, TextSelection, DrawingData, Rect, ClientMessage, ServerMessage, IterationInfo } from 'iterate-ui-core';
|
|
4
|
+
|
|
5
|
+
type ToolMode = "select" | "move" | "draw" | "browse";
|
|
6
|
+
interface IterateOverlayProps {
|
|
7
|
+
/** Which tool mode is active */
|
|
8
|
+
mode: ToolMode;
|
|
9
|
+
/** Name of the current iteration being viewed */
|
|
10
|
+
iteration: string;
|
|
11
|
+
/** WebSocket URL for daemon connection (auto-detected if omitted) */
|
|
12
|
+
wsUrl?: string;
|
|
13
|
+
/** Reference to the iteration iframe */
|
|
14
|
+
iframeRef: React.RefObject<HTMLIFrameElement | null>;
|
|
15
|
+
/** Current pending change count (passed up for toolbar badge) */
|
|
16
|
+
onBatchCountChange?: (count: number) => void;
|
|
17
|
+
/** Current pending move count (passed up for toolbar badge) */
|
|
18
|
+
onMoveCountChange?: (count: number) => void;
|
|
19
|
+
/** Whether any changes are currently being processed (in-progress) */
|
|
20
|
+
onProcessingChange?: (processing: boolean) => void;
|
|
21
|
+
/** Whether live preview is enabled */
|
|
22
|
+
previewMode?: boolean;
|
|
23
|
+
/** Whether the toolbar is visible — when false, badges are hidden and tools are disabled */
|
|
24
|
+
visible?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Main overlay component for iterate.
|
|
28
|
+
* Renders element selection tools, change panel, and drag handler
|
|
29
|
+
* on top of an iteration's iframe.
|
|
30
|
+
*
|
|
31
|
+
* Changes and DOM changes are pushed to the daemon immediately on creation
|
|
32
|
+
* (no local batching). The daemon is the source of truth — state is synced via
|
|
33
|
+
* WebSocket and badges are removed when the agent implements them.
|
|
34
|
+
*/
|
|
35
|
+
declare function IterateOverlay({ mode, iteration, wsUrl, iframeRef, onBatchCountChange, onMoveCountChange, onProcessingChange, previewMode, visible, }: IterateOverlayProps): react_jsx_runtime.JSX.Element;
|
|
36
|
+
|
|
37
|
+
interface PickedElement extends SelectedElement {
|
|
38
|
+
/** The raw DOM element (not serialized) */
|
|
39
|
+
domElement: Element;
|
|
40
|
+
}
|
|
41
|
+
interface ElementPickerProps {
|
|
42
|
+
active: boolean;
|
|
43
|
+
iframeRef: React.RefObject<HTMLIFrameElement | null>;
|
|
44
|
+
selectedElements: PickedElement[];
|
|
45
|
+
onSelect: (elements: PickedElement[], clickPosition?: {
|
|
46
|
+
x: number;
|
|
47
|
+
y: number;
|
|
48
|
+
}) => void;
|
|
49
|
+
/** When true, suppress hover highlight (e.g. during marquee drag) */
|
|
50
|
+
suppressHover?: boolean;
|
|
51
|
+
/** Shared ref — when true, a marquee drag just finished and the click should be swallowed */
|
|
52
|
+
justFinishedDragRef?: React.RefObject<boolean>;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Overlay that highlights elements on hover and captures clicks.
|
|
56
|
+
* Supports multi-select with Ctrl/Cmd+Click.
|
|
57
|
+
* Shows React component names and source file paths when available.
|
|
58
|
+
*/
|
|
59
|
+
declare function ElementPicker({ active, iframeRef, selectedElements, onSelect, suppressHover, justFinishedDragRef, }: ElementPickerProps): react_jsx_runtime.JSX.Element | null;
|
|
60
|
+
|
|
61
|
+
interface MarqueeSelectProps {
|
|
62
|
+
active: boolean;
|
|
63
|
+
iframeRef: React.RefObject<HTMLIFrameElement | null>;
|
|
64
|
+
onSelect: (elements: PickedElement[]) => void;
|
|
65
|
+
/** Called when marquee drag starts/stops */
|
|
66
|
+
onDragStateChange?: (isDragging: boolean) => void;
|
|
67
|
+
/** Shared ref — set to true after a successful drag so ElementPicker can swallow the click */
|
|
68
|
+
justFinishedDragRef?: React.RefObject<boolean>;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Rubber-band / marquee multi-select overlay.
|
|
72
|
+
* Click-drag on empty space to draw a selection rectangle,
|
|
73
|
+
* then select all elements within the rectangle.
|
|
74
|
+
* Highlights contained elements live during drag.
|
|
75
|
+
*/
|
|
76
|
+
declare function MarqueeSelect({ active, iframeRef, onSelect, onDragStateChange, justFinishedDragRef, }: MarqueeSelectProps): react_jsx_runtime.JSX.Element | null;
|
|
77
|
+
|
|
78
|
+
interface TextSelectProps {
|
|
79
|
+
active: boolean;
|
|
80
|
+
iframeRef: React.RefObject<HTMLIFrameElement | null>;
|
|
81
|
+
onTextSelect: (selection: TextSelection | null) => void;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Captures text selections within the iframe.
|
|
85
|
+
* When the user highlights text using native browser selection,
|
|
86
|
+
* captures the text, containing element, and range offsets.
|
|
87
|
+
*/
|
|
88
|
+
declare function TextSelect({ active, iframeRef, onTextSelect, }: TextSelectProps): react_jsx_runtime.JSX.Element | null;
|
|
89
|
+
|
|
90
|
+
interface MarkerDrawProps {
|
|
91
|
+
active: boolean;
|
|
92
|
+
iframeRef: React.RefObject<HTMLIFrameElement | null>;
|
|
93
|
+
/** Called when drawing is complete — returns nearby elements + drawing data */
|
|
94
|
+
onDrawComplete: (elements: PickedElement[], drawing: DrawingData) => void;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Freehand drawing overlay (marker tool).
|
|
98
|
+
*
|
|
99
|
+
* When active, the user can draw on the screen. On mouseup, the drawing
|
|
100
|
+
* is captured as an SVG path, nearby/underlying elements are identified,
|
|
101
|
+
* and the annotation panel is opened.
|
|
102
|
+
*/
|
|
103
|
+
declare function MarkerDraw({ active, iframeRef, onDrawComplete, }: MarkerDrawProps): react_jsx_runtime.JSX.Element | null;
|
|
104
|
+
|
|
105
|
+
interface SelectionPanelProps {
|
|
106
|
+
selectedElements: PickedElement[];
|
|
107
|
+
textSelection: TextSelection | null;
|
|
108
|
+
onRemoveElement: (index: number) => void;
|
|
109
|
+
onAddToBatch: (comment: string) => void;
|
|
110
|
+
onClearSelection: () => void;
|
|
111
|
+
clickPosition?: {
|
|
112
|
+
x: number;
|
|
113
|
+
y: number;
|
|
114
|
+
} | null;
|
|
115
|
+
/** When true, the header shows "Path" with no dropdown (marker/draw tool) */
|
|
116
|
+
isDrawing?: boolean;
|
|
117
|
+
/** Pre-fill comment when editing an existing change */
|
|
118
|
+
initialComment?: string;
|
|
119
|
+
/** Shown as a left-aligned trash button in the toolbar (for editing existing changes) */
|
|
120
|
+
onDelete?: () => void;
|
|
121
|
+
/** Reference to the iteration iframe (for click-outside detection) */
|
|
122
|
+
iframeRef?: React.RefObject<HTMLIFrameElement | null>;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Flat, greyscale popup with a layered card effect.
|
|
126
|
+
*
|
|
127
|
+
* The header (component name + CSS drawer) sits on a recessed lower layer.
|
|
128
|
+
* The main card (textarea + buttons) floats on top with rounded top corners,
|
|
129
|
+
* so the CSS drawer feels like it slides out from behind the main card.
|
|
130
|
+
*
|
|
131
|
+
* Animates in with a springy scale-up and fades out on dismiss.
|
|
132
|
+
*/
|
|
133
|
+
declare function SelectionPanel({ selectedElements, textSelection, onAddToBatch, onClearSelection, clickPosition, isDrawing, initialComment, onDelete, iframeRef, }: SelectionPanelProps): react_jsx_runtime.JSX.Element | null;
|
|
134
|
+
|
|
135
|
+
/** A completed move with rollback info for live preview */
|
|
136
|
+
interface PendingMove {
|
|
137
|
+
iteration?: string;
|
|
138
|
+
/** Page URL where this move was made */
|
|
139
|
+
url?: string;
|
|
140
|
+
selector: string;
|
|
141
|
+
from: Rect;
|
|
142
|
+
to: Rect;
|
|
143
|
+
computedStyles: Record<string, string>;
|
|
144
|
+
componentName: string | null;
|
|
145
|
+
sourceLocation: string | null;
|
|
146
|
+
/** Whether the element is the root of its React component (vs a child inside it) */
|
|
147
|
+
isComponentRoot?: boolean;
|
|
148
|
+
/** For flex/grid reordering: the target sibling index */
|
|
149
|
+
reorderIndex?: number;
|
|
150
|
+
/** For flex/grid reordering: the original sibling index before drag */
|
|
151
|
+
originalSiblingIndex?: number;
|
|
152
|
+
/** The original parent selector for reorder context */
|
|
153
|
+
parentSelector?: string;
|
|
154
|
+
/** The destination parent selector (for cross-parent reparenting) */
|
|
155
|
+
targetParentSelector?: string;
|
|
156
|
+
/** Window scroll offset when this move was created (for scroll-aware rendering) */
|
|
157
|
+
scrollOffset?: {
|
|
158
|
+
x: number;
|
|
159
|
+
y: number;
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
interface DragHandlerProps {
|
|
163
|
+
active: boolean;
|
|
164
|
+
iframeRef: React.RefObject<HTMLIFrameElement | null>;
|
|
165
|
+
/** Called when a drag completes with full move data */
|
|
166
|
+
onMove: (move: PendingMove) => void;
|
|
167
|
+
/** Pending moves to visualize origin markers for */
|
|
168
|
+
pendingMoves: PendingMove[];
|
|
169
|
+
/** Whether to show the live preview (transforms applied) vs original positions */
|
|
170
|
+
previewMode: boolean;
|
|
171
|
+
/** Called when user deletes a pending move via its badge popup */
|
|
172
|
+
onDeleteMove?: (index: number) => void;
|
|
173
|
+
/** @deprecated No longer used — deltas applied via direct DOM mutation in IterateOverlay */
|
|
174
|
+
moveDeltas?: Record<number, {
|
|
175
|
+
dx: number;
|
|
176
|
+
dy: number;
|
|
177
|
+
}>;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Drag-to-move handler with two behaviors:
|
|
181
|
+
*
|
|
182
|
+
* 1. Flex/grid children: Live DOM reordering — the element physically moves
|
|
183
|
+
* among its siblings as the user drags. A drop indicator line shows the
|
|
184
|
+
* target gap. On mouseup the reorder is recorded as a dom-change.
|
|
185
|
+
*
|
|
186
|
+
* 2. All other elements: Records a positional move intent. Element stays in place,
|
|
187
|
+
* a dotted border shows current position, and an arrow points to where it was
|
|
188
|
+
* dragged.
|
|
189
|
+
*/
|
|
190
|
+
declare function DragHandler({ active, iframeRef, onMove, pendingMoves, previewMode, onDeleteMove, moveDeltas, }: DragHandlerProps): react_jsx_runtime.JSX.Element;
|
|
191
|
+
|
|
192
|
+
type MessageHandler = (msg: ServerMessage) => void;
|
|
193
|
+
type IterationsChangeHandler = (iterations: Record<string, IterationInfo>) => void;
|
|
194
|
+
type ToolModeHandler = (mode: string) => void;
|
|
195
|
+
/**
|
|
196
|
+
* WebSocket connection to the iterate daemon.
|
|
197
|
+
* Handles reconnection, message dispatch, and iteration state tracking.
|
|
198
|
+
*/
|
|
199
|
+
declare class DaemonConnection {
|
|
200
|
+
private ws;
|
|
201
|
+
private handlers;
|
|
202
|
+
private iterationsHandlers;
|
|
203
|
+
private toolModeHandlers;
|
|
204
|
+
private url;
|
|
205
|
+
private reconnectTimer;
|
|
206
|
+
private _iterations;
|
|
207
|
+
constructor(url?: string);
|
|
208
|
+
connect(): void;
|
|
209
|
+
disconnect(): void;
|
|
210
|
+
send(msg: ClientMessage): void;
|
|
211
|
+
onMessage(handler: MessageHandler): () => void;
|
|
212
|
+
/** Subscribe to iteration list changes */
|
|
213
|
+
onIterationsChange(handler: IterationsChangeHandler): () => void;
|
|
214
|
+
/** Current iterations snapshot */
|
|
215
|
+
get iterations(): Record<string, IterationInfo>;
|
|
216
|
+
get connected(): boolean;
|
|
217
|
+
/** Send a tool mode change to the daemon for relay to all clients */
|
|
218
|
+
sendToolMode(mode: string): void;
|
|
219
|
+
/** Subscribe to tool mode changes relayed from other clients */
|
|
220
|
+
onToolModeChange(handler: ToolModeHandler): () => void;
|
|
221
|
+
/** Dispatch tool mode changes from server messages */
|
|
222
|
+
private trackToolMode;
|
|
223
|
+
/** Update internal iterations state from server messages */
|
|
224
|
+
private trackIterations;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
interface FloatingPanelProps {
|
|
228
|
+
mode: ToolMode;
|
|
229
|
+
onModeChange: (mode: ToolMode) => void;
|
|
230
|
+
visible: boolean;
|
|
231
|
+
onVisibilityChange: (visible: boolean) => void;
|
|
232
|
+
/** Number of annotations in the pending batch */
|
|
233
|
+
batchCount?: number;
|
|
234
|
+
/** Number of pending moves */
|
|
235
|
+
moveCount?: number;
|
|
236
|
+
/** Called when user clicks Trash (clear all annotations and moves) */
|
|
237
|
+
onClearBatch?: () => void;
|
|
238
|
+
/** Called when user clicks Copy (copy annotations to clipboard) */
|
|
239
|
+
onCopyBatch?: () => void;
|
|
240
|
+
/** Called when user clicks Undo (revert last move) */
|
|
241
|
+
onUndoMove?: () => void;
|
|
242
|
+
/** Available iterations (from daemon state) */
|
|
243
|
+
iterations?: Record<string, IterationInfo>;
|
|
244
|
+
/** Currently active iteration name */
|
|
245
|
+
activeIteration?: string;
|
|
246
|
+
/** Called when user switches iteration */
|
|
247
|
+
onIterationChange?: (name: string) => void;
|
|
248
|
+
/** Called when user wants to create iterations (fork) */
|
|
249
|
+
onFork?: () => void;
|
|
250
|
+
/** Called when user wants to pick the active iteration */
|
|
251
|
+
onPick?: (name: string) => void | Promise<void>;
|
|
252
|
+
/** Called when user wants to discard all iterations and keep original */
|
|
253
|
+
onDiscard?: () => void | Promise<void>;
|
|
254
|
+
/** Whether currently viewing an iteration (not Original) */
|
|
255
|
+
isViewingIteration?: boolean;
|
|
256
|
+
/** Badge counts per tab (tab name → total pending changes) */
|
|
257
|
+
tabBadgeCounts?: Record<string, number>;
|
|
258
|
+
/** Set of iteration names whose iframes have sent a "ready" postMessage */
|
|
259
|
+
readyIframes?: Set<string>;
|
|
260
|
+
/** Whether any changes are currently being processed (in-progress) */
|
|
261
|
+
processing?: boolean;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Floating toolbar panel with icon-based tools and iteration selector.
|
|
265
|
+
* Single container that animates between collapsed (logo only) and expanded states.
|
|
266
|
+
* Can be dragged to any corner of the screen.
|
|
267
|
+
*
|
|
268
|
+
* All collapsible tools live in a single ToolGroup for consistent flex spacing.
|
|
269
|
+
* Sections (separated by dividers):
|
|
270
|
+
* 1. Annotation tools (select, draw, move)
|
|
271
|
+
* 2. Change tools (undo, trash, copy, send) — no internal divider
|
|
272
|
+
* 3. Branching tools (fork/iterate, merge/pick, discard)
|
|
273
|
+
* 4. Close/open toggle (always visible)
|
|
274
|
+
*/
|
|
275
|
+
declare function FloatingPanel({ mode, onModeChange, visible, onVisibilityChange, batchCount, moveCount, onClearBatch, onCopyBatch, onUndoMove, iterations, activeIteration, onIterationChange, onFork, onPick, onDiscard, isViewingIteration, tabBadgeCounts, readyIframes, processing, }: FloatingPanelProps): react_jsx_runtime.JSX.Element;
|
|
276
|
+
|
|
277
|
+
interface ThemeTokens {
|
|
278
|
+
panelBg: string;
|
|
279
|
+
cardBg: string;
|
|
280
|
+
toolbarBg: string;
|
|
281
|
+
drawerBg: string;
|
|
282
|
+
hoverBg: string;
|
|
283
|
+
activeBg: string;
|
|
284
|
+
border: string;
|
|
285
|
+
textPrimary: string;
|
|
286
|
+
textSecondary: string;
|
|
287
|
+
textTertiary: string;
|
|
288
|
+
textDisabled: string;
|
|
289
|
+
iconDefault: string;
|
|
290
|
+
iconHover: string;
|
|
291
|
+
suspenseOverlay: string;
|
|
292
|
+
spinnerBg: string;
|
|
293
|
+
spinnerFg: string;
|
|
294
|
+
tooltipBg: string;
|
|
295
|
+
tooltipText: string;
|
|
296
|
+
tooltipKeyBg: string;
|
|
297
|
+
tooltipKeyText: string;
|
|
298
|
+
buttonBg: string;
|
|
299
|
+
buttonText: string;
|
|
300
|
+
}
|
|
301
|
+
declare function useTheme(): ThemeTokens;
|
|
302
|
+
declare function ThemeProvider({ children, targetDocument, }: {
|
|
303
|
+
children: React.ReactNode;
|
|
304
|
+
/** Optional document to detect theme from (e.g. an iteration iframe's contentDocument).
|
|
305
|
+
* Falls back to the current document when null/undefined. */
|
|
306
|
+
targetDocument?: Document | null;
|
|
307
|
+
}): React.FunctionComponentElement<React.ProviderProps<ThemeTokens>>;
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Generate a unique CSS selector for a DOM element.
|
|
311
|
+
* Produces a human-readable path like: article > section.hero > h1
|
|
312
|
+
*/
|
|
313
|
+
declare function generateSelector(element: Element): string;
|
|
314
|
+
/**
|
|
315
|
+
* Build a human-readable ancestor path (up to maxDepth ancestors).
|
|
316
|
+
* Example: "main > section > div.card"
|
|
317
|
+
*/
|
|
318
|
+
declare function buildAncestorPath(element: Element, maxDepth?: number): string;
|
|
319
|
+
/**
|
|
320
|
+
* Generate a human-readable label for an element.
|
|
321
|
+
*/
|
|
322
|
+
declare function describeElement(element: Element): string;
|
|
323
|
+
/** Capture text content near the element (own + sibling text) */
|
|
324
|
+
declare function captureContextText(element: Element): string;
|
|
325
|
+
/**
|
|
326
|
+
* Get the nearest React component name for a DOM element by walking the
|
|
327
|
+
* fiber tree. Returns just the innermost user component (e.g. "Header"),
|
|
328
|
+
* not the full ancestry chain.
|
|
329
|
+
*
|
|
330
|
+
* Falls back to data-iterate-component/data-iterate-source attributes
|
|
331
|
+
* if the babel plugin injected them.
|
|
332
|
+
*/
|
|
333
|
+
declare function getComponentInfo(element: Element): {
|
|
334
|
+
component: string | null;
|
|
335
|
+
source: string | null;
|
|
336
|
+
isComponentRoot: boolean;
|
|
337
|
+
};
|
|
338
|
+
/**
|
|
339
|
+
* Extract computed styles relevant to the element's type.
|
|
340
|
+
* Text elements get typography props, containers get layout props, etc.
|
|
341
|
+
*/
|
|
342
|
+
declare function getRelevantStyles(element: Element): Record<string, string>;
|
|
343
|
+
|
|
344
|
+
export { DaemonConnection, DragHandler, ElementPicker, FloatingPanel, IterateOverlay, type IterateOverlayProps, MarkerDraw, MarqueeSelect, type PendingMove, type PickedElement, SelectionPanel, TextSelect, ThemeProvider, type ThemeTokens, type ToolMode, buildAncestorPath, captureContextText, describeElement, generateSelector, getComponentInfo, getRelevantStyles, useTheme };
|