@np-dev/ui-ai-anotation 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.
Files changed (52) hide show
  1. package/README.md +245 -0
  2. package/dist/cjs/index.cjs +1550 -0
  3. package/dist/cjs/index.cjs.map +7 -0
  4. package/dist/cjs/index.native.cjs +1004 -0
  5. package/dist/cjs/index.native.cjs.map +7 -0
  6. package/dist/cjs/index.web.cjs +83 -0
  7. package/dist/cjs/index.web.cjs.map +7 -0
  8. package/dist/esm/index.js +1524 -0
  9. package/dist/esm/index.js.map +7 -0
  10. package/dist/esm/index.native.js +1012 -0
  11. package/dist/esm/index.native.js.map +7 -0
  12. package/dist/esm/index.web.js +62 -0
  13. package/dist/esm/index.web.js.map +7 -0
  14. package/dist/types/components/AnnotationInput.d.ts +8 -0
  15. package/dist/types/components/AnnotationList.d.ts +1 -0
  16. package/dist/types/components/Draggable.d.ts +10 -0
  17. package/dist/types/components/Highlighter.d.ts +1 -0
  18. package/dist/types/components/Toolbar.d.ts +1 -0
  19. package/dist/types/index.d.ts +20 -0
  20. package/dist/types/index.web.d.ts +69 -0
  21. package/dist/types/store.d.ts +66 -0
  22. package/dist/types/utils/fiber.d.ts +51 -0
  23. package/dist/types/utils/platform.d.ts +8 -0
  24. package/dist/types/utils/screenshot.d.ts +28 -0
  25. package/package.json +115 -0
  26. package/src/components/AnnotationInput.tsx +269 -0
  27. package/src/components/AnnotationList.tsx +248 -0
  28. package/src/components/Draggable.tsx +73 -0
  29. package/src/components/Highlighter.tsx +497 -0
  30. package/src/components/Toolbar.tsx +213 -0
  31. package/src/components/native/AnnotationInput.tsx +227 -0
  32. package/src/components/native/AnnotationList.tsx +157 -0
  33. package/src/components/native/Draggable.tsx +65 -0
  34. package/src/components/native/Highlighter.tsx +239 -0
  35. package/src/components/native/Toolbar.tsx +192 -0
  36. package/src/components/native/index.ts +6 -0
  37. package/src/components/web/AnnotationInput.tsx +150 -0
  38. package/src/components/web/AnnotationList.tsx +117 -0
  39. package/src/components/web/Draggable.tsx +74 -0
  40. package/src/components/web/Highlighter.tsx +329 -0
  41. package/src/components/web/Toolbar.tsx +198 -0
  42. package/src/components/web/index.ts +6 -0
  43. package/src/extension.tsx +15 -0
  44. package/src/index.native.tsx +50 -0
  45. package/src/index.tsx +41 -0
  46. package/src/index.web.tsx +124 -0
  47. package/src/store.tsx +120 -0
  48. package/src/utils/fiber.native.ts +90 -0
  49. package/src/utils/fiber.ts +255 -0
  50. package/src/utils/platform.ts +33 -0
  51. package/src/utils/screenshot.native.ts +139 -0
  52. package/src/utils/screenshot.ts +162 -0
@@ -0,0 +1,1004 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.native.tsx
31
+ var index_native_exports = {};
32
+ __export(index_native_exports, {
33
+ AiAnnotationProvider: () => AiAnnotationProvider2,
34
+ AnnotationInput: () => AnnotationInput,
35
+ AnnotationList: () => AnnotationList,
36
+ Draggable: () => Draggable,
37
+ Highlighter: () => Highlighter,
38
+ Toolbar: () => Toolbar,
39
+ captureScreenshot: () => captureScreenshot,
40
+ getComponentDisplayName: () => getComponentDisplayName,
41
+ getElementFromFiber: () => getElementFromFiber,
42
+ getPlatform: () => getPlatform,
43
+ getReactFiber: () => getReactFiber,
44
+ inspectComponent: () => inspectComponent,
45
+ isNative: () => isNative,
46
+ isTauriEnv: () => isTauriEnv,
47
+ isWeb: () => isWeb,
48
+ useAiAnnotation: () => useAiAnnotation
49
+ });
50
+ module.exports = __toCommonJS(index_native_exports);
51
+ var import_react_native6 = require("react-native");
52
+
53
+ // src/store.tsx
54
+ var import_react = require("react");
55
+ var import_jsx_runtime = require("react/jsx-runtime");
56
+ var initialState = {
57
+ mode: "disabled",
58
+ annotations: [],
59
+ hoveredElement: null,
60
+ hoveredComponentInfo: null,
61
+ isMinimized: false,
62
+ showList: false
63
+ };
64
+ var AnnotationContext = (0, import_react.createContext)(void 0);
65
+ function reducer(state, action) {
66
+ switch (action.type) {
67
+ case "SET_MODE":
68
+ return { ...state, mode: action.payload };
69
+ case "ADD_ANNOTATION":
70
+ return { ...state, annotations: [...state.annotations, action.payload] };
71
+ case "REMOVE_ANNOTATION":
72
+ return {
73
+ ...state,
74
+ annotations: state.annotations.filter((a) => a.id !== action.payload)
75
+ };
76
+ case "CLEAR_ALL_ANNOTATIONS":
77
+ return {
78
+ ...state,
79
+ annotations: []
80
+ };
81
+ case "SET_HOVERED":
82
+ if (state.hoveredElement === action.payload.element) return state;
83
+ return {
84
+ ...state,
85
+ hoveredElement: action.payload.element,
86
+ hoveredComponentInfo: action.payload.name ? { name: action.payload.name, details: action.payload.details } : null
87
+ };
88
+ case "RESET_HOVER":
89
+ return { ...state, hoveredElement: null, hoveredComponentInfo: null };
90
+ case "TOGGLE_MINIMIZED":
91
+ return { ...state, isMinimized: !state.isMinimized };
92
+ case "TOGGLE_LIST":
93
+ return { ...state, showList: !state.showList };
94
+ default:
95
+ return state;
96
+ }
97
+ }
98
+ function AiAnnotationProvider({ children }) {
99
+ const [state, dispatch] = (0, import_react.useReducer)(reducer, initialState);
100
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AnnotationContext.Provider, { value: { state, dispatch }, children });
101
+ }
102
+ function useAiAnnotation() {
103
+ const context = (0, import_react.useContext)(AnnotationContext);
104
+ if (!context) {
105
+ throw new Error("useAiAnnotation must be used within an AiAnnotationProvider");
106
+ }
107
+ return context;
108
+ }
109
+
110
+ // src/components/native/Toolbar.tsx
111
+ var import_react5 = require("react");
112
+ var import_react_native5 = require("react-native");
113
+
114
+ // src/components/native/Draggable.tsx
115
+ var import_react2 = require("react");
116
+ var import_react_native = require("react-native");
117
+ var import_jsx_runtime2 = require("react/jsx-runtime");
118
+ function Draggable({ children, initialPos = { x: 20, y: 20 }, style }) {
119
+ const pan = (0, import_react2.useRef)(new import_react_native.Animated.ValueXY(initialPos)).current;
120
+ const lastOffset = (0, import_react2.useRef)(initialPos);
121
+ const panResponder = (0, import_react2.useRef)(
122
+ import_react_native.PanResponder.create({
123
+ onStartShouldSetPanResponder: () => true,
124
+ onMoveShouldSetPanResponder: () => true,
125
+ onPanResponderGrant: () => {
126
+ pan.setOffset(lastOffset.current);
127
+ pan.setValue({ x: 0, y: 0 });
128
+ },
129
+ onPanResponderMove: import_react_native.Animated.event(
130
+ [null, { dx: pan.x, dy: pan.y }],
131
+ { useNativeDriver: false }
132
+ ),
133
+ onPanResponderRelease: (_e, gestureState) => {
134
+ lastOffset.current = {
135
+ x: lastOffset.current.x + gestureState.dx,
136
+ y: lastOffset.current.y + gestureState.dy
137
+ };
138
+ pan.flattenOffset();
139
+ }
140
+ })
141
+ ).current;
142
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
143
+ import_react_native.Animated.View,
144
+ {
145
+ ...panResponder.panHandlers,
146
+ style: [
147
+ styles.container,
148
+ style,
149
+ {
150
+ transform: [{ translateX: pan.x }, { translateY: pan.y }]
151
+ }
152
+ ],
153
+ children
154
+ }
155
+ );
156
+ }
157
+ var styles = import_react_native.StyleSheet.create({
158
+ container: {
159
+ position: "absolute",
160
+ zIndex: 9999
161
+ }
162
+ });
163
+
164
+ // src/components/native/Highlighter.tsx
165
+ var import_react4 = require("react");
166
+ var import_react_native3 = require("react-native");
167
+
168
+ // src/components/native/AnnotationInput.tsx
169
+ var import_react3 = require("react");
170
+ var import_react_native2 = require("react-native");
171
+ var import_jsx_runtime3 = require("react/jsx-runtime");
172
+ function AnnotationInput({ onClose, componentName }) {
173
+ const { dispatch } = useAiAnnotation();
174
+ const [note, setNote] = (0, import_react3.useState)("");
175
+ const [fadeAnim] = (0, import_react3.useState)(new import_react_native2.Animated.Value(0));
176
+ const [scaleAnim] = (0, import_react3.useState)(new import_react_native2.Animated.Value(0.95));
177
+ (0, import_react3.useEffect)(() => {
178
+ import_react_native2.Animated.parallel([
179
+ import_react_native2.Animated.timing(fadeAnim, {
180
+ toValue: 1,
181
+ duration: 200,
182
+ useNativeDriver: true
183
+ }),
184
+ import_react_native2.Animated.spring(scaleAnim, {
185
+ toValue: 1,
186
+ friction: 8,
187
+ useNativeDriver: true
188
+ })
189
+ ]).start();
190
+ }, []);
191
+ const handleClose = () => {
192
+ import_react_native2.Animated.parallel([
193
+ import_react_native2.Animated.timing(fadeAnim, {
194
+ toValue: 0,
195
+ duration: 150,
196
+ useNativeDriver: true
197
+ }),
198
+ import_react_native2.Animated.timing(scaleAnim, {
199
+ toValue: 0.95,
200
+ duration: 150,
201
+ useNativeDriver: true
202
+ })
203
+ ]).start(() => {
204
+ onClose();
205
+ });
206
+ };
207
+ const handleSubmit = () => {
208
+ if (!note.trim()) return;
209
+ dispatch({
210
+ type: "ADD_ANNOTATION",
211
+ payload: {
212
+ id: Date.now().toString(),
213
+ componentName,
214
+ note: note.trim(),
215
+ timestamp: Date.now()
216
+ }
217
+ });
218
+ handleClose();
219
+ };
220
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
221
+ import_react_native2.Modal,
222
+ {
223
+ visible: true,
224
+ transparent: true,
225
+ animationType: "none",
226
+ onRequestClose: handleClose,
227
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
228
+ import_react_native2.KeyboardAvoidingView,
229
+ {
230
+ behavior: import_react_native2.Platform.OS === "ios" ? "padding" : "height",
231
+ style: styles2.keyboardView,
232
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native2.Animated.View, { style: [styles2.overlay, { opacity: fadeAnim }], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
233
+ import_react_native2.TouchableOpacity,
234
+ {
235
+ style: styles2.backdropTouchable,
236
+ activeOpacity: 1,
237
+ onPress: handleClose,
238
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
239
+ import_react_native2.Animated.View,
240
+ {
241
+ style: [
242
+ styles2.container,
243
+ {
244
+ opacity: fadeAnim,
245
+ transform: [{ scale: scaleAnim }]
246
+ }
247
+ ],
248
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native2.TouchableOpacity, { activeOpacity: 1, children: [
249
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native2.View, { style: styles2.header, children: [
250
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native2.Text, { style: styles2.title, children: "Add Annotation" }),
251
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native2.TouchableOpacity, { onPress: handleClose, style: styles2.closeButton, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native2.Text, { style: styles2.closeButtonText, children: "\u2715" }) })
252
+ ] }),
253
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native2.Text, { style: styles2.componentLabel, children: [
254
+ "Component: ",
255
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native2.Text, { style: styles2.componentName, children: componentName })
256
+ ] }),
257
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
258
+ import_react_native2.TextInput,
259
+ {
260
+ style: styles2.textInput,
261
+ value: note,
262
+ onChangeText: setNote,
263
+ placeholder: "Describe what this component does...",
264
+ placeholderTextColor: "#6b7280",
265
+ multiline: true,
266
+ numberOfLines: 4,
267
+ textAlignVertical: "top",
268
+ autoFocus: true
269
+ }
270
+ ),
271
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native2.View, { style: styles2.buttonContainer, children: [
272
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native2.TouchableOpacity, { style: styles2.cancelButton, onPress: handleClose, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native2.Text, { style: styles2.cancelButtonText, children: "Cancel" }) }),
273
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native2.TouchableOpacity, { style: styles2.submitButton, onPress: handleSubmit, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native2.Text, { style: styles2.submitButtonText, children: "Save Annotation" }) })
274
+ ] })
275
+ ] })
276
+ }
277
+ )
278
+ }
279
+ ) })
280
+ }
281
+ )
282
+ }
283
+ );
284
+ }
285
+ var styles2 = import_react_native2.StyleSheet.create({
286
+ keyboardView: {
287
+ flex: 1
288
+ },
289
+ overlay: {
290
+ flex: 1,
291
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
292
+ justifyContent: "center",
293
+ alignItems: "center"
294
+ },
295
+ backdropTouchable: {
296
+ flex: 1,
297
+ width: "100%",
298
+ justifyContent: "center",
299
+ alignItems: "center"
300
+ },
301
+ container: {
302
+ backgroundColor: "#1e1e1e",
303
+ borderRadius: 8,
304
+ padding: 20,
305
+ width: "90%",
306
+ maxWidth: 400
307
+ },
308
+ header: {
309
+ flexDirection: "row",
310
+ justifyContent: "space-between",
311
+ alignItems: "center",
312
+ marginBottom: 16
313
+ },
314
+ title: {
315
+ color: "#e5e7eb",
316
+ fontSize: 18,
317
+ fontWeight: "bold"
318
+ },
319
+ closeButton: {
320
+ padding: 4
321
+ },
322
+ closeButtonText: {
323
+ color: "#e5e7eb",
324
+ fontSize: 20
325
+ },
326
+ componentLabel: {
327
+ color: "#9ca3af",
328
+ fontSize: 14,
329
+ marginBottom: 12
330
+ },
331
+ componentName: {
332
+ color: "#e5e7eb",
333
+ fontWeight: "bold"
334
+ },
335
+ textInput: {
336
+ backgroundColor: "#2d2d2d",
337
+ borderWidth: 1,
338
+ borderColor: "#404040",
339
+ borderRadius: 4,
340
+ padding: 8,
341
+ color: "white",
342
+ height: 100,
343
+ marginBottom: 16,
344
+ fontSize: 14
345
+ },
346
+ buttonContainer: {
347
+ flexDirection: "row",
348
+ justifyContent: "flex-end",
349
+ gap: 8
350
+ },
351
+ cancelButton: {
352
+ paddingHorizontal: 12,
353
+ paddingVertical: 8,
354
+ borderRadius: 4,
355
+ borderWidth: 1,
356
+ borderColor: "#404040"
357
+ },
358
+ cancelButtonText: {
359
+ color: "white",
360
+ fontSize: 14
361
+ },
362
+ submitButton: {
363
+ backgroundColor: "#3b82f6",
364
+ paddingHorizontal: 12,
365
+ paddingVertical: 8,
366
+ borderRadius: 4
367
+ },
368
+ submitButtonText: {
369
+ color: "white",
370
+ fontSize: 14
371
+ }
372
+ });
373
+
374
+ // src/components/native/Highlighter.tsx
375
+ var import_jsx_runtime4 = require("react/jsx-runtime");
376
+ function Highlighter({ onInspect }) {
377
+ const { state, dispatch } = useAiAnnotation();
378
+ const { mode } = state;
379
+ const [highlightRect, setHighlightRect] = (0, import_react4.useState)(null);
380
+ const [componentName, setComponentName] = (0, import_react4.useState)("");
381
+ const [showInput, setShowInput] = (0, import_react4.useState)(false);
382
+ const [showTooltip, setShowTooltip] = (0, import_react4.useState)(false);
383
+ const [tooltipPos, setTooltipPos] = (0, import_react4.useState)({ x: 0, y: 0 });
384
+ const screenDimensions = import_react_native3.Dimensions.get("window");
385
+ const handleTouch = (0, import_react4.useCallback)(
386
+ (event) => {
387
+ if (mode !== "inspecting") return;
388
+ const { pageX, pageY } = event.nativeEvent;
389
+ if (onInspect) {
390
+ const result = onInspect(event);
391
+ if (result) {
392
+ setHighlightRect(result.rect);
393
+ setComponentName(result.name);
394
+ setTooltipPos({ x: pageX, y: pageY });
395
+ setShowTooltip(true);
396
+ return;
397
+ }
398
+ }
399
+ setTooltipPos({ x: pageX, y: pageY });
400
+ setShowTooltip(true);
401
+ setComponentName("TouchedComponent");
402
+ setHighlightRect({
403
+ x: pageX - 50,
404
+ y: pageY - 50,
405
+ width: 100,
406
+ height: 100
407
+ });
408
+ },
409
+ [mode, onInspect]
410
+ );
411
+ const handleAddAnnotation = () => {
412
+ setShowInput(true);
413
+ setShowTooltip(false);
414
+ };
415
+ const handleCloseInput = () => {
416
+ setShowInput(false);
417
+ setHighlightRect(null);
418
+ setComponentName("");
419
+ };
420
+ const handleDismiss = () => {
421
+ setShowTooltip(false);
422
+ setHighlightRect(null);
423
+ setComponentName("");
424
+ };
425
+ if (mode !== "inspecting") return null;
426
+ const tooltipWidth = 120;
427
+ const tooltipHeight = 50;
428
+ let adjustedX = tooltipPos.x + 16;
429
+ let adjustedY = tooltipPos.y + 16;
430
+ if (adjustedX + tooltipWidth > screenDimensions.width) {
431
+ adjustedX = tooltipPos.x - tooltipWidth - 16;
432
+ }
433
+ if (adjustedY + tooltipHeight > screenDimensions.height) {
434
+ adjustedY = tooltipPos.y - tooltipHeight - 16;
435
+ }
436
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native3.View, { style: import_react_native3.StyleSheet.absoluteFill, pointerEvents: "box-none", children: [
437
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
438
+ import_react_native3.TouchableOpacity,
439
+ {
440
+ style: styles3.touchOverlay,
441
+ activeOpacity: 1,
442
+ onPress: handleTouch
443
+ }
444
+ ),
445
+ highlightRect && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
446
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
447
+ import_react_native3.View,
448
+ {
449
+ style: [
450
+ styles3.highlight,
451
+ {
452
+ left: highlightRect.x - 2,
453
+ top: highlightRect.y - 2,
454
+ width: highlightRect.width + 4,
455
+ height: highlightRect.height + 4
456
+ }
457
+ ],
458
+ pointerEvents: "none"
459
+ }
460
+ ),
461
+ componentName && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
462
+ import_react_native3.View,
463
+ {
464
+ style: [
465
+ styles3.nameLabel,
466
+ {
467
+ left: highlightRect.x,
468
+ top: highlightRect.y - 24
469
+ }
470
+ ],
471
+ pointerEvents: "none",
472
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native3.Text, { style: styles3.nameLabelText, children: componentName })
473
+ }
474
+ )
475
+ ] }),
476
+ showTooltip && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
477
+ import_react_native3.View,
478
+ {
479
+ style: [
480
+ styles3.tooltip,
481
+ {
482
+ left: adjustedX,
483
+ top: adjustedY
484
+ }
485
+ ],
486
+ children: [
487
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native3.TouchableOpacity, { style: styles3.tooltipButton, onPress: handleAddAnnotation, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native3.Text, { style: styles3.tooltipButtonText, children: "+" }) }),
488
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native3.TouchableOpacity, { style: styles3.dismissButton, onPress: handleDismiss, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native3.Text, { style: styles3.dismissButtonText, children: "\u2715" }) })
489
+ ]
490
+ }
491
+ ),
492
+ showInput && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AnnotationInput, { onClose: handleCloseInput, componentName: componentName || "Unknown" })
493
+ ] });
494
+ }
495
+ var styles3 = import_react_native3.StyleSheet.create({
496
+ touchOverlay: {
497
+ ...import_react_native3.StyleSheet.absoluteFillObject,
498
+ backgroundColor: "transparent"
499
+ },
500
+ highlight: {
501
+ position: "absolute",
502
+ borderWidth: 2,
503
+ borderColor: "#3b82f6",
504
+ borderRadius: 4,
505
+ backgroundColor: "rgba(59, 130, 246, 0.1)"
506
+ },
507
+ nameLabel: {
508
+ position: "absolute",
509
+ backgroundColor: "#3b82f6",
510
+ paddingHorizontal: 8,
511
+ paddingVertical: 2,
512
+ borderRadius: 4
513
+ },
514
+ nameLabelText: {
515
+ color: "white",
516
+ fontSize: 12,
517
+ fontFamily: "monospace"
518
+ },
519
+ tooltip: {
520
+ position: "absolute",
521
+ flexDirection: "row",
522
+ gap: 6,
523
+ padding: 6,
524
+ backgroundColor: "rgba(0, 0, 0, 0.9)",
525
+ borderRadius: 8,
526
+ shadowColor: "#000",
527
+ shadowOffset: { width: 0, height: 4 },
528
+ shadowOpacity: 0.3,
529
+ shadowRadius: 12,
530
+ elevation: 8
531
+ },
532
+ tooltipButton: {
533
+ width: 32,
534
+ height: 32,
535
+ borderRadius: 6,
536
+ backgroundColor: "#3b82f6",
537
+ justifyContent: "center",
538
+ alignItems: "center"
539
+ },
540
+ tooltipButtonText: {
541
+ color: "white",
542
+ fontSize: 18,
543
+ fontWeight: "bold"
544
+ },
545
+ dismissButton: {
546
+ width: 32,
547
+ height: 32,
548
+ borderRadius: 6,
549
+ backgroundColor: "#6b7280",
550
+ justifyContent: "center",
551
+ alignItems: "center"
552
+ },
553
+ dismissButtonText: {
554
+ color: "white",
555
+ fontSize: 14
556
+ }
557
+ });
558
+
559
+ // src/components/native/AnnotationList.tsx
560
+ var import_react_native4 = require("react-native");
561
+ var import_jsx_runtime5 = require("react/jsx-runtime");
562
+ function AnnotationList() {
563
+ const { state, dispatch } = useAiAnnotation();
564
+ if (!state.showList) return null;
565
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
566
+ import_react_native4.Modal,
567
+ {
568
+ visible: state.showList,
569
+ transparent: true,
570
+ animationType: "fade",
571
+ onRequestClose: () => dispatch({ type: "TOGGLE_LIST" }),
572
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.View, { style: styles4.overlay, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native4.View, { style: styles4.container, children: [
573
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native4.View, { style: styles4.header, children: [
574
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native4.Text, { style: styles4.title, children: [
575
+ "Annotations (",
576
+ state.annotations.length,
577
+ ")"
578
+ ] }),
579
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native4.View, { style: styles4.headerActions, children: [
580
+ state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
581
+ import_react_native4.TouchableOpacity,
582
+ {
583
+ style: styles4.clearButton,
584
+ onPress: () => dispatch({ type: "CLEAR_ALL_ANNOTATIONS" }),
585
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.Text, { style: styles4.clearButtonText, children: "Clear All" })
586
+ }
587
+ ),
588
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
589
+ import_react_native4.TouchableOpacity,
590
+ {
591
+ style: styles4.closeButton,
592
+ onPress: () => dispatch({ type: "TOGGLE_LIST" }),
593
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.Text, { style: styles4.closeButtonText, children: "\u2715" })
594
+ }
595
+ )
596
+ ] })
597
+ ] }),
598
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.ScrollView, { style: styles4.listContainer, children: state.annotations.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.Text, { style: styles4.emptyText, children: "No annotations yet." }) : state.annotations.map((ann) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native4.View, { style: styles4.annotationItem, children: [
599
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native4.View, { style: styles4.annotationContent, children: [
600
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.Text, { style: styles4.componentName, children: ann.componentName }),
601
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.Text, { style: styles4.annotationNote, children: ann.note })
602
+ ] }),
603
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
604
+ import_react_native4.TouchableOpacity,
605
+ {
606
+ style: styles4.deleteButton,
607
+ onPress: () => dispatch({ type: "REMOVE_ANNOTATION", payload: ann.id }),
608
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.Text, { style: styles4.deleteButtonText, children: "\u{1F5D1}" })
609
+ }
610
+ )
611
+ ] }, ann.id)) })
612
+ ] }) })
613
+ }
614
+ );
615
+ }
616
+ var styles4 = import_react_native4.StyleSheet.create({
617
+ overlay: {
618
+ flex: 1,
619
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
620
+ justifyContent: "center",
621
+ alignItems: "center"
622
+ },
623
+ container: {
624
+ backgroundColor: "#1e1e1e",
625
+ borderRadius: 8,
626
+ width: "90%",
627
+ maxWidth: 500,
628
+ maxHeight: "80%",
629
+ padding: 20
630
+ },
631
+ header: {
632
+ flexDirection: "row",
633
+ justifyContent: "space-between",
634
+ alignItems: "center",
635
+ marginBottom: 16
636
+ },
637
+ title: {
638
+ color: "#e5e7eb",
639
+ fontSize: 18,
640
+ fontWeight: "bold"
641
+ },
642
+ headerActions: {
643
+ flexDirection: "row",
644
+ alignItems: "center",
645
+ gap: 8
646
+ },
647
+ clearButton: {
648
+ backgroundColor: "#ef4444",
649
+ paddingHorizontal: 12,
650
+ paddingVertical: 6,
651
+ borderRadius: 4
652
+ },
653
+ clearButtonText: {
654
+ color: "white",
655
+ fontSize: 12
656
+ },
657
+ closeButton: {
658
+ padding: 4
659
+ },
660
+ closeButtonText: {
661
+ color: "#e5e7eb",
662
+ fontSize: 20
663
+ },
664
+ listContainer: {
665
+ flex: 1
666
+ },
667
+ emptyText: {
668
+ color: "#9ca3af",
669
+ textAlign: "center",
670
+ padding: 20
671
+ },
672
+ annotationItem: {
673
+ backgroundColor: "#2d2d2d",
674
+ padding: 12,
675
+ borderRadius: 4,
676
+ marginBottom: 8,
677
+ flexDirection: "row",
678
+ justifyContent: "space-between",
679
+ alignItems: "flex-start"
680
+ },
681
+ annotationContent: {
682
+ flex: 1,
683
+ marginRight: 12
684
+ },
685
+ componentName: {
686
+ color: "#60a5fa",
687
+ fontWeight: "bold",
688
+ fontSize: 14,
689
+ marginBottom: 4
690
+ },
691
+ annotationNote: {
692
+ color: "#e5e7eb",
693
+ fontSize: 14
694
+ },
695
+ deleteButton: {
696
+ padding: 4
697
+ },
698
+ deleteButtonText: {
699
+ fontSize: 16
700
+ }
701
+ });
702
+
703
+ // src/components/native/Toolbar.tsx
704
+ var import_jsx_runtime6 = require("react/jsx-runtime");
705
+ var copyToClipboard = async (text) => {
706
+ try {
707
+ const ExpoClipboard = await import("expo-clipboard");
708
+ await ExpoClipboard.setStringAsync(text);
709
+ } catch {
710
+ try {
711
+ const RNClipboard = await import("@react-native-clipboard/clipboard");
712
+ RNClipboard.default.setString(text);
713
+ } catch {
714
+ console.warn("No clipboard module available");
715
+ }
716
+ }
717
+ };
718
+ function Toolbar() {
719
+ const { state, dispatch } = useAiAnnotation();
720
+ const [showCopied, setShowCopied] = (0, import_react5.useState)(false);
721
+ const handleCopy = async () => {
722
+ const data = state.annotations.map((a) => ({
723
+ component: a.componentName,
724
+ instruction: a.note
725
+ }));
726
+ const text = JSON.stringify(data, null, 2);
727
+ await copyToClipboard(text);
728
+ setShowCopied(true);
729
+ setTimeout(() => setShowCopied(false), 2e3);
730
+ };
731
+ const toggleMode = () => {
732
+ dispatch({
733
+ type: "SET_MODE",
734
+ payload: state.mode === "disabled" ? "inspecting" : "disabled"
735
+ });
736
+ };
737
+ const handleToggleMinimized = () => {
738
+ dispatch({ type: "TOGGLE_MINIMIZED" });
739
+ };
740
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
741
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Highlighter, {}),
742
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AnnotationList, {}),
743
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Draggable, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native5.View, { style: styles5.toolbar, children: [
744
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.View, { style: styles5.dragHandle, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.Text, { style: styles5.dragHandleText, children: "\u22EE\u22EE" }) }),
745
+ !state.isMinimized && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
746
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.View, { style: styles5.separator }),
747
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
748
+ import_react_native5.TouchableOpacity,
749
+ {
750
+ style: [
751
+ styles5.button,
752
+ state.mode === "inspecting" && styles5.buttonActive
753
+ ],
754
+ onPress: toggleMode,
755
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.Text, { style: styles5.buttonText, children: state.mode === "inspecting" ? "\u{1F446}" : "\u{1F6AB}" })
756
+ }
757
+ ),
758
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
759
+ import_react_native5.TouchableOpacity,
760
+ {
761
+ style: styles5.button,
762
+ onPress: () => dispatch({ type: "TOGGLE_LIST" }),
763
+ children: [
764
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.Text, { style: styles5.buttonText, children: "\u{1F4CB}" }),
765
+ state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.View, { style: styles5.badge, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.Text, { style: styles5.badgeText, children: state.annotations.length }) })
766
+ ]
767
+ }
768
+ ),
769
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
770
+ import_react_native5.TouchableOpacity,
771
+ {
772
+ style: [styles5.button, showCopied && styles5.buttonSuccess],
773
+ onPress: handleCopy,
774
+ children: [
775
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.Text, { style: styles5.buttonText, children: showCopied ? "\u2713" : "\u{1F4CB}" }),
776
+ showCopied && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.Text, { style: styles5.copiedText, children: "Copied!" })
777
+ ]
778
+ }
779
+ )
780
+ ] }),
781
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.View, { style: styles5.separator }),
782
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.TouchableOpacity, { style: styles5.button, onPress: handleToggleMinimized, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.Text, { style: styles5.buttonText, children: state.isMinimized ? "\u2B1C" : "\u2796" }) })
783
+ ] }) })
784
+ ] });
785
+ }
786
+ var styles5 = import_react_native5.StyleSheet.create({
787
+ toolbar: {
788
+ backgroundColor: "#1e1e1e",
789
+ borderWidth: 1,
790
+ borderColor: "#333",
791
+ borderRadius: 8,
792
+ padding: 8,
793
+ flexDirection: "row",
794
+ alignItems: "center",
795
+ gap: 8,
796
+ shadowColor: "#000",
797
+ shadowOffset: { width: 0, height: 4 },
798
+ shadowOpacity: 0.3,
799
+ shadowRadius: 12,
800
+ elevation: 8
801
+ },
802
+ dragHandle: {
803
+ paddingHorizontal: 4
804
+ },
805
+ dragHandleText: {
806
+ color: "#666",
807
+ fontSize: 16
808
+ },
809
+ separator: {
810
+ width: 1,
811
+ height: 24,
812
+ backgroundColor: "#333"
813
+ },
814
+ button: {
815
+ width: 32,
816
+ height: 32,
817
+ borderRadius: 4,
818
+ justifyContent: "center",
819
+ alignItems: "center",
820
+ position: "relative"
821
+ },
822
+ buttonActive: {
823
+ backgroundColor: "#3b82f6"
824
+ },
825
+ buttonSuccess: {
826
+ backgroundColor: "#22c55e",
827
+ flexDirection: "row",
828
+ width: "auto",
829
+ paddingHorizontal: 8,
830
+ gap: 4
831
+ },
832
+ buttonText: {
833
+ fontSize: 16
834
+ },
835
+ copiedText: {
836
+ color: "white",
837
+ fontSize: 12
838
+ },
839
+ badge: {
840
+ position: "absolute",
841
+ top: -4,
842
+ right: -4,
843
+ backgroundColor: "#ef4444",
844
+ borderRadius: 7,
845
+ width: 14,
846
+ height: 14,
847
+ justifyContent: "center",
848
+ alignItems: "center"
849
+ },
850
+ badgeText: {
851
+ color: "white",
852
+ fontSize: 9,
853
+ fontWeight: "bold"
854
+ }
855
+ });
856
+
857
+ // src/utils/screenshot.native.ts
858
+ async function captureScreenshot(viewRef, options = {}) {
859
+ const {
860
+ scale = 2,
861
+ format = "png",
862
+ quality = 0.9,
863
+ copyToClipboard: copyToClipboard2 = false,
864
+ saveToCameraRoll = false
865
+ } = options;
866
+ try {
867
+ let captureRef;
868
+ try {
869
+ const viewShot = await import("react-native-view-shot");
870
+ captureRef = viewShot.captureRef;
871
+ } catch {
872
+ return {
873
+ success: false,
874
+ error: "react-native-view-shot is not installed. Run: npm install react-native-view-shot"
875
+ };
876
+ }
877
+ if (!viewRef.current) {
878
+ return {
879
+ success: false,
880
+ error: "View reference is null"
881
+ };
882
+ }
883
+ const uri = await captureRef(viewRef, {
884
+ format,
885
+ quality,
886
+ result: "tmpfile",
887
+ snapshotContentContainer: false
888
+ });
889
+ let base64;
890
+ if (copyToClipboard2) {
891
+ const base64Result = await captureRef(viewRef, {
892
+ format,
893
+ quality,
894
+ result: "base64",
895
+ snapshotContentContainer: false
896
+ });
897
+ base64 = base64Result;
898
+ }
899
+ if (copyToClipboard2 && base64) {
900
+ try {
901
+ const Clipboard = await import("expo-clipboard");
902
+ await Clipboard.setStringAsync(base64);
903
+ } catch {
904
+ console.warn("expo-clipboard not available for clipboard support");
905
+ }
906
+ }
907
+ if (saveToCameraRoll) {
908
+ try {
909
+ const MediaLibrary = await import("expo-media-library");
910
+ const { status } = await MediaLibrary.requestPermissionsAsync();
911
+ if (status === "granted") {
912
+ await MediaLibrary.saveToLibraryAsync(uri);
913
+ }
914
+ } catch {
915
+ console.warn("expo-media-library not available for saving to camera roll");
916
+ }
917
+ }
918
+ return {
919
+ success: true,
920
+ uri,
921
+ base64
922
+ };
923
+ } catch (error) {
924
+ const message = error instanceof Error ? error.message : "Unknown error";
925
+ console.error("Screenshot capture failed:", message);
926
+ return {
927
+ success: false,
928
+ error: message
929
+ };
930
+ }
931
+ }
932
+
933
+ // src/utils/fiber.native.ts
934
+ function getReactFiber(instance) {
935
+ if (!instance) return null;
936
+ const key = Object.keys(instance).find(
937
+ (k) => k.startsWith("__reactFiber$") || k.startsWith("__reactInternalInstance$") || k.startsWith("_reactInternals")
938
+ );
939
+ return key ? instance[key] : null;
940
+ }
941
+ function getComponentDisplayName(fiber) {
942
+ if (!fiber) return "Unknown";
943
+ let curr = fiber;
944
+ while (curr) {
945
+ const type = curr.type;
946
+ if (type) {
947
+ const name = type.displayName || type.name;
948
+ if (name && typeof name === "string") {
949
+ if (!name.startsWith("RCT") && !name.startsWith("_")) {
950
+ return name;
951
+ }
952
+ }
953
+ }
954
+ curr = curr.return;
955
+ }
956
+ return "Unknown";
957
+ }
958
+ function getElementFromFiber(_fiber) {
959
+ return null;
960
+ }
961
+ function inspectComponent(ref) {
962
+ if (!ref) return null;
963
+ const fiber = getReactFiber(ref);
964
+ if (fiber) {
965
+ return {
966
+ name: getComponentDisplayName(fiber),
967
+ props: fiber.memoizedProps
968
+ };
969
+ }
970
+ if (ref.constructor && ref.constructor.name) {
971
+ return {
972
+ name: ref.constructor.name
973
+ };
974
+ }
975
+ return null;
976
+ }
977
+
978
+ // src/utils/platform.ts
979
+ var isWeb = typeof document !== "undefined" && typeof window !== "undefined";
980
+ var isNative = !isWeb && typeof global !== "undefined";
981
+ function getPlatform() {
982
+ if (isWeb) return "web";
983
+ try {
984
+ const { Platform: Platform3 } = require("react-native");
985
+ if (Platform3.OS === "ios") return "ios";
986
+ if (Platform3.OS === "android") return "android";
987
+ return "native";
988
+ } catch {
989
+ return "native";
990
+ }
991
+ }
992
+ function isTauriEnv() {
993
+ return isWeb && typeof window !== "undefined" && "__TAURI_INTERNALS__" in window;
994
+ }
995
+
996
+ // src/index.native.tsx
997
+ var import_jsx_runtime7 = require("react/jsx-runtime");
998
+ function AiAnnotationProvider2({ children }) {
999
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AiAnnotationProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native6.View, { style: { flex: 1 }, children: [
1000
+ children,
1001
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Toolbar, {})
1002
+ ] }) });
1003
+ }
1004
+ //# sourceMappingURL=index.native.cjs.map