@andsam/shopify-grab 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.
@@ -0,0 +1,448 @@
1
+ type DeepPartial<T> = {
2
+ [P in keyof T]?: T[P] extends object ? T[P] extends (...args: unknown[]) => unknown ? T[P] : DeepPartial<T[P]> : T[P];
3
+ };
4
+ interface Theme {
5
+ /**
6
+ * Globally toggle the entire overlay
7
+ * @default true
8
+ */
9
+ enabled?: boolean;
10
+ /**
11
+ * Base hue (0-360) used to generate colors throughout the interface using HSL color space
12
+ * @default 0
13
+ */
14
+ hue?: number;
15
+ /**
16
+ * The highlight box that appears when hovering over an element before selecting it
17
+ */
18
+ selectionBox?: {
19
+ /**
20
+ * Whether to show the selection highlight
21
+ * @default true
22
+ */
23
+ enabled?: boolean;
24
+ };
25
+ /**
26
+ * The rectangular selection area that appears when clicking and dragging to select multiple elements
27
+ */
28
+ dragBox?: {
29
+ /**
30
+ * Whether to show the drag selection box
31
+ * @default true
32
+ */
33
+ enabled?: boolean;
34
+ };
35
+ /**
36
+ * Brief flash/highlight boxes that appear on elements immediately after they're successfully grabbed/copied
37
+ */
38
+ grabbedBoxes?: {
39
+ /**
40
+ * Whether to show these success flash effects
41
+ * @default true
42
+ */
43
+ enabled?: boolean;
44
+ };
45
+ /**
46
+ * The floating label that follows the cursor showing information about the currently hovered element
47
+ */
48
+ elementLabel?: {
49
+ /**
50
+ * Whether to show the label
51
+ * @default true
52
+ */
53
+ enabled?: boolean;
54
+ };
55
+ /**
56
+ * The crosshair cursor overlay that helps with precise element targeting
57
+ */
58
+ crosshair?: {
59
+ /**
60
+ * Whether to show the crosshair
61
+ * @default true
62
+ */
63
+ enabled?: boolean;
64
+ };
65
+ /**
66
+ * The floating toolbar that allows toggling Shopify Grab activation
67
+ */
68
+ toolbar?: {
69
+ /**
70
+ * Whether to show the toolbar
71
+ * @default true
72
+ */
73
+ enabled?: boolean;
74
+ };
75
+ }
76
+ interface ShopifyGrabState {
77
+ isActive: boolean;
78
+ isDragging: boolean;
79
+ isCopying: boolean;
80
+ isPromptMode: boolean;
81
+ isCrosshairVisible: boolean;
82
+ isSelectionBoxVisible: boolean;
83
+ isDragBoxVisible: boolean;
84
+ targetElement: Element | null;
85
+ dragBounds: DragRect | null;
86
+ /**
87
+ * Currently visible grabbed boxes (success flash effects).
88
+ * These are temporary visual indicators shown after elements are grabbed/copied.
89
+ */
90
+ grabbedBoxes: Array<{
91
+ id: string;
92
+ bounds: OverlayBounds;
93
+ createdAt: number;
94
+ }>;
95
+ selectionFilePath: string | null;
96
+ toolbarState: ToolbarState | null;
97
+ }
98
+ type ElementLabelVariant = "hover" | "processing" | "success";
99
+ interface PromptModeContext {
100
+ x: number;
101
+ y: number;
102
+ targetElement: Element | null;
103
+ }
104
+ interface CrosshairContext {
105
+ x: number;
106
+ y: number;
107
+ }
108
+ interface ElementLabelContext {
109
+ x: number;
110
+ y: number;
111
+ content: string;
112
+ element?: Element;
113
+ tagName?: string;
114
+ componentName?: string;
115
+ filePath?: string;
116
+ lineNumber?: number;
117
+ }
118
+ type ActivationKey = string | ((event: KeyboardEvent) => boolean);
119
+ interface AgentContext<T = unknown> {
120
+ content: string[];
121
+ prompt: string;
122
+ options?: T;
123
+ sessionId?: string;
124
+ }
125
+ interface AgentSession {
126
+ id: string;
127
+ context: AgentContext;
128
+ lastStatus: string;
129
+ isStreaming: boolean;
130
+ isFading?: boolean;
131
+ createdAt: number;
132
+ lastUpdatedAt: number;
133
+ position: {
134
+ x: number;
135
+ y: number;
136
+ };
137
+ selectionBounds: OverlayBounds[];
138
+ tagName?: string;
139
+ componentName?: string;
140
+ error?: string;
141
+ }
142
+ interface AgentProvider<T = any> {
143
+ send: (context: AgentContext<T>, signal: AbortSignal) => AsyncIterable<string>;
144
+ resume?: (sessionId: string, signal: AbortSignal, storage: AgentSessionStorage) => AsyncIterable<string>;
145
+ abort?: (sessionId: string) => Promise<void>;
146
+ supportsResume?: boolean;
147
+ supportsFollowUp?: boolean;
148
+ dismissButtonText?: string;
149
+ checkConnection?: () => Promise<boolean>;
150
+ getCompletionMessage?: () => string | undefined;
151
+ undo?: () => Promise<void>;
152
+ canUndo?: () => boolean;
153
+ redo?: () => Promise<void>;
154
+ canRedo?: () => boolean;
155
+ }
156
+ interface AgentSessionStorage {
157
+ getItem(key: string): string | null;
158
+ setItem(key: string, value: string): void;
159
+ removeItem(key: string): void;
160
+ }
161
+ interface AgentCompleteResult {
162
+ error?: string;
163
+ }
164
+ interface AgentOptions<T = any> {
165
+ provider?: AgentProvider<T>;
166
+ storage?: AgentSessionStorage | null;
167
+ getOptions?: () => T;
168
+ onStart?: (session: AgentSession, elements: Element[]) => void;
169
+ onStatus?: (status: string, session: AgentSession) => void;
170
+ onComplete?: (session: AgentSession, elements: Element[]) => AgentCompleteResult | void | Promise<AgentCompleteResult | void>;
171
+ onError?: (error: Error, session: AgentSession) => void;
172
+ onResume?: (session: AgentSession) => void;
173
+ onAbort?: (session: AgentSession, elements: Element[]) => void;
174
+ onUndo?: (session: AgentSession, elements: Element[]) => void;
175
+ onDismiss?: (session: AgentSession, elements: Element[]) => void;
176
+ }
177
+ type ActivationMode = "toggle" | "hold";
178
+ interface ActionContext {
179
+ element: Element;
180
+ elements: Element[];
181
+ filePath?: string;
182
+ lineNumber?: number;
183
+ componentName?: string;
184
+ tagName?: string;
185
+ enterPromptMode?: (agent?: AgentOptions) => void;
186
+ }
187
+ interface ContextMenuAction {
188
+ id: string;
189
+ label: string;
190
+ shortcut?: string;
191
+ enabled?: boolean | ((context: ActionContext) => boolean);
192
+ onAction: (context: ActionContext) => void;
193
+ agent?: AgentOptions;
194
+ }
195
+ interface ScreenshotBounds {
196
+ x: number;
197
+ y: number;
198
+ width: number;
199
+ height: number;
200
+ }
201
+ interface PluginHooks {
202
+ onActivate?: () => void;
203
+ onDeactivate?: () => void;
204
+ onElementHover?: (element: Element) => void;
205
+ onElementSelect?: (element: Element) => void;
206
+ onDragStart?: (startX: number, startY: number) => void;
207
+ onDragEnd?: (elements: Element[], bounds: DragRect) => void;
208
+ onBeforeCopy?: (elements: Element[]) => void | Promise<void>;
209
+ transformCopyContent?: (content: string, elements: Element[]) => string | Promise<string>;
210
+ onAfterCopy?: (elements: Element[], success: boolean) => void;
211
+ onCopySuccess?: (elements: Element[], content: string) => void;
212
+ onCopyError?: (error: Error) => void;
213
+ onStateChange?: (state: ShopifyGrabState) => void;
214
+ onPromptModeChange?: (isPromptMode: boolean, context: PromptModeContext) => void;
215
+ onSelectionBox?: (visible: boolean, bounds: OverlayBounds | null, element: Element | null) => void;
216
+ onDragBox?: (visible: boolean, bounds: OverlayBounds | null) => void;
217
+ onGrabbedBox?: (bounds: OverlayBounds, element: Element) => void;
218
+ onElementLabel?: (visible: boolean, variant: ElementLabelVariant, context: ElementLabelContext) => void;
219
+ onCrosshair?: (visible: boolean, context: CrosshairContext) => void;
220
+ onContextMenu?: (element: Element, position: {
221
+ x: number;
222
+ y: number;
223
+ }) => void;
224
+ onOpenFile?: (filePath: string, lineNumber?: number) => boolean | void;
225
+ transformHtmlContent?: (html: string, elements: Element[]) => string | Promise<string>;
226
+ transformScreenshot?: (blob: Blob, elements: Element[], bounds: ScreenshotBounds) => Blob | Promise<Blob>;
227
+ transformAgentContext?: (context: AgentContext, elements: Element[]) => AgentContext | Promise<AgentContext>;
228
+ transformActionContext?: (context: ActionContext) => ActionContext;
229
+ transformOpenFileUrl?: (url: string, filePath: string, lineNumber?: number) => string;
230
+ transformSnippet?: (snippet: string, element: Element) => string | Promise<string>;
231
+ }
232
+ interface PluginConfig {
233
+ theme?: DeepPartial<Theme>;
234
+ options?: SettableOptions;
235
+ actions?: ContextMenuAction[];
236
+ hooks?: PluginHooks;
237
+ cleanup?: () => void;
238
+ }
239
+ interface Plugin {
240
+ name: string;
241
+ theme?: DeepPartial<Theme>;
242
+ options?: SettableOptions;
243
+ actions?: ContextMenuAction[];
244
+ hooks?: PluginHooks;
245
+ setup?: (api: ShopifyGrabAPI) => PluginConfig | void;
246
+ }
247
+ interface Options {
248
+ enabled?: boolean;
249
+ activationMode?: ActivationMode;
250
+ keyHoldDuration?: number;
251
+ allowActivationInsideInput?: boolean;
252
+ maxContextLines?: number;
253
+ activationKey?: ActivationKey;
254
+ getContent?: (elements: Element[]) => Promise<string> | string;
255
+ /**
256
+ * Whether to freeze page state updates while Shopify Grab is active.
257
+ * This prevents UI changes from interfering with element selection.
258
+ * @default true
259
+ */
260
+ freezePageUpdates?: boolean;
261
+ }
262
+ interface SettableOptions extends Options {
263
+ enabled?: never;
264
+ }
265
+ interface SourceInfo {
266
+ filePath: string;
267
+ lineNumber: number | null;
268
+ componentName: string | null;
269
+ }
270
+ interface ToolbarState {
271
+ edge: "top" | "bottom" | "left" | "right";
272
+ ratio: number;
273
+ collapsed: boolean;
274
+ enabled: boolean;
275
+ }
276
+ interface ShopifyGrabAPI {
277
+ activate: () => void;
278
+ deactivate: () => void;
279
+ toggle: () => void;
280
+ isActive: () => boolean;
281
+ isEnabled: () => boolean;
282
+ setEnabled: (enabled: boolean) => void;
283
+ getToolbarState: () => ToolbarState | null;
284
+ setToolbarState: (state: Partial<ToolbarState>) => void;
285
+ onToolbarStateChange: (callback: (state: ToolbarState) => void) => () => void;
286
+ dispose: () => void;
287
+ copyElement: (elements: Element | Element[]) => Promise<boolean>;
288
+ getSource: (element: Element) => Promise<SourceInfo | null>;
289
+ getState: () => ShopifyGrabState;
290
+ setOptions: (options: SettableOptions) => void;
291
+ registerPlugin: (plugin: Plugin) => void;
292
+ unregisterPlugin: (name: string) => void;
293
+ getPlugins: () => string[];
294
+ getDisplayName: (element: Element) => string | null;
295
+ }
296
+ interface OverlayBounds {
297
+ borderRadius: string;
298
+ height: number;
299
+ transform: string;
300
+ width: number;
301
+ x: number;
302
+ y: number;
303
+ }
304
+ type SelectionLabelStatus = "idle" | "copying" | "copied" | "fading" | "error";
305
+ interface SelectionLabelInstance {
306
+ id: string;
307
+ bounds: OverlayBounds;
308
+ boundsMultiple?: OverlayBounds[];
309
+ tagName: string;
310
+ componentName?: string;
311
+ status: SelectionLabelStatus;
312
+ createdAt: number;
313
+ element?: Element;
314
+ elements?: Element[];
315
+ mouseX?: number;
316
+ mouseXOffsetFromCenter?: number;
317
+ mouseXOffsetRatio?: number;
318
+ errorMessage?: string;
319
+ }
320
+ interface ShopifyGrabRendererProps {
321
+ selectionVisible?: boolean;
322
+ selectionBounds?: OverlayBounds;
323
+ selectionBoundsMultiple?: OverlayBounds[];
324
+ selectionShouldSnap?: boolean;
325
+ selectionElementsCount?: number;
326
+ selectionFilePath?: string;
327
+ selectionLineNumber?: number;
328
+ selectionTagName?: string;
329
+ selectionComponentName?: string;
330
+ selectionLabelVisible?: boolean;
331
+ selectionLabelStatus?: SelectionLabelStatus;
332
+ labelInstances?: SelectionLabelInstance[];
333
+ dragVisible?: boolean;
334
+ dragBounds?: OverlayBounds;
335
+ grabbedBoxes?: Array<{
336
+ id: string;
337
+ bounds: OverlayBounds;
338
+ createdAt: number;
339
+ }>;
340
+ labelZIndex?: number;
341
+ mouseX?: number;
342
+ mouseY?: number;
343
+ crosshairVisible?: boolean;
344
+ isFrozen?: boolean;
345
+ inputValue?: string;
346
+ isPromptMode?: boolean;
347
+ replyToPrompt?: string;
348
+ hasAgent?: boolean;
349
+ isAgentConnected?: boolean;
350
+ agentSessions?: Map<string, AgentSession>;
351
+ supportsUndo?: boolean;
352
+ supportsFollowUp?: boolean;
353
+ dismissButtonText?: string;
354
+ onRequestAbortSession?: (sessionId: string) => void;
355
+ onAbortSession?: (sessionId: string, confirmed: boolean) => void;
356
+ onDismissSession?: (sessionId: string) => void;
357
+ onUndoSession?: (sessionId: string) => void;
358
+ onFollowUpSubmitSession?: (sessionId: string, prompt: string) => void;
359
+ onAcknowledgeSessionError?: (sessionId: string) => void;
360
+ onRetrySession?: (sessionId: string) => void;
361
+ onShowContextMenuSession?: (sessionId: string) => void;
362
+ onShowContextMenuInstance?: (instanceId: string) => void;
363
+ onLabelInstanceHoverChange?: (instanceId: string, isHovered: boolean) => void;
364
+ onInputChange?: (value: string) => void;
365
+ onInputSubmit?: () => void;
366
+ onInputCancel?: () => void;
367
+ onToggleExpand?: () => void;
368
+ isPendingDismiss?: boolean;
369
+ onConfirmDismiss?: () => void;
370
+ onCancelDismiss?: () => void;
371
+ pendingAbortSessionId?: string | null;
372
+ theme?: Required<Theme>;
373
+ toolbarVisible?: boolean;
374
+ isActive?: boolean;
375
+ onToggleActive?: () => void;
376
+ enabled?: boolean;
377
+ onToggleEnabled?: () => void;
378
+ shakeCount?: number;
379
+ onToolbarStateChange?: (state: ToolbarState) => void;
380
+ onSubscribeToToolbarStateChanges?: (callback: (state: ToolbarState) => void) => () => void;
381
+ onToolbarSelectHoverChange?: (isHovered: boolean) => void;
382
+ contextMenuPosition?: {
383
+ x: number;
384
+ y: number;
385
+ } | null;
386
+ contextMenuBounds?: OverlayBounds | null;
387
+ contextMenuTagName?: string;
388
+ contextMenuComponentName?: string;
389
+ contextMenuHasFilePath?: boolean;
390
+ actions?: ContextMenuAction[];
391
+ actionContext?: ActionContext;
392
+ onContextMenuCopy?: () => void;
393
+ onContextMenuCopyScreenshot?: () => void;
394
+ onContextMenuCopyHtml?: () => void;
395
+ onContextMenuOpen?: () => void;
396
+ onContextMenuDismiss?: () => void;
397
+ onContextMenuHide?: () => void;
398
+ }
399
+ interface GrabbedBox {
400
+ id: string;
401
+ bounds: OverlayBounds;
402
+ createdAt: number;
403
+ element: Element;
404
+ }
405
+ interface Rect {
406
+ left: number;
407
+ top: number;
408
+ right: number;
409
+ bottom: number;
410
+ }
411
+ interface DragRect {
412
+ x: number;
413
+ y: number;
414
+ width: number;
415
+ height: number;
416
+ }
417
+
418
+ interface ShopifyStackFrame {
419
+ functionName: string | null;
420
+ fileName: string | null;
421
+ lineNumber: number | null;
422
+ columnNumber: number | null;
423
+ isServer: boolean;
424
+ }
425
+ declare const getStack: (element: Element) => Promise<ShopifyStackFrame[]>;
426
+ interface GetElementContextOptions {
427
+ maxLines?: number;
428
+ }
429
+ declare const getElementContext: (element: Element, options?: GetElementContextOptions) => Promise<string>;
430
+
431
+ declare const DEFAULT_THEME: Required<Theme>;
432
+
433
+ interface GenerateSnippetOptions {
434
+ maxLines?: number;
435
+ }
436
+ declare const generateSnippet: (elements: Element[], options?: GenerateSnippetOptions) => Promise<string[]>;
437
+
438
+ interface CopyContentOptions {
439
+ onSuccess?: () => void;
440
+ name?: string;
441
+ }
442
+ declare const copyContent: (content: string, options?: CopyContentOptions) => boolean;
443
+
444
+ declare const init: (rawOptions?: Options) => ShopifyGrabAPI;
445
+
446
+ declare const isInstrumentationActive: () => boolean;
447
+
448
+ export { type ActionContext as A, type ContextMenuAction as C, DEFAULT_THEME as D, type ElementLabelContext as E, type GrabbedBox as G, type Options as O, type Plugin as P, type Rect as R, type ShopifyGrabAPI as S, type Theme as T, type ActivationMode as a, type AgentCompleteResult as b, type AgentContext as c, type AgentOptions as d, type AgentProvider as e, type AgentSession as f, type AgentSessionStorage as g, type CrosshairContext as h, type DeepPartial as i, type DragRect as j, type ElementLabelVariant as k, type OverlayBounds as l, type PluginConfig as m, type PluginHooks as n, type PromptModeContext as o, type SettableOptions as p, type ShopifyGrabState as q, type SourceInfo as r, type ToolbarState as s, getElementContext as t, generateSnippet as u, getStack as v, init as w, isInstrumentationActive as x, type ShopifyGrabRendererProps as y, copyContent as z };