@promakeai/inspector 0.2.2 → 1.0.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.
Files changed (104) hide show
  1. package/dist/inspector.css +1 -0
  2. package/dist/inspector.js +8740 -0
  3. package/dist/packages/inspector/src/App.d.ts +5 -0
  4. package/dist/packages/inspector/src/App.d.ts.map +1 -0
  5. package/dist/packages/inspector/src/__tests__/App.test.d.ts +5 -0
  6. package/dist/packages/inspector/src/__tests__/App.test.d.ts.map +1 -0
  7. package/dist/packages/inspector/src/components/Badge.d.ts +9 -0
  8. package/dist/packages/inspector/src/components/Badge.d.ts.map +1 -0
  9. package/dist/packages/inspector/src/components/ControlBox/ContentArea.d.ts +10 -0
  10. package/dist/packages/inspector/src/components/ControlBox/ContentArea.d.ts.map +1 -0
  11. package/dist/packages/inspector/src/components/ControlBox/PromptInput.d.ts +12 -0
  12. package/dist/packages/inspector/src/components/ControlBox/PromptInput.d.ts.map +1 -0
  13. package/dist/packages/inspector/src/components/ControlBox/index.d.ts +21 -0
  14. package/dist/packages/inspector/src/components/ControlBox/index.d.ts.map +1 -0
  15. package/dist/packages/inspector/src/components/ImageEditor/UploadBox.d.ts +10 -0
  16. package/dist/packages/inspector/src/components/ImageEditor/UploadBox.d.ts.map +1 -0
  17. package/dist/packages/inspector/src/components/ImageEditor/index.d.ts +11 -0
  18. package/dist/packages/inspector/src/components/ImageEditor/index.d.ts.map +1 -0
  19. package/dist/packages/inspector/src/components/Overlay.d.ts +11 -0
  20. package/dist/packages/inspector/src/components/Overlay.d.ts.map +1 -0
  21. package/dist/packages/inspector/src/components/StyleEditor/BorderSection.d.ts +13 -0
  22. package/dist/packages/inspector/src/components/StyleEditor/BorderSection.d.ts.map +1 -0
  23. package/dist/packages/inspector/src/components/StyleEditor/ColorPicker.d.ts +13 -0
  24. package/dist/packages/inspector/src/components/StyleEditor/ColorPicker.d.ts.map +1 -0
  25. package/dist/packages/inspector/src/components/StyleEditor/DisplaySection.d.ts +13 -0
  26. package/dist/packages/inspector/src/components/StyleEditor/DisplaySection.d.ts.map +1 -0
  27. package/dist/packages/inspector/src/components/StyleEditor/ImageSection.d.ts +13 -0
  28. package/dist/packages/inspector/src/components/StyleEditor/ImageSection.d.ts.map +1 -0
  29. package/dist/packages/inspector/src/components/StyleEditor/LayoutSection.d.ts +13 -0
  30. package/dist/packages/inspector/src/components/StyleEditor/LayoutSection.d.ts.map +1 -0
  31. package/dist/packages/inspector/src/components/StyleEditor/NumberInput.d.ts +17 -0
  32. package/dist/packages/inspector/src/components/StyleEditor/NumberInput.d.ts.map +1 -0
  33. package/dist/packages/inspector/src/components/StyleEditor/SliderInput.d.ts +16 -0
  34. package/dist/packages/inspector/src/components/StyleEditor/SliderInput.d.ts.map +1 -0
  35. package/dist/packages/inspector/src/components/StyleEditor/SpacingSection.d.ts +13 -0
  36. package/dist/packages/inspector/src/components/StyleEditor/SpacingSection.d.ts.map +1 -0
  37. package/dist/packages/inspector/src/components/StyleEditor/TextSection.d.ts +13 -0
  38. package/dist/packages/inspector/src/components/StyleEditor/TextSection.d.ts.map +1 -0
  39. package/dist/packages/inspector/src/components/StyleEditor/index.d.ts +12 -0
  40. package/dist/packages/inspector/src/components/StyleEditor/index.d.ts.map +1 -0
  41. package/dist/packages/inspector/src/components/TextEditor/index.d.ts +11 -0
  42. package/dist/packages/inspector/src/components/TextEditor/index.d.ts.map +1 -0
  43. package/dist/packages/inspector/src/components/ui/CustomCollapsible.d.ts +26 -0
  44. package/dist/packages/inspector/src/components/ui/CustomCollapsible.d.ts.map +1 -0
  45. package/dist/packages/inspector/src/components/ui/button.d.ts +9 -0
  46. package/dist/packages/inspector/src/components/ui/button.d.ts.map +1 -0
  47. package/dist/packages/inspector/src/components/ui/color-picker.d.ts +10 -0
  48. package/dist/packages/inspector/src/components/ui/color-picker.d.ts.map +1 -0
  49. package/dist/packages/inspector/src/components/ui/input.d.ts +6 -0
  50. package/dist/packages/inspector/src/components/ui/input.d.ts.map +1 -0
  51. package/dist/packages/inspector/src/components/ui/popover.d.ts +8 -0
  52. package/dist/packages/inspector/src/components/ui/popover.d.ts.map +1 -0
  53. package/dist/packages/inspector/src/components/ui/select.d.ts +16 -0
  54. package/dist/packages/inspector/src/components/ui/select.d.ts.map +1 -0
  55. package/dist/packages/inspector/src/components/ui/slider.d.ts +5 -0
  56. package/dist/packages/inspector/src/components/ui/slider.d.ts.map +1 -0
  57. package/dist/packages/inspector/src/components/ui/textarea.d.ts +4 -0
  58. package/dist/packages/inspector/src/components/ui/textarea.d.ts.map +1 -0
  59. package/dist/packages/inspector/src/components/ui/tooltip.d.ts +8 -0
  60. package/dist/packages/inspector/src/components/ui/tooltip.d.ts.map +1 -0
  61. package/dist/packages/inspector/src/core/highlighter.d.ts +40 -0
  62. package/dist/packages/inspector/src/core/highlighter.d.ts.map +1 -0
  63. package/dist/packages/inspector/src/hooks/useMessageBridge.d.ts +9 -0
  64. package/dist/packages/inspector/src/hooks/useMessageBridge.d.ts.map +1 -0
  65. package/dist/packages/inspector/src/hooks/useStylePreview.d.ts +11 -0
  66. package/dist/packages/inspector/src/hooks/useStylePreview.d.ts.map +1 -0
  67. package/dist/packages/inspector/src/index.d.ts +16 -0
  68. package/dist/packages/inspector/src/index.d.ts.map +1 -0
  69. package/dist/packages/inspector/src/lib/utils.d.ts +3 -0
  70. package/dist/packages/inspector/src/lib/utils.d.ts.map +1 -0
  71. package/dist/packages/inspector/src/plugin.d.ts +4 -0
  72. package/dist/packages/inspector/src/plugin.d.ts.map +1 -0
  73. package/dist/packages/inspector/src/store/useInspectorStore.d.ts +13 -0
  74. package/dist/packages/inspector/src/store/useInspectorStore.d.ts.map +1 -0
  75. package/dist/packages/inspector/src/styles.d.ts +5 -0
  76. package/dist/packages/inspector/src/styles.d.ts.map +1 -0
  77. package/dist/packages/inspector/src/utils/colorUtils.d.ts +49 -0
  78. package/dist/packages/inspector/src/utils/colorUtils.d.ts.map +1 -0
  79. package/dist/packages/inspector/src/utils/elementNames.d.ts +7 -0
  80. package/dist/packages/inspector/src/utils/elementNames.d.ts.map +1 -0
  81. package/dist/packages/inspector/src/utils/elementUtils.d.ts +28 -0
  82. package/dist/packages/inspector/src/utils/elementUtils.d.ts.map +1 -0
  83. package/dist/packages/inspector/src/utils/errorTracker.d.ts +48 -0
  84. package/dist/packages/inspector/src/utils/errorTracker.d.ts.map +1 -0
  85. package/dist/packages/inspector/src/utils/inputStyles.d.ts +23 -0
  86. package/dist/packages/inspector/src/utils/inputStyles.d.ts.map +1 -0
  87. package/dist/packages/inspector/src/utils/styleUtils.d.ts +27 -0
  88. package/dist/packages/inspector/src/utils/styleUtils.d.ts.map +1 -0
  89. package/dist/packages/inspector/src/utils/tailwindMapper.d.ts +9 -0
  90. package/dist/packages/inspector/src/utils/tailwindMapper.d.ts.map +1 -0
  91. package/dist/packages/inspector/src/utils/urlTracker.d.ts +27 -0
  92. package/dist/packages/inspector/src/utils/urlTracker.d.ts.map +1 -0
  93. package/dist/packages/inspector/tsconfig.tsbuildinfo +1 -0
  94. package/dist/plugin.js +10 -1893
  95. package/package.json +80 -75
  96. package/README.md +0 -866
  97. package/dist/hook.d.ts +0 -115
  98. package/dist/hook.d.ts.map +0 -1
  99. package/dist/hook.js +0 -288
  100. package/dist/plugin.d.ts +0 -44
  101. package/dist/plugin.d.ts.map +0 -1
  102. package/dist/types.d.ts +0 -141
  103. package/dist/types.d.ts.map +0 -1
  104. package/dist/types.js +0 -7
package/README.md DELETED
@@ -1,866 +0,0 @@
1
- # @promakeai/inspector
2
-
3
- [![Build Status](https://github.com/promakeai/inspector/actions/workflows/build.yml/badge.svg)](https://github.com/promakeai/inspector/actions/workflows/build.yml)
4
- [![Tests](https://github.com/promakeai/inspector/actions/workflows/test.yml/badge.svg)](https://github.com/promakeai/inspector/actions/workflows/test.yml)
5
- [![npm version](https://badge.fury.io/js/@promakeai%2Finspector.svg)](https://www.npmjs.com/package/@promakeai/inspector)
6
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
-
8
- Visual element inspector for React apps in iframe with AI prompt support. Perfect for visual editors, page builders, and low-code platforms.
9
-
10
- ## Features
11
-
12
- - 🎯 **Element Selection** - Click to select any element on the page
13
- - 🔍 **React Component Detection** - Automatically detects React components via Fiber
14
- - 📝 **Dynamic Content Input** - Show/hide text editing on-demand with `showContentInput()`
15
- - 🖼️ **Image Upload Support** - Custom drag & drop image uploader with preview
16
- - ⚡ **Immediate DOM Updates** - Optional instant feedback while backend processes
17
- - 🤖 **AI Prompt Support** - Always-visible prompt input for AI modifications
18
- - 🎨 **Visual Feedback** - Highlight selected elements with overlay
19
- - 🔒 **Pause Mode** - Lock selection and disable scroll while editing
20
- - 🌐 **URL Tracking** - Monitor navigation changes in iframe
21
- - 🐛 **Error Tracking** - Capture JavaScript errors, promise rejections, and console errors
22
- - 🎨 **Customizable Theme** - Full color customization for all UI elements
23
- - 🌍 **Customizable Labels** - Multi-language support
24
- - 🚫 **Ignore Elements** - Mark elements as non-inspectable with `data-inspector-ignore`
25
- - 🔍 **Text Node Detection** - Automatically detect if selected element is a text node
26
- - 🖼️ **Image Node Detection** - Automatically detect if selected element is an image
27
- - 🏷️ **Promake Badge** - Optional "Built by Promake" badge with smooth animations
28
- - 🔍 **Element Highlighting** - Revisit and highlight previously inspected elements
29
- - 🆔 **Persistent Element IDs** - Structural signature-based IDs that survive page reloads
30
- - 🔄 **Reload-Safe Highlighting** - Same element gets same ID even after refresh
31
- - 🎯 **Smart Fallback** - Position-based matching when DOM structure changes
32
- - 📦 **TypeScript** - Full type safety
33
- - ✅ **Well Tested** - 42 unit tests + 35 e2e tests with 90%+ coverage
34
-
35
- ## Installation
36
-
37
- ```bash
38
- npm install @promakeai/inspector
39
- ```
40
-
41
- ## Usage
42
-
43
- ### Template Side (iframe/vite app)
44
-
45
- Add the plugin to your `vite.config.ts`:
46
-
47
- ```typescript
48
- import { defineConfig } from "vite";
49
- import react from "@vitejs/plugin-react";
50
- import { inspectorPlugin } from "@promakeai/inspector/plugin";
51
-
52
- export default defineConfig({
53
- plugins: [react(), inspectorPlugin()],
54
- });
55
- ```
56
-
57
- ### Parent App Side
58
-
59
- Use the hook in your React app:
60
-
61
- ```typescript
62
- import { useRef } from "react";
63
- import { useInspector } from "@promakeai/inspector/hook";
64
-
65
- function App() {
66
- const iframeRef = useRef<HTMLIFrameElement>(null);
67
-
68
- const { isInspecting, toggleInspector, showContentInput, showImageInput } =
69
- useInspector(
70
- iframeRef,
71
- {
72
- onElementSelected: (data) => {
73
- console.log("Element selected:", data);
74
- console.log("Is text node:", data.isTextNode);
75
- console.log("Is image node:", data.isImageNode);
76
-
77
- // Access component info
78
- console.log(data.component?.fileName);
79
- console.log(data.component?.lineNumber);
80
-
81
- // Show content input if it's a text node
82
- if (data.isTextNode) {
83
- showContentInput(true);
84
- }
85
-
86
- // Show image input if it's an image node
87
- if (data.isImageNode) {
88
- showImageInput(true);
89
- }
90
- },
91
- onPromptSubmitted: (data) => {
92
- console.log("AI Prompt:", data.prompt);
93
- // Send to your AI service
94
- fetch("/api/ai-edit", {
95
- method: "POST",
96
- body: JSON.stringify({
97
- prompt: data.prompt,
98
- element: data.element,
99
- }),
100
- });
101
- },
102
- onTextUpdated: (data) => {
103
- console.log("Text updated:", data.text);
104
- // Save to backend
105
- },
106
- onImageUpdated: (data) => {
107
- console.log("Image updated:", data.imageFile.name);
108
- console.log("Image data (base64):", data.imageData);
109
- // Upload to server
110
- fetch("/api/upload-image", {
111
- method: "POST",
112
- body: JSON.stringify(data),
113
- });
114
- },
115
- onInspectorClosed: () => {
116
- console.log("Inspector closed");
117
- // Update UI state, re-enable elements, etc.
118
- },
119
- onUrlChange: (data) => {
120
- console.log("URL changed:", data.pathname);
121
- },
122
- onError: (data) => {
123
- console.error("Error in template:", data);
124
- // Send to error tracking service (Sentry, etc.)
125
- // Sentry.captureException(new Error(data.message));
126
- },
127
- },
128
- {
129
- // Optional: Custom labels
130
- editText: "Edit Text",
131
- textPlaceholder: "Enter text...",
132
- updateText: "Update",
133
- promptPlaceholder: "Ask AI for changes...",
134
- editImage: "Change Image",
135
- imageUploadTitle: "Select Image",
136
- imageUploadHint: "Click or drag",
137
- updateImage: "Update Image",
138
- badgeText: "Built with Promake",
139
- },
140
- {
141
- // Optional: Custom theme colors
142
- backgroundColor: "#ffffff",
143
- textColor: "#111827",
144
- buttonColor: "#4417db",
145
- buttonTextColor: "#ffffff",
146
- inputBackgroundColor: "#f9fafb",
147
- inputTextColor: "#111827",
148
- inputBorderColor: "#d1d5db",
149
- badgeGradientStart: "#411E93",
150
- badgeGradientEnd: "#E87C85",
151
- badgeTextColor: "#ffffff",
152
- }
153
- );
154
-
155
- return (
156
- <div>
157
- <button onClick={() => toggleInspector()}>
158
- {isInspecting ? "Stop Inspector" : "Start Inspector"}
159
- </button>
160
-
161
- {/* Optional: Manual content input toggle */}
162
- {isInspecting && (
163
- <button onClick={() => showContentInput(true)}>
164
- Show Content Input
165
- </button>
166
- )}
167
-
168
- <iframe ref={iframeRef} src="http://localhost:5173" />
169
- </div>
170
- );
171
- }
172
- ```
173
-
174
- ## API
175
-
176
- ### `useInspector(iframeRef, callbacks?, labels?, theme?)`
177
-
178
- #### Parameters
179
-
180
- - **iframeRef**: `RefObject<HTMLIFrameElement>` - Reference to the iframe element
181
- - **callbacks**: `InspectorCallbacks` (optional)
182
- - `onElementSelected`: Called when an element is selected (receives `isTextNode` and `isImageNode` properties)
183
- - `onPromptSubmitted`: Called when AI prompt is submitted
184
- - `onTextUpdated`: Called when text content is updated
185
- - `onImageUpdated`: Called when image is uploaded
186
- - `onInspectorClosed`: Called when inspector mode is closed (after submitting prompt/text/image)
187
- - `onUrlChange`: Called when URL changes in iframe
188
- - `onError`: Called when an error occurs in iframe
189
- - **labels**: `InspectorLabels` (optional)
190
- - `editText`: Label for text edit section
191
- - `textPlaceholder`: Placeholder for text input
192
- - `updateText`: Label for update button
193
- - `promptPlaceholder`: Placeholder for prompt input
194
- - `editImage`: Label for image edit section
195
- - `imageUploadTitle`: Upload box title (e.g., "Select Image")
196
- - `imageUploadHint`: Upload box hint (e.g., "Click or drag")
197
- - `updateImage`: Label for image update button
198
- - `badgeText`: Badge text (default: "Built with Promake")
199
- - **theme**: `InspectorTheme` (optional)
200
- - `backgroundColor`: Box background color (default: `#ffffff`)
201
- - `textColor`: Text color (default: `#111827`)
202
- - `buttonColor`: Button background color (default: `#4417db`)
203
- - `buttonTextColor`: Button text color (default: `#ffffff`)
204
- - `inputBackgroundColor`: Input background color (default: `#f9fafb`)
205
- - `inputTextColor`: Input text color (default: `#111827`)
206
- - `inputBorderColor`: Input border color (default: `#d1d5db`)
207
- - `badgeGradientStart`: Badge gradient start color (default: `#411E93`)
208
- - `badgeGradientEnd`: Badge gradient end color (default: `#E87C85`)
209
- - `badgeTextColor`: Badge text color (default: `#ffffff`)
210
-
211
- #### Returns
212
-
213
- - **isInspecting**: `boolean` - Current inspection state
214
- - **toggleInspector**: `(active?: boolean) => void` - Toggle inspection mode
215
- - **startInspecting**: `() => void` - Start inspecting
216
- - **stopInspecting**: `() => void` - Stop inspecting
217
- - **showContentInput**: `(show: boolean, updateImmediately?: boolean) => void` - Show or hide text content input dynamically. If `updateImmediately` is true, DOM is updated immediately on submit (useful for slow backend responses)
218
- - **showImageInput**: `(show: boolean, updateImmediately?: boolean) => void` - Show or hide image input dynamically. If `updateImmediately` is true, DOM is updated immediately on submit (useful for slow backend responses)
219
- - **setBadgeVisible**: `(visible: boolean) => void` - Show or hide "Built by Promake" badge in bottom-right corner
220
- - **highlightElement**: `(identifier: string | ElementIdentifier, options?: HighlightOptions) => void` - Highlight an element in the iframe by ID or selector
221
- - **getElementByInspectorId**: `(inspectorId: string) => void` - Request element info by unique inspector ID
222
-
223
- ## Types
224
-
225
- ### `SelectedElementData`
226
-
227
- ```typescript
228
- interface SelectedElementData {
229
- tagName: string;
230
- className: string;
231
- id: string;
232
- component: ComponentInfo | null;
233
- position: ElementPosition;
234
- isTextNode?: boolean; // Whether the element is a text node
235
- textContent?: string; // Text content of the element (if text node)
236
- isImageNode?: boolean; // Whether the element is an image node
237
- imageUrl?: string; // Image URL (if image node)
238
- inspectorId?: string; // Unique inspector ID for element tracking
239
- selector?: string; // CSS selector for element identification
240
- }
241
- ```
242
-
243
- ### `ElementIdentifier`
244
-
245
- ```typescript
246
- interface ElementIdentifier {
247
- inspectorId: string; // Unique ID (primary)
248
- selector: string; // CSS selector (fallback)
249
- position?: {
250
- // Position (for disambiguation)
251
- top: number;
252
- left: number;
253
- };
254
- component?: {
255
- // Component info (metadata)
256
- name: string;
257
- fileName: string;
258
- lineNumber?: number;
259
- };
260
- }
261
- ```
262
-
263
- ### `HighlightOptions`
264
-
265
- ```typescript
266
- interface HighlightOptions {
267
- duration?: number; // Highlight duration in ms (default: 3000)
268
- scrollIntoView?: boolean; // Scroll to element (default: true)
269
- color?: string; // Highlight color (default: '#4417db')
270
- animation?: "pulse" | "fade" | "none"; // Animation type (default: 'pulse')
271
- }
272
- ```
273
-
274
- ## Element Identification & Persistence
275
-
276
- Inspector uses a **structural signature-based ID system** to ensure the same element gets the same ID across page reloads, making it perfect for features like chat history highlighting.
277
-
278
- ### How Persistent IDs Work
279
-
280
- #### ID Format
281
-
282
- ```
283
- pi-{hash}
284
- ```
285
-
286
- Example: `pi-1f2a3b4c`
287
-
288
- #### ID Generation
289
-
290
- IDs are generated based on element's structural properties:
291
-
292
- 1. **XPath** - DOM tree position (primary identifier)
293
- 2. **Static Identifiers** - `id`, `data-id`, `data-testid`, `data-component`, `data-cy`
294
- 3. **Semantic Properties** - `tag`, `role`, `type`, `name`, `href`, `src`
295
- 4. **Structural Context** - sibling index, parent tag (if no static ID)
296
-
297
- **Excluded for Stability:**
298
-
299
- - ❌ Class names (frequently change)
300
- - ❌ Text content (dynamic)
301
- - ❌ Style attributes (dynamic)
302
-
303
- #### Consistency Guarantees
304
-
305
- ✅ **Same element → Same ID** (across page reloads)
306
- ✅ **Class changes → ID unchanged**
307
- ✅ **Text changes → ID unchanged**
308
- ✅ **Style changes → ID unchanged**
309
- ❌ **DOM position changes → Different ID** (new structure = new ID)
310
-
311
- #### Best Practices for Maximum Consistency
312
-
313
- To ensure the most reliable element identification:
314
-
315
- ```html
316
- <!-- ✅ Best: Use data-id for elements you want to reliably track -->
317
- <div data-id="hero-section">...</div>
318
- <button data-id="cta-button">...</button>
319
-
320
- <!-- ✅ Good: Use element.id -->
321
- <div id="main-content">...</div>
322
-
323
- <!-- ✅ Good: Use data-testid -->
324
- <button data-testid="submit-form">...</button>
325
-
326
- <!-- ⚠️ Okay: Relies on DOM position (changes if DOM structure changes) -->
327
- <div class="card">...</div>
328
- ```
329
-
330
- #### Fallback System
331
-
332
- If an element's ID changes (e.g., DOM restructure), the system uses smart fallbacks:
333
-
334
- 1. **Primary**: Try to find by `inspectorId`
335
- 2. **Fallback 1**: Use CSS selector
336
- 3. **Fallback 2**: Use position matching (if multiple matches)
337
-
338
- ```typescript
339
- // Full identifier with fallback support
340
- highlightElement({
341
- inspectorId: "pi-1f2a3b4c", // Primary
342
- selector: "button.cta-primary", // Fallback 1
343
- position: { top: 500, left: 100 }, // Fallback 2
344
- });
345
- ```
346
-
347
- ### `ComponentInfo`
348
-
349
- ```typescript
350
- interface ComponentInfo {
351
- componentName: string;
352
- fileName: string;
353
- lineNumber: number;
354
- columnNumber: number;
355
- }
356
- ```
357
-
358
- ### `PromptSubmittedData`
359
-
360
- ```typescript
361
- interface PromptSubmittedData {
362
- prompt: string;
363
- element: SelectedElementData;
364
- }
365
- ```
366
-
367
- ### `TextUpdatedData`
368
-
369
- ```typescript
370
- interface TextUpdatedData {
371
- text: string;
372
- originalText: string;
373
- element: SelectedElementData;
374
- }
375
- ```
376
-
377
- ### `ImageUpdatedData`
378
-
379
- ```typescript
380
- interface ImageUpdatedData {
381
- imageData: string; // Base64 encoded image data
382
- imageFile: {
383
- name: string;
384
- size: number;
385
- type: string;
386
- };
387
- originalImageUrl: string;
388
- element: SelectedElementData;
389
- }
390
- ```
391
-
392
- ### `ErrorData`
393
-
394
- ```typescript
395
- interface ErrorData {
396
- type: "javascript" | "promise" | "console";
397
- message: string;
398
- stack?: string;
399
- fileName?: string;
400
- lineNumber?: number;
401
- columnNumber?: number;
402
- timestamp: number;
403
- }
404
- ```
405
-
406
- ### `InspectorLabels`
407
-
408
- ```typescript
409
- interface InspectorLabels {
410
- editText?: string; // Label for text edit section
411
- textPlaceholder?: string; // Placeholder for text input
412
- updateText?: string; // Label for text update button
413
- promptPlaceholder?: string; // Placeholder for prompt input
414
- editImage?: string; // Label for image edit section
415
- imageUploadTitle?: string; // Upload box title (e.g., "Select Image")
416
- imageUploadHint?: string; // Upload box hint (e.g., "Click or drag")
417
- updateImage?: string; // Label for image update button
418
- badgeText?: string; // Badge text (default: "Built with Promake")
419
- }
420
- ```
421
-
422
- ### `InspectorTheme`
423
-
424
- ```typescript
425
- interface InspectorTheme {
426
- backgroundColor?: string; // Box background color
427
- textColor?: string; // Text color
428
- buttonColor?: string; // Button background color
429
- buttonTextColor?: string; // Button text color
430
- inputBackgroundColor?: string; // Input background color
431
- inputTextColor?: string; // Input text color
432
- inputBorderColor?: string; // Input border color
433
- badgeGradientStart?: string; // Badge gradient start color
434
- badgeGradientEnd?: string; // Badge gradient end color
435
- badgeTextColor?: string; // Badge text color
436
- }
437
- ```
438
-
439
- ## Features in Detail
440
-
441
- ### Element Selection
442
-
443
- Click any element to select it. The inspector will:
444
-
445
- - Show a blue highlight overlay
446
- - Display a control box below/above the element (always shows prompt input)
447
- - Pause scrolling
448
- - Extract React component information
449
- - Detect if element is a text-only node (`isTextNode`)
450
- - Detect if element is an image node (`isImageNode`)
451
-
452
- ### Dynamic Content Input
453
-
454
- The inspector now uses a three-stage approach:
455
-
456
- 1. **Prompt Input (Always Visible)**: Every element shows a prompt input for AI instructions
457
- 2. **Text Content Input (On-Demand)**: Text editing appears only when you call `showContentInput(true)`
458
- 3. **Image Upload (On-Demand)**: Image upload appears only when you call `showImageInput(true)`
459
-
460
- This allows you to:
461
-
462
- - Run AI computations after selection
463
- - Decide programmatically when to show text editing or image upload
464
- - Keep the UI clean and focused
465
-
466
- ```typescript
467
- onElementSelected: (data) => {
468
- if (data.isTextNode) {
469
- // Show content input above prompt input
470
- // Pass true as second parameter for immediate DOM update
471
- showContentInput(true, true);
472
- }
473
-
474
- if (data.isImageNode) {
475
- // Show image upload for images
476
- // Pass true as second parameter for immediate DOM update
477
- showImageInput(true, true);
478
- }
479
- };
480
- ```
481
-
482
- ### Image Upload
483
-
484
- For image elements:
485
-
486
- - **Custom Upload Box**: Dashed border box with drag & drop support
487
- - **Click to Upload**: Click the box to select image from file explorer
488
- - **Drag & Drop**: Drag image files directly onto the upload box
489
- - **Preview**: Selected image appears in the same box (max 100px height)
490
- - **Base64 Encoding**: Image is automatically converted to base64
491
- - **File Metadata**: File name, size, and type are included
492
-
493
- The image data is sent to parent app with `onImageUpdated` callback for upload to your server.
494
-
495
- ### Immediate DOM Updates
496
-
497
- For production environments where backend processing takes time, you can enable immediate DOM updates:
498
-
499
- ```typescript
500
- // Text updates - DOM is updated immediately, no wait for backend
501
- showContentInput(true, true); // updateImmediately: true
502
-
503
- // Image updates - Image appears immediately, no wait for backend
504
- showImageInput(true, true); // updateImmediately: true
505
- ```
506
-
507
- **How it works:**
508
-
509
- 1. **Text Updates**: When user submits new text, the DOM text content is updated immediately
510
- 2. **Image Updates**: When user selects an image, the `<img>` src (or background-image) is updated immediately with base64 data
511
- 3. **Backend Sync**: The `onTextUpdated` or `onImageUpdated` callback is still fired for backend sync
512
- 4. **User Experience**: User sees instant feedback, while your backend processes in the background
513
-
514
- This is perfect for:
515
-
516
- - Slow API responses
517
- - AI processing that takes seconds
518
- - Upload-heavy operations
519
- - Better perceived performance
520
-
521
- ### Promake Badge
522
-
523
- Show a beautiful "Built with Promake" badge in the bottom-right corner:
524
-
525
- ```typescript
526
- // Show badge with default text ("Built with Promake")
527
- setBadgeVisible(true);
528
-
529
- // Hide badge
530
- setBadgeVisible(false);
531
-
532
- // Customize badge text via labels
533
- const { setBadgeVisible } = useInspector(iframeRef, callbacks, {
534
- badgeText: "Made with ❤️ by MyCompany",
535
- });
536
-
537
- // Customize badge colors via theme
538
- const { setBadgeVisible } = useInspector(
539
- iframeRef,
540
- callbacks,
541
- undefined, // no custom labels
542
- {
543
- badgeGradientStart: "#10b981", // Green
544
- badgeGradientEnd: "#3b82f6", // Blue
545
- badgeTextColor: "#ffffff", // White text
546
- }
547
- );
548
-
549
- // Dark badge with light text
550
- const { setBadgeVisible } = useInspector(iframeRef, callbacks, undefined, {
551
- badgeGradientStart: "#1e293b", // Dark slate
552
- badgeGradientEnd: "#334155", // Slate
553
- badgeTextColor: "#f8fafc", // Light text
554
- });
555
- ```
556
-
557
- **Features:**
558
-
559
- - 🎨 Beautiful gradient design (purple to violet by default)
560
- - ⚡ Smooth fade-in/fade-out animations
561
- - 🖱️ Hover effects with elevation
562
- - 🔗 Clickable - opens promake.ai in new tab
563
- - 📍 Fixed position in bottom-right
564
- - 🚫 Ignored by inspector (has `data-inspector-ignore`)
565
- - 📝 Customizable text via labels
566
- - 🎨 Customizable gradient colors via theme
567
- - 🔤 Customizable text color via theme
568
- - ❌ Close button appears on hover - users can dismiss the badge
569
-
570
- **Default**: Badge is hidden by default. Enable it when needed using `setBadgeVisible(true)`. Default text is "Built with Promake". Default gradient colors are deep purple (#411E93) to coral pink (#E87C85). Default text color is white (#ffffff).
571
-
572
- **Auto-Show**: Badge automatically appears when the app is running in `preview.promake.ai` environment **without** a parent iframe. This ensures the badge is visible in preview deployments where parent control is not available.
573
-
574
- **Close Button**: When users hover over the badge, a small close button (×) appears in the top-right corner. Clicking it hides the badge with a smooth animation.
575
-
576
- **Color Examples:**
577
-
578
- **Gradient Backgrounds:**
579
-
580
- - **Deep Purple to Coral Pink** (default): `#411E93` → `#E87C85` (white text)
581
- - **Blue to Cyan**: `#3b82f6` → `#06b6d4` (white text)
582
- - **Green to Emerald**: `#10b981` → `#059669` (white text)
583
- - **Pink to Rose**: `#ec4899` → `#f43f5e` (white text)
584
- - **Orange to Red**: `#f97316` → `#ef4444` (white text)
585
- - **Dark Slate**: `#1e293b` → `#334155` (light text `#f8fafc`)
586
-
587
- **Text Colors:**
588
-
589
- - **White** (default): `#ffffff`
590
- - **Light**: `#f8fafc`, `#f1f5f9`
591
- - **Dark**: `#111827`, `#1e293b`
592
- - **Brand Colors**: Match your brand palette
593
-
594
- **Auto-Show Behavior:**
595
-
596
- The badge automatically appears in these conditions:
597
-
598
- 1. The app is **not** inside an iframe (`window.parent === window`)
599
- 2. The URL contains `preview.promake.ai`
600
-
601
- This ensures the badge is visible in Promake preview deployments where parent window control is unavailable. Users can still close it using the close button on hover.
602
-
603
- **Use Cases:**
604
-
605
- - Show attribution to Promake
606
- - Free tier watermark for preview deployments
607
- - Branding for templates built with Promake
608
- - Custom branding with your own text and colors
609
- - Automatic display in preview environments
610
-
611
- ### AI Prompts
612
-
613
- For any element:
614
-
615
- - Prompt input is always visible
616
- - Enter a prompt describing desired changes
617
- - Click the send button (↑)
618
- - Prompt + element data sent to parent app
619
-
620
- ### Ignoring Elements
621
-
622
- Mark elements as non-inspectable using the `data-inspector-ignore` attribute:
623
-
624
- ```jsx
625
- <button data-inspector-ignore onClick={toggleInspect}>
626
- Inspector Controls
627
- </button>
628
-
629
- <div data-inspector-ignore>
630
- {/* All children will be ignored too */}
631
- <button>Button 1</button>
632
- <button>Button 2</button>
633
- </div>
634
- ```
635
-
636
- This is perfect for:
637
-
638
- - Inspector control buttons
639
- - Floating toolbars
640
- - Fixed navigation
641
- - Any UI that shouldn't be inspectable
642
-
643
- ### Component Detection
644
-
645
- Automatically extracts:
646
-
647
- - Component name
648
- - Source file path
649
- - Line number
650
- - Column number
651
-
652
- **Note**: Works only in development mode with React DevTools enabled.
653
-
654
- ### Error Tracking
655
-
656
- Automatically captures and reports:
657
-
658
- - **JavaScript Errors**: Runtime errors with stack traces
659
- - **Promise Rejections**: Unhandled promise rejections
660
- - **Console Errors**: All `console.error()` calls
661
-
662
- All errors are sent to the parent app with detailed information including:
663
-
664
- - Error type and message
665
- - Stack trace
666
- - File name and line number
667
- - Timestamp
668
-
669
- Perfect for integrating with error tracking services like Sentry, LogRocket, or custom logging solutions.
670
-
671
- ## Examples
672
-
673
- ### Element Highlighting from Chat History
674
-
675
- ```typescript
676
- const { highlightElement, getElementByInspectorId } = useInspector(iframeRef, {
677
- onElementSelected: (data) => {
678
- // Store inspectorId in your chat message
679
- const message = {
680
- text: `Selected ${data.tagName} element`,
681
- inspectorId: data.inspectorId,
682
- selector: data.selector,
683
- position: data.position,
684
- };
685
- saveToChatHistory(message);
686
- },
687
- onElementInfoReceived: (data) => {
688
- if (data.found) {
689
- console.log("Element found:", data.element);
690
- } else {
691
- console.log("Element not found:", data.error);
692
- }
693
- },
694
- });
695
-
696
- // Later: Click on a chat message to re-highlight the element
697
- function handleChatMessageClick(message) {
698
- // Highlight with full identifier (with fallback support)
699
- highlightElement(
700
- {
701
- inspectorId: message.inspectorId,
702
- selector: message.selector,
703
- position: message.position,
704
- },
705
- {
706
- duration: 4000,
707
- color: "#10b981",
708
- animation: "pulse",
709
- }
710
- );
711
- }
712
-
713
- // Or simply by ID
714
- function quickHighlight(inspectorId) {
715
- highlightElement(inspectorId);
716
- }
717
-
718
- // Request element info
719
- function checkElementStatus(inspectorId) {
720
- getElementByInspectorId(inspectorId);
721
- }
722
- ```
723
-
724
- ### Dynamic Content Input Based on AI Response
725
-
726
- ```typescript
727
- const { toggleInspector, showContentInput } = useInspector(iframeRef, {
728
- onElementSelected: async (data) => {
729
- // Run AI analysis first
730
- const analysis = await analyzeElement(data);
731
-
732
- // Show content input only if AI suggests text editing
733
- if (analysis.shouldShowTextEditor && data.isTextNode) {
734
- showContentInput(true);
735
- }
736
- },
737
- onPromptSubmitted: async (data) => {
738
- // Process AI prompt
739
- const result = await processAIPrompt(data.prompt, data.element);
740
-
741
- // Optionally show content input after AI processing
742
- if (result.needsTextInput) {
743
- showContentInput(true);
744
- }
745
- },
746
- });
747
- ```
748
-
749
- ### Dark Theme
750
-
751
- ```typescript
752
- const { toggleInspector } = useInspector(iframeRef, callbacks, labels, {
753
- backgroundColor: "#1a1a1a",
754
- textColor: "#ffffff",
755
- buttonColor: "#00ff00",
756
- buttonTextColor: "#000000",
757
- inputBackgroundColor: "#2a2a2a",
758
- inputTextColor: "#ffffff",
759
- inputBorderColor: "#444444",
760
- });
761
- ```
762
-
763
- ### Multi-language Support
764
-
765
- ```typescript
766
- const { toggleInspector } = useInspector(iframeRef, callbacks, {
767
- editText: "Metni Düzenle",
768
- textPlaceholder: "Metin girin...",
769
- updateText: "Güncelle",
770
- promptPlaceholder: "Promake'e değişiklik sor...",
771
- });
772
- ```
773
-
774
- ### Prevent Inspector Buttons from Being Selected
775
-
776
- ```jsx
777
- function App() {
778
- return (
779
- <div>
780
- {/* These buttons won't be inspectable */}
781
- <div className="inspector-controls" data-inspector-ignore>
782
- <button onClick={toggleInspect}>Toggle Inspector</button>
783
- <button onClick={() => showContentInput(true)}>
784
- Show Content Input
785
- </button>
786
- </div>
787
-
788
- <iframe ref={iframeRef} src="http://localhost:5173" />
789
- </div>
790
- );
791
- }
792
- ```
793
-
794
- ### Open File in Editor
795
-
796
- ```typescript
797
- onElementSelected: async (data) => {
798
- if (data.component) {
799
- await fetch("/api/open-in-editor", {
800
- method: "POST",
801
- body: JSON.stringify({
802
- fileName: data.component.fileName,
803
- lineNumber: data.component.lineNumber,
804
- }),
805
- });
806
- }
807
- };
808
- ```
809
-
810
- ### Error Tracking with Sentry
811
-
812
- ```typescript
813
- import * as Sentry from "@sentry/react";
814
-
815
- const { toggleInspector } = useInspector(iframeRef, {
816
- onError: (data) => {
817
- // Send to Sentry
818
- Sentry.captureException(new Error(data.message), {
819
- extra: {
820
- type: data.type,
821
- stack: data.stack,
822
- fileName: data.fileName,
823
- lineNumber: data.lineNumber,
824
- timestamp: data.timestamp,
825
- },
826
- });
827
- },
828
- });
829
- ```
830
-
831
- ## Browser Support
832
-
833
- - Chrome/Edge: ✅
834
- - Firefox: ✅
835
- - Safari: ✅
836
-
837
- ## Requirements
838
-
839
- - Vite 5.0+
840
- - React 18.0+
841
- - TypeScript (recommended)
842
-
843
- ## CI/CD
844
-
845
- This project includes GitHub Actions workflow:
846
-
847
- ### Build Workflow (`.github/workflows/build.yml`)
848
-
849
- Automatically runs on every push and pull request:
850
-
851
- - ✅ Uses Bun for fast installation and build
852
- - ✅ Runs `bun install` and `bun run build`
853
- - ✅ Checks for build artifacts
854
- - ✅ Uploads build artifacts for review
855
-
856
- ## License
857
-
858
- MIT
859
-
860
- ## Contributing
861
-
862
- Issues and pull requests are welcome!
863
-
864
- ## Author
865
-
866
- Promake