fixdog 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +80 -433
  3. package/dist/api/client.d.ts +74 -0
  4. package/dist/components/ConversationalInputReact.d.ts +26 -0
  5. package/dist/components/ElementInfoDisplayReact.d.ts +9 -0
  6. package/dist/components/FixdogSidebarReact.d.ts +29 -0
  7. package/dist/fiber.d.ts +9 -0
  8. package/dist/index.cjs.js +33 -0
  9. package/dist/index.cjs.js.map +1 -0
  10. package/dist/index.d.ts +6 -158
  11. package/dist/index.esm.js +29 -0
  12. package/dist/index.esm.js.map +1 -0
  13. package/dist/inspector-B4F5CBT7.cjs.js +1159 -0
  14. package/dist/inspector-B4F5CBT7.cjs.js.map +1 -0
  15. package/dist/inspector-BL2pNjn-.cjs.js +1173 -0
  16. package/dist/inspector-BL2pNjn-.cjs.js.map +1 -0
  17. package/dist/inspector-Bg6uSvk0.esm.js +1273 -0
  18. package/dist/inspector-Bg6uSvk0.esm.js.map +1 -0
  19. package/dist/inspector-BuOffbVc.cjs.js +1280 -0
  20. package/dist/inspector-BuOffbVc.cjs.js.map +1 -0
  21. package/dist/inspector-CNgFkZOU.esm.js +1185 -0
  22. package/dist/inspector-CNgFkZOU.esm.js.map +1 -0
  23. package/dist/inspector-CPF1N9dL.esm.js +1185 -0
  24. package/dist/inspector-CPF1N9dL.esm.js.map +1 -0
  25. package/dist/inspector-CPGK5Lg7.esm.js +1155 -0
  26. package/dist/inspector-CPGK5Lg7.esm.js.map +1 -0
  27. package/dist/inspector-CWcTSREy.cjs.js +1174 -0
  28. package/dist/inspector-CWcTSREy.cjs.js.map +1 -0
  29. package/dist/inspector-Cn_bl9Io.cjs.js +1189 -0
  30. package/dist/inspector-Cn_bl9Io.cjs.js.map +1 -0
  31. package/dist/inspector-D9DuXirp.cjs.js +1189 -0
  32. package/dist/inspector-D9DuXirp.cjs.js.map +1 -0
  33. package/dist/inspector-DQEtAjyM.esm.js +1129 -0
  34. package/dist/inspector-DQEtAjyM.esm.js.map +1 -0
  35. package/dist/inspector-DVlU9p44.cjs.js +1189 -0
  36. package/dist/inspector-DVlU9p44.cjs.js.map +1 -0
  37. package/dist/inspector-DaRVppX9.cjs.js +1134 -0
  38. package/dist/inspector-DaRVppX9.cjs.js.map +1 -0
  39. package/dist/inspector-huqtI2MD.esm.js +1170 -0
  40. package/dist/inspector-huqtI2MD.esm.js.map +1 -0
  41. package/dist/inspector-spoCY1tf.esm.js +1169 -0
  42. package/dist/inspector-spoCY1tf.esm.js.map +1 -0
  43. package/dist/inspector-tY1kJK5_.esm.js +1185 -0
  44. package/dist/inspector-tY1kJK5_.esm.js.map +1 -0
  45. package/dist/inspector.d.ts +43 -0
  46. package/dist/keyboard.d.ts +10 -0
  47. package/dist/overlay.d.ts +31 -0
  48. package/dist/react/InspectorProvider.d.ts +6 -0
  49. package/dist/react/index.cjs.js +32 -0
  50. package/dist/react/index.cjs.js.map +1 -0
  51. package/dist/react/index.esm.js +30 -0
  52. package/dist/react/index.esm.js.map +1 -0
  53. package/dist/sidebar/SidebarRuntime.d.ts +8 -0
  54. package/dist/sidebar-runtime.esm.js +2122 -0
  55. package/dist/sidebar-runtime.esm.js.map +1 -0
  56. package/dist/sidebar-runtime.iife.js +2991 -0
  57. package/dist/styles/sidebarStyles.d.ts +2 -0
  58. package/dist/styles.d.ts +8 -0
  59. package/dist/types/sidebar.d.ts +62 -0
  60. package/dist/types.d.ts +47 -0
  61. package/dist/utils/cookies.d.ts +10 -0
  62. package/dist/utils/devMode.d.ts +17 -0
  63. package/dist/utils/sessionStorage.d.ts +19 -0
  64. package/package.json +57 -40
  65. package/USAGE.md +0 -77
  66. package/dist/client/index.d.mts +0 -110
  67. package/dist/client/index.d.ts +0 -110
  68. package/dist/client/index.js +0 -1601
  69. package/dist/client/index.mjs +0 -1582
  70. package/dist/client/init.d.mts +0 -67
  71. package/dist/client/init.d.ts +0 -67
  72. package/dist/client/init.js +0 -1609
  73. package/dist/client/init.mjs +0 -1593
  74. package/dist/index.d.mts +0 -158
  75. package/dist/index.js +0 -1635
  76. package/dist/index.mjs +0 -1606
  77. package/src/api/client.ts +0 -141
  78. package/src/client/index.ts +0 -75
  79. package/src/client/init.tsx +0 -78
  80. package/src/components/ConversationalInputReact.tsx +0 -406
  81. package/src/components/ElementInfoDisplayReact.tsx +0 -84
  82. package/src/components/UiDogSidebarReact.tsx +0 -49
  83. package/src/element-detector.ts +0 -186
  84. package/src/index.ts +0 -228
  85. package/src/instrument.ts +0 -171
  86. package/src/sidebar-initializer.ts +0 -171
  87. package/src/source-resolver.ts +0 -121
  88. package/src/styles/sidebarStyles.ts +0 -597
  89. package/src/types/css.d.ts +0 -9
  90. package/src/types/sidebar.ts +0 -56
  91. package/src/types.ts +0 -119
  92. package/tsconfig.json +0 -23
  93. package/tsup.config.ts +0 -40
@@ -1,84 +0,0 @@
1
- import type { ElementInfo } from "../types";
2
-
3
- interface ElementInfoDisplayProps {
4
- elementInfo: ElementInfo;
5
- onClose: () => void;
6
- }
7
-
8
- export function ElementInfoDisplayReact(props: ElementInfoDisplayProps) {
9
- const isDomSnapshot = props.elementInfo.kind === "dom";
10
-
11
- if (isDomSnapshot) {
12
- const dom = props.elementInfo.domSnapshot;
13
- const outerHTML = dom?.outerHTML || "No HTML available";
14
- const text = dom?.text || "";
15
- const attributes = dom?.attributes || {};
16
-
17
- return (
18
- <div className="uidog-element-info">
19
- <div className="uidog-element-info-content">
20
- <div className="uidog-file-location">
21
- Server-rendered DOM (no source available)
22
- </div>
23
- <button
24
- className="uidog-close-btn"
25
- onClick={props.onClose}
26
- title="Close sidebar (ESC)"
27
- aria-label="Close sidebar"
28
- >
29
- ×
30
- </button>
31
- </div>
32
-
33
- <div className="uidog-dom-snapshot">
34
- <div className="uidog-dom-label">outerHTML (trimmed):</div>
35
- <pre className="uidog-dom-snippet">{outerHTML}</pre>
36
-
37
- {text && (
38
- <>
39
- <div className="uidog-dom-label">textContent (trimmed):</div>
40
- <pre className="uidog-dom-snippet">{text}</pre>
41
- </>
42
- )}
43
-
44
- {Object.keys(attributes).length > 0 && (
45
- <div className="uidog-dom-attributes">
46
- <div className="uidog-dom-label">attributes:</div>
47
- <ul>
48
- {Object.entries(attributes).map(([key, value]) => (
49
- <li key={key}>
50
- <code>{key}</code>=<code>{value}</code>
51
- </li>
52
- ))}
53
- </ul>
54
- </div>
55
- )}
56
-
57
- <div className="uidog-dom-hint">
58
- To see file/line info, render this DOM through a small client
59
- boundary.
60
- </div>
61
- </div>
62
- </div>
63
- );
64
- }
65
-
66
- const fileName = props.elementInfo.filePath?.split("/").pop() || "";
67
- const fileLocation = `Selected element at ${fileName}`;
68
-
69
- return (
70
- <div className="uidog-element-info">
71
- <div className="uidog-element-info-content">
72
- <span className="uidog-file-location">{fileLocation}</span>
73
- <button
74
- className="uidog-close-btn"
75
- onClick={props.onClose}
76
- title="Close sidebar (ESC)"
77
- aria-label="Close sidebar"
78
- >
79
- ×
80
- </button>
81
- </div>
82
- </div>
83
- );
84
- }
@@ -1,49 +0,0 @@
1
- import { useEffect } from "react";
2
- import type { ElementInfo } from "../types";
3
- import { ElementInfoDisplayReact } from "./ElementInfoDisplayReact";
4
- import { ConversationalInputReact } from "./ConversationalInputReact";
5
-
6
- interface UiDogSidebarProps {
7
- elementInfo: ElementInfo;
8
- editorUrl: string;
9
- onClose: () => void;
10
- apiEndpoint: string;
11
- }
12
-
13
- export function UiDogSidebarReact(props: UiDogSidebarProps) {
14
- useEffect(() => {
15
- const handleEscapeKey = (e: KeyboardEvent) => {
16
- if (e.key === "Escape") {
17
- props.onClose();
18
- }
19
- };
20
-
21
- document.addEventListener("keydown", handleEscapeKey);
22
- return () => {
23
- document.removeEventListener("keydown", handleEscapeKey);
24
- };
25
- }, [props]);
26
-
27
- return (
28
- <div className="uidog-sidebar-overlay">
29
- <div className="uidog-sidebar">
30
- {/* Element Info Section */}
31
- <div className="uidog-element-info-section">
32
- <ElementInfoDisplayReact
33
- elementInfo={props.elementInfo}
34
- onClose={props.onClose}
35
- />
36
- </div>
37
-
38
- {/* Chat Area - Messages + Input */}
39
- <div className="uidog-chat-container">
40
- <ConversationalInputReact
41
- elementInfo={props.elementInfo}
42
- editorUrl={props.editorUrl}
43
- apiEndpoint={props.apiEndpoint}
44
- />
45
- </div>
46
- </div>
47
- </div>
48
- );
49
- }
@@ -1,186 +0,0 @@
1
- /**
2
- * Element detector - handles Alt+click detection and source resolution using Bippy
3
- */
4
-
5
- import {
6
- getSourceFromElement,
7
- getComponentNameFromFiber,
8
- getFiberFromHostInstance,
9
- } from "./instrument";
10
- import { isSourceFile } from "./source-resolver";
11
- import type { ElementDetectorOptions, SourceLocation } from "./types";
12
-
13
- let detectorCleanup: (() => void) | null = null;
14
- let isSetup = false;
15
-
16
- /**
17
- * Setup element detection with Alt+click (or other modifier)
18
- */
19
- export function setupElementDetector(
20
- options: ElementDetectorOptions
21
- ): () => void {
22
- const { onElementSelected, modifier = "alt" } = options;
23
-
24
- // Cleanup any existing detector
25
- if (detectorCleanup) {
26
- detectorCleanup();
27
- }
28
-
29
- isSetup = true;
30
-
31
- const handleClick = async (event: MouseEvent) => {
32
- // Check if modifier key is pressed
33
- const modifierPressed =
34
- (modifier === "alt" && event.altKey) ||
35
- (modifier === "ctrl" && event.ctrlKey) ||
36
- (modifier === "meta" && event.metaKey) ||
37
- (modifier === "shift" && event.shiftKey);
38
-
39
- if (!modifierPressed) return;
40
-
41
- event.preventDefault();
42
- event.stopPropagation();
43
-
44
- const target = event.target as Element;
45
-
46
- try {
47
- // Get source location using Bippy
48
- const source = await getSourceFromElement(target);
49
-
50
- if (source && source.fileName && isSourceFile(source.fileName)) {
51
- // Get component name
52
- const fiber = getFiberFromHostInstance(target);
53
- const componentName = fiber
54
- ? getComponentNameFromFiber(fiber)
55
- : "Unknown";
56
-
57
- const enrichedSource: SourceLocation = {
58
- ...source,
59
- functionName: source.functionName || componentName,
60
- };
61
-
62
- onElementSelected(enrichedSource, target);
63
- } else {
64
- console.info(
65
- "[UiDog Next] Could not find source for element. Falling back to DOM snapshot (likely server component or library code)."
66
- );
67
- onElementSelected(null, target);
68
- }
69
- } catch (error) {
70
- console.warn("[UiDog Next] Error detecting element source:", error);
71
- }
72
- };
73
-
74
- // Handle mouse movement for hover highlighting (optional enhancement)
75
- const handleMouseMove = (event: MouseEvent) => {
76
- // Check if modifier key is pressed
77
- const modifierPressed =
78
- (modifier === "alt" && event.altKey) ||
79
- (modifier === "ctrl" && event.ctrlKey) ||
80
- (modifier === "meta" && event.metaKey) ||
81
- (modifier === "shift" && event.shiftKey);
82
-
83
- if (!modifierPressed) {
84
- removeHighlight();
85
- return;
86
- }
87
-
88
- const target = event.target as Element;
89
- highlightElement(target);
90
- };
91
-
92
- // Handle key up to remove highlight when modifier is released
93
- const handleKeyUp = (event: KeyboardEvent) => {
94
- const relevantKey =
95
- (modifier === "alt" && event.key === "Alt") ||
96
- (modifier === "ctrl" && event.key === "Control") ||
97
- (modifier === "meta" && event.key === "Meta") ||
98
- (modifier === "shift" && event.key === "Shift");
99
-
100
- if (relevantKey) {
101
- removeHighlight();
102
- }
103
- };
104
-
105
- // Use capture phase to intercept before other handlers
106
- document.addEventListener("click", handleClick, true);
107
- document.addEventListener("mousemove", handleMouseMove, true);
108
- document.addEventListener("keyup", handleKeyUp, true);
109
-
110
- detectorCleanup = () => {
111
- document.removeEventListener("click", handleClick, true);
112
- document.removeEventListener("mousemove", handleMouseMove, true);
113
- document.removeEventListener("keyup", handleKeyUp, true);
114
- removeHighlight();
115
- isSetup = false;
116
- };
117
-
118
- return detectorCleanup;
119
- }
120
-
121
- // Highlight state
122
- let currentHighlight: HTMLElement | null = null;
123
- let highlightOverlay: HTMLElement | null = null;
124
-
125
- /**
126
- * Highlight an element on hover when modifier is pressed
127
- */
128
- function highlightElement(element: Element): void {
129
- // Don't highlight our own overlay
130
- if (element === highlightOverlay || highlightOverlay?.contains(element)) {
131
- return;
132
- }
133
-
134
- // Create overlay if it doesn't exist
135
- if (!highlightOverlay) {
136
- highlightOverlay = document.createElement("div");
137
- highlightOverlay.id = "uidog-highlight-overlay";
138
- highlightOverlay.style.cssText = `
139
- position: fixed;
140
- pointer-events: none;
141
- background: rgba(59, 130, 246, 0.2);
142
- border: 2px solid rgba(59, 130, 246, 0.8);
143
- border-radius: 4px;
144
- z-index: 999998;
145
- transition: all 0.1s ease-out;
146
- `;
147
- document.body.appendChild(highlightOverlay);
148
- }
149
-
150
- // Update position
151
- const rect = element.getBoundingClientRect();
152
- highlightOverlay.style.top = `${rect.top}px`;
153
- highlightOverlay.style.left = `${rect.left}px`;
154
- highlightOverlay.style.width = `${rect.width}px`;
155
- highlightOverlay.style.height = `${rect.height}px`;
156
- highlightOverlay.style.display = "block";
157
-
158
- currentHighlight = element as HTMLElement;
159
- }
160
-
161
- /**
162
- * Remove highlight overlay
163
- */
164
- function removeHighlight(): void {
165
- if (highlightOverlay) {
166
- highlightOverlay.style.display = "none";
167
- }
168
- currentHighlight = null;
169
- }
170
-
171
- /**
172
- * Check if element detector is set up
173
- */
174
- export function isElementDetectorSetup(): boolean {
175
- return isSetup;
176
- }
177
-
178
- /**
179
- * Cleanup element detector
180
- */
181
- export function cleanupElementDetector(): void {
182
- if (detectorCleanup) {
183
- detectorCleanup();
184
- detectorCleanup = null;
185
- }
186
- }
package/src/index.ts DELETED
@@ -1,228 +0,0 @@
1
- /**
2
- * UiDog SDK for Next.js - Main entry point
3
- *
4
- * Uses Bippy to hook into React's internals for element source detection,
5
- * providing a seamless developer experience for inspecting component locations.
6
- */
7
-
8
- import { setupBippyInstrumentation } from "./instrument";
9
- import {
10
- setupElementDetector,
11
- cleanupElementDetector,
12
- } from "./element-detector";
13
- import {
14
- initializeSidebar,
15
- openSidebar,
16
- closeSidebar,
17
- cleanupSidebar,
18
- } from "./sidebar-initializer";
19
- import {
20
- buildEditorUrl,
21
- normalizeFileName,
22
- getShortFileName,
23
- } from "./source-resolver";
24
- import type {
25
- UiDogNextOptions,
26
- SourceLocation,
27
- ElementInfo,
28
- EditorType,
29
- } from "./types";
30
-
31
- let isInitialized = false;
32
-
33
- /**
34
- * Initialize UiDog for Next.js
35
- *
36
- * This function sets up Bippy instrumentation, element detection, and the sidebar UI.
37
- * It should be called early in your application's lifecycle, ideally via
38
- * instrumentation-client.ts (Next.js 15.3+) or at the top of _app.tsx.
39
- */
40
- export function initializeUiDogNext(options: UiDogNextOptions = {}): void {
41
- if (typeof window === "undefined") return;
42
- if (isInitialized) {
43
- console.warn("[UiDog Next] Already initialized");
44
- return;
45
- }
46
-
47
- // Check if in development mode
48
- if (process.env.NODE_ENV === "production") {
49
- console.warn(
50
- "[UiDog Next] Running in production mode. Element source detection may not work as _debugSource is stripped in production builds."
51
- );
52
- }
53
-
54
- const {
55
- editor = "cursor",
56
- projectPath = "",
57
- modifier = "alt",
58
- enableSidebar = true,
59
- apiEndpoint = "https://api.ui.dog",
60
- } = options;
61
-
62
- isInitialized = true;
63
- window.__UIDOG_NEXT_INITIALIZED__ = true;
64
-
65
- // Setup Bippy instrumentation (hooks into React DevTools API)
66
- setupBippyInstrumentation();
67
-
68
- // Initialize sidebar if enabled
69
- if (enableSidebar) {
70
- initializeSidebar({ apiEndpoint });
71
- }
72
-
73
- // Setup element detection (Alt+click to select elements)
74
- setupElementDetector({
75
- modifier,
76
- onElementSelected: (source: SourceLocation | null, element: Element) => {
77
- const rect = element.getBoundingClientRect
78
- ? element.getBoundingClientRect()
79
- : null;
80
-
81
- const buildDomSnapshot = () => {
82
- const outerHTML = element.outerHTML || "";
83
- const text = (element.textContent || "").trim();
84
- const attributes: Record<string, string> = {};
85
-
86
- Array.from(element.attributes || []).forEach((attr) => {
87
- attributes[attr.name] = attr.value;
88
- });
89
-
90
- return {
91
- outerHTML:
92
- outerHTML.length > 4000
93
- ? `${outerHTML.slice(0, 4000)}…`
94
- : outerHTML,
95
- text: text.length > 1000 ? `${text.slice(0, 1000)}…` : text,
96
- attributes,
97
- };
98
- };
99
-
100
- if (source) {
101
- const editorUrl = buildEditorUrl(source, editor, projectPath);
102
-
103
- console.info(
104
- "[UiDog Next] Source detected:",
105
- normalizeFileName(source.fileName),
106
- "line",
107
- source.lineNumber,
108
- "column",
109
- source.columnNumber
110
- );
111
-
112
- if (enableSidebar) {
113
- const elementInfo: ElementInfo = {
114
- kind: "source",
115
- componentName: source.functionName || "Unknown",
116
- filePath: normalizeFileName(source.fileName),
117
- line: source.lineNumber,
118
- column: source.columnNumber,
119
- box: rect
120
- ? {
121
- x: rect.x,
122
- y: rect.y,
123
- width: rect.width,
124
- height: rect.height,
125
- }
126
- : undefined,
127
- };
128
-
129
- openSidebar(elementInfo, editorUrl);
130
- } else {
131
- console.log("[UiDog Next] Element selected:");
132
- console.log(" Component:", source.functionName || "Unknown");
133
- console.log(" File:", source.fileName);
134
- console.log(" Line:", source.lineNumber);
135
- console.log(" Column:", source.columnNumber);
136
- console.log(" Editor URL:", editorUrl);
137
- }
138
- } else {
139
- const domSnapshot = buildDomSnapshot();
140
-
141
- console.info("[UiDog Next] DOM snapshot (no source):", {
142
- outerHTML: domSnapshot.outerHTML,
143
- text: domSnapshot.text,
144
- attributes: domSnapshot.attributes,
145
- box: rect
146
- ? {
147
- x: rect.x,
148
- y: rect.y,
149
- width: rect.width,
150
- height: rect.height,
151
- }
152
- : undefined,
153
- });
154
-
155
- const elementInfo: ElementInfo = {
156
- kind: "dom",
157
- componentName: "Server-rendered element",
158
- domSnapshot,
159
- box: rect
160
- ? {
161
- x: rect.x,
162
- y: rect.y,
163
- width: rect.width,
164
- height: rect.height,
165
- }
166
- : undefined,
167
- };
168
-
169
- if (enableSidebar) {
170
- openSidebar(elementInfo, "");
171
- } else {
172
- console.log("[UiDog Next] Element selected (DOM snapshot):");
173
- console.log(" outerHTML:", domSnapshot.outerHTML);
174
- console.log(" text:", domSnapshot.text);
175
- }
176
- }
177
- },
178
- });
179
-
180
- console.log(
181
- `[UiDog Next] Initialized (${modifier}+click to select elements)`
182
- );
183
- }
184
-
185
- /**
186
- * Cleanup UiDog - removes all event listeners and UI
187
- */
188
- export function cleanupUiDogNext(): void {
189
- cleanupElementDetector();
190
- cleanupSidebar();
191
- isInitialized = false;
192
-
193
- if (typeof window !== "undefined") {
194
- window.__UIDOG_NEXT_INITIALIZED__ = false;
195
- }
196
- }
197
-
198
- /**
199
- * Check if UiDog is initialized
200
- */
201
- export function isUiDogNextInitialized(): boolean {
202
- return isInitialized;
203
- }
204
-
205
- // Re-export types and utilities
206
- export type {
207
- UiDogNextOptions,
208
- SourceLocation,
209
- ElementInfo,
210
- EditorType,
211
- SidebarConfig,
212
- EditRequest,
213
- EditResponse,
214
- } from "./types";
215
-
216
- export {
217
- buildEditorUrl,
218
- normalizeFileName,
219
- getShortFileName,
220
- } from "./source-resolver";
221
-
222
- export { openSidebar, closeSidebar } from "./sidebar-initializer";
223
-
224
- export {
225
- setupBippyInstrumentation,
226
- getSourceFromElement,
227
- getComponentNameFromFiber,
228
- } from "./instrument";