rn-backstage 1.0.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 (102) hide show
  1. package/README.md +80 -0
  2. package/lib/commonjs/Backstage.js +130 -0
  3. package/lib/commonjs/Backstage.js.map +1 -0
  4. package/lib/commonjs/components/BackstagePanel.js +192 -0
  5. package/lib/commonjs/components/BackstagePanel.js.map +1 -0
  6. package/lib/commonjs/components/FloatingPill.js +147 -0
  7. package/lib/commonjs/components/FloatingPill.js.map +1 -0
  8. package/lib/commonjs/components/InfoTab.js +260 -0
  9. package/lib/commonjs/components/InfoTab.js.map +1 -0
  10. package/lib/commonjs/components/JsonTreeView.js +245 -0
  11. package/lib/commonjs/components/JsonTreeView.js.map +1 -0
  12. package/lib/commonjs/components/LogItem.js +191 -0
  13. package/lib/commonjs/components/LogItem.js.map +1 -0
  14. package/lib/commonjs/components/LogsTab.js +235 -0
  15. package/lib/commonjs/components/LogsTab.js.map +1 -0
  16. package/lib/commonjs/components/TabBar.js +132 -0
  17. package/lib/commonjs/components/TabBar.js.map +1 -0
  18. package/lib/commonjs/constants.js +89 -0
  19. package/lib/commonjs/constants.js.map +1 -0
  20. package/lib/commonjs/index.js +20 -0
  21. package/lib/commonjs/index.js.map +1 -0
  22. package/lib/commonjs/log-interceptor.js +114 -0
  23. package/lib/commonjs/log-interceptor.js.map +1 -0
  24. package/lib/commonjs/package.json +1 -0
  25. package/lib/commonjs/types.js +21 -0
  26. package/lib/commonjs/types.js.map +1 -0
  27. package/lib/commonjs/utils/formatTimestamp.js +26 -0
  28. package/lib/commonjs/utils/formatTimestamp.js.map +1 -0
  29. package/lib/commonjs/utils/stringify.js +78 -0
  30. package/lib/commonjs/utils/stringify.js.map +1 -0
  31. package/lib/module/Backstage.js +125 -0
  32. package/lib/module/Backstage.js.map +1 -0
  33. package/lib/module/components/BackstagePanel.js +187 -0
  34. package/lib/module/components/BackstagePanel.js.map +1 -0
  35. package/lib/module/components/FloatingPill.js +142 -0
  36. package/lib/module/components/FloatingPill.js.map +1 -0
  37. package/lib/module/components/InfoTab.js +255 -0
  38. package/lib/module/components/InfoTab.js.map +1 -0
  39. package/lib/module/components/JsonTreeView.js +241 -0
  40. package/lib/module/components/JsonTreeView.js.map +1 -0
  41. package/lib/module/components/LogItem.js +186 -0
  42. package/lib/module/components/LogItem.js.map +1 -0
  43. package/lib/module/components/LogsTab.js +230 -0
  44. package/lib/module/components/LogsTab.js.map +1 -0
  45. package/lib/module/components/TabBar.js +127 -0
  46. package/lib/module/components/TabBar.js.map +1 -0
  47. package/lib/module/constants.js +85 -0
  48. package/lib/module/constants.js.map +1 -0
  49. package/lib/module/index.js +5 -0
  50. package/lib/module/index.js.map +1 -0
  51. package/lib/module/log-interceptor.js +108 -0
  52. package/lib/module/log-interceptor.js.map +1 -0
  53. package/lib/module/package.json +1 -0
  54. package/lib/module/types.js +25 -0
  55. package/lib/module/types.js.map +1 -0
  56. package/lib/module/utils/formatTimestamp.js +22 -0
  57. package/lib/module/utils/formatTimestamp.js.map +1 -0
  58. package/lib/module/utils/stringify.js +73 -0
  59. package/lib/module/utils/stringify.js.map +1 -0
  60. package/lib/typescript/Backstage.d.ts +4 -0
  61. package/lib/typescript/Backstage.d.ts.map +1 -0
  62. package/lib/typescript/components/BackstagePanel.d.ts +21 -0
  63. package/lib/typescript/components/BackstagePanel.d.ts.map +1 -0
  64. package/lib/typescript/components/FloatingPill.d.ts +13 -0
  65. package/lib/typescript/components/FloatingPill.d.ts.map +1 -0
  66. package/lib/typescript/components/InfoTab.d.ts +16 -0
  67. package/lib/typescript/components/InfoTab.d.ts.map +1 -0
  68. package/lib/typescript/components/JsonTreeView.d.ts +10 -0
  69. package/lib/typescript/components/JsonTreeView.d.ts.map +1 -0
  70. package/lib/typescript/components/LogItem.d.ts +10 -0
  71. package/lib/typescript/components/LogItem.d.ts.map +1 -0
  72. package/lib/typescript/components/LogsTab.d.ts +11 -0
  73. package/lib/typescript/components/LogsTab.d.ts.map +1 -0
  74. package/lib/typescript/components/TabBar.d.ts +14 -0
  75. package/lib/typescript/components/TabBar.d.ts.map +1 -0
  76. package/lib/typescript/constants.d.ts +43 -0
  77. package/lib/typescript/constants.d.ts.map +1 -0
  78. package/lib/typescript/index.d.ts +4 -0
  79. package/lib/typescript/index.d.ts.map +1 -0
  80. package/lib/typescript/log-interceptor.d.ts +16 -0
  81. package/lib/typescript/log-interceptor.d.ts.map +1 -0
  82. package/lib/typescript/types.d.ts +110 -0
  83. package/lib/typescript/types.d.ts.map +1 -0
  84. package/lib/typescript/utils/formatTimestamp.d.ts +7 -0
  85. package/lib/typescript/utils/formatTimestamp.d.ts.map +1 -0
  86. package/lib/typescript/utils/stringify.d.ts +9 -0
  87. package/lib/typescript/utils/stringify.d.ts.map +1 -0
  88. package/package.json +91 -0
  89. package/src/Backstage.tsx +145 -0
  90. package/src/components/BackstagePanel.tsx +208 -0
  91. package/src/components/FloatingPill.tsx +150 -0
  92. package/src/components/InfoTab.tsx +264 -0
  93. package/src/components/JsonTreeView.tsx +259 -0
  94. package/src/components/LogItem.tsx +189 -0
  95. package/src/components/LogsTab.tsx +239 -0
  96. package/src/components/TabBar.tsx +150 -0
  97. package/src/constants.ts +82 -0
  98. package/src/index.ts +14 -0
  99. package/src/log-interceptor.ts +137 -0
  100. package/src/types.ts +147 -0
  101. package/src/utils/formatTimestamp.ts +22 -0
  102. package/src/utils/stringify.ts +90 -0
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import type { LogEntry, BackstageStyleOverrides } from '../types';
3
+ interface LogsTabProps {
4
+ logs: LogEntry[];
5
+ onRefresh: () => void;
6
+ onCopyLogs?: (logs: string) => void;
7
+ styles?: BackstageStyleOverrides;
8
+ }
9
+ export declare const LogsTab: React.FC<LogsTabProps>;
10
+ export {};
11
+ //# sourceMappingURL=LogsTab.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LogsTab.d.ts","sourceRoot":"","sources":["../../../src/components/LogsTab.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyC,MAAM,OAAO,CAAA;AAG7D,OAAO,KAAK,EAAE,QAAQ,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAA;AAMjE,UAAU,YAAY;IACpB,IAAI,EAAE,QAAQ,EAAE,CAAA;IAChB,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,MAAM,CAAC,EAAE,uBAAuB,CAAA;CACjC;AAID,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CAmH1C,CAAA"}
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ interface Tab {
3
+ key: string;
4
+ title: string;
5
+ icon?: string;
6
+ }
7
+ interface TabBarProps {
8
+ tabs: Tab[];
9
+ activeTab: string;
10
+ onTabChange: (key: string) => void;
11
+ }
12
+ export declare const TabBar: React.FC<TabBarProps>;
13
+ export {};
14
+ //# sourceMappingURL=TabBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TabBar.d.ts","sourceRoot":"","sources":["../../../src/components/TabBar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyC,MAAM,OAAO,CAAA;AAc7D,UAAU,GAAG;IACX,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,UAAU,WAAW;IACnB,IAAI,EAAE,GAAG,EAAE,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CACnC;AAID,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAyExC,CAAA"}
@@ -0,0 +1,43 @@
1
+ import type { BackstageTheme } from './types';
2
+ export declare const Metrics: {
3
+ screenWidth: number;
4
+ screenHeight: number;
5
+ isIOS: boolean;
6
+ pillWidth: number;
7
+ pillHeight: number;
8
+ panelBorderRadius: number;
9
+ tabBarHeight: number;
10
+ headerHeight: number;
11
+ sectionSpacing: number;
12
+ contentPadding: number;
13
+ };
14
+ export declare const DarkTheme: BackstageTheme;
15
+ export declare const DEFAULT_MAX_LOGS = 500;
16
+ export declare const MonospaceFont: string;
17
+ export declare const TestIDs: {
18
+ floatingPill: string;
19
+ panel: string;
20
+ header: {
21
+ container: string;
22
+ title: string;
23
+ closeButton: string;
24
+ };
25
+ tabBar: string;
26
+ tabs: {
27
+ info: string;
28
+ logs: string;
29
+ };
30
+ infoTab: {
31
+ section: string;
32
+ deviceInfo: string;
33
+ stateTree: string;
34
+ quickActions: string;
35
+ };
36
+ logsTab: {
37
+ section: string;
38
+ searchInput: string;
39
+ copyButton: string;
40
+ list: string;
41
+ };
42
+ };
43
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAM7C,eAAO,MAAM,OAAO;;;;;;;;;;;CAWnB,CAAA;AAID,eAAO,MAAM,SAAS,EAAE,cAmBvB,CAAA;AAID,eAAO,MAAM,gBAAgB,MAAM,CAAA;AAInC,eAAO,MAAM,aAAa,QAGxB,CAAA;AAIF,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;CAyBnB,CAAA"}
@@ -0,0 +1,4 @@
1
+ export { Backstage } from './Backstage';
2
+ export type { BackstageProps, BackstageRef, BackstageTab, BackstageStyleOverrides, BackstageTheme, QuickAction, AppInfoItem, LogEntry, } from './types';
3
+ export { LogLevel } from './types';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAEvC,YAAY,EACV,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,uBAAuB,EACvB,cAAc,EACd,WAAW,EACX,WAAW,EACX,QAAQ,GACT,MAAM,SAAS,CAAA;AAEhB,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA"}
@@ -0,0 +1,16 @@
1
+ import type { LogEntry } from './types';
2
+ type LogCallback = (entry: LogEntry) => void;
3
+ export declare function installInterceptor(callback: LogCallback, filters?: string[]): void;
4
+ export declare function uninstallInterceptor(): void;
5
+ export declare class LogBuffer {
6
+ private logs;
7
+ private maxSize;
8
+ constructor(maxSize?: number);
9
+ push(entry: LogEntry): void;
10
+ getAll(): LogEntry[];
11
+ clear(): void;
12
+ get hasErrors(): boolean;
13
+ get size(): number;
14
+ }
15
+ export {};
16
+ //# sourceMappingURL=log-interceptor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-interceptor.d.ts","sourceRoot":"","sources":["../../src/log-interceptor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAcvC,KAAK,WAAW,GAAG,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAA;AAyC5C,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,GAAE,MAAM,EAAO,GAAG,IAAI,CAiCtF;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAW3C;AAID,qBAAa,SAAS;IACpB,OAAO,CAAC,IAAI,CAAiB;IAC7B,OAAO,CAAC,OAAO,CAAQ;gBAEX,OAAO,SAAmB;IAItC,IAAI,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAO3B,MAAM,IAAI,QAAQ,EAAE;IAIpB,KAAK,IAAI,IAAI;IAIb,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
@@ -0,0 +1,110 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { StyleProp, TextStyle, ViewStyle } from 'react-native';
3
+ export declare enum LogLevel {
4
+ log = "log",
5
+ debug = "debug",
6
+ info = "info",
7
+ warn = "warn",
8
+ error = "error"
9
+ }
10
+ export interface LogEntry {
11
+ id: string;
12
+ level: LogLevel;
13
+ message: string;
14
+ data?: unknown;
15
+ timestamp: number;
16
+ }
17
+ export interface AppInfoItem {
18
+ label: string;
19
+ value: string;
20
+ }
21
+ export interface QuickAction {
22
+ title: string;
23
+ onPress: () => void;
24
+ closeOnPress?: boolean;
25
+ icon?: string;
26
+ destructive?: boolean;
27
+ testID?: string;
28
+ }
29
+ export interface BackstageTab {
30
+ key: string;
31
+ title: string;
32
+ icon?: string;
33
+ render: () => ReactNode;
34
+ }
35
+ export interface BackstageTheme {
36
+ background: string;
37
+ surface: string;
38
+ surfaceElevated: string;
39
+ border: string;
40
+ text: string;
41
+ textSecondary: string;
42
+ textMuted: string;
43
+ accent: string;
44
+ accentDim: string;
45
+ error: string;
46
+ errorDim: string;
47
+ warning: string;
48
+ warningDim: string;
49
+ success: string;
50
+ info: string;
51
+ infoDim: string;
52
+ debugColor: string;
53
+ debugDim: string;
54
+ }
55
+ export interface BackstageProps {
56
+ /** Whether the floating pill trigger is visible. Default: true */
57
+ visible?: boolean;
58
+ /** App version string (e.g., "1.2.3") */
59
+ appVersion?: string;
60
+ /** Build number (e.g., "42") */
61
+ buildNumber?: string;
62
+ /** Bundle identifier (e.g., "com.example.app") */
63
+ bundleId?: string;
64
+ /** Additional device/app information rows */
65
+ deviceInfo?: AppInfoItem[];
66
+ /** State object to display in the tree viewer (Redux store, Zustand, etc.) */
67
+ state?: Record<string, unknown>;
68
+ /** Custom action buttons in the Info tab */
69
+ quickActions?: QuickAction[];
70
+ /** Maximum number of logs to retain in memory. Default: 500 */
71
+ maxLogs?: number;
72
+ /** Log messages containing these strings will be excluded */
73
+ logFilters?: string[];
74
+ /** Callback triggered when user copies logs */
75
+ onCopyLogs?: (logs: string) => void;
76
+ /** Additional custom tabs beyond Info and Logs */
77
+ extraTabs?: BackstageTab[];
78
+ /** Extra content rendered at the bottom of the Info tab */
79
+ children?: ReactNode;
80
+ /** Custom styles overrides */
81
+ styles?: BackstageStyleOverrides;
82
+ /** Initial X position for the floating pill */
83
+ initialX?: number;
84
+ /** Initial Y position for the floating pill */
85
+ initialY?: number;
86
+ /** Text displayed on the floating pill. Defaults to appVersion or "DEV" */
87
+ pillText?: string;
88
+ }
89
+ export interface BackstageStyleOverrides {
90
+ pillStyle?: StyleProp<ViewStyle>;
91
+ pillTextStyle?: StyleProp<TextStyle>;
92
+ panelStyle?: StyleProp<ViewStyle>;
93
+ headerTitleStyle?: StyleProp<TextStyle>;
94
+ sectionTitleStyle?: StyleProp<TextStyle>;
95
+ infoLabelStyle?: StyleProp<TextStyle>;
96
+ infoValueStyle?: StyleProp<TextStyle>;
97
+ actionButtonStyle?: StyleProp<ViewStyle>;
98
+ actionButtonTitleStyle?: StyleProp<TextStyle>;
99
+ logTimestampStyle?: StyleProp<TextStyle>;
100
+ logMessageStyle?: StyleProp<TextStyle>;
101
+ }
102
+ export interface BackstageRef {
103
+ /** Open the backstage panel */
104
+ open: () => void;
105
+ /** Close the backstage panel */
106
+ close: () => void;
107
+ /** Clear all captured logs */
108
+ clearLogs: () => void;
109
+ }
110
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Formats a timestamp (Date.now()) into a human-readable local time string.
3
+ * Format: "h:mm:ss.SSS AM/PM"
4
+ * No external dependencies — uses native Date API.
5
+ */
6
+ export declare function formatTimestamp(timestamp: number): string;
7
+ //# sourceMappingURL=formatTimestamp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatTimestamp.d.ts","sourceRoot":"","sources":["../../../src/utils/formatTimestamp.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAgBzD"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Safely stringifies a value, handling circular references and Error objects.
3
+ */
4
+ export declare function safeStringify(value: unknown, indent?: number): string;
5
+ /**
6
+ * Formats a console message and its optional params into a single string.
7
+ */
8
+ export declare function formatLogMessage(message: unknown, optionalParams?: unknown[]): string;
9
+ //# sourceMappingURL=stringify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stringify.d.ts","sourceRoot":"","sources":["../../../src/utils/stringify.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,SAAI,GAAG,MAAM,CA4ChE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,cAAc,CAAC,EAAE,OAAO,EAAE,GAAG,MAAM,CA4BrF"}
package/package.json ADDED
@@ -0,0 +1,91 @@
1
+ {
2
+ "name": "rn-backstage",
3
+ "version": "1.0.0",
4
+ "description": "A zero-dependency developer/QA debug panel for React Native apps",
5
+ "main": "lib/commonjs/index",
6
+ "module": "lib/module/index",
7
+ "types": "lib/typescript/index.d.ts",
8
+ "react-native": "src/index",
9
+ "source": "src/index",
10
+ "files": [
11
+ "src",
12
+ "lib",
13
+ "!**/__tests__",
14
+ "!**/__fixtures__",
15
+ "!**/__mocks__",
16
+ "!**/.*"
17
+ ],
18
+ "scripts": {
19
+ "typecheck": "tsc --noEmit",
20
+ "lint": "prettier --write \"**/*.{js,ts,tsx}\" && eslint \"**/*.{js,ts,tsx}\"",
21
+ "prepack": "bob build",
22
+ "release": "release-it",
23
+ "clean": "del-cli lib"
24
+ },
25
+ "keywords": [
26
+ "react-native",
27
+ "backstage",
28
+ "debug",
29
+ "developer-tools",
30
+ "qa-menu",
31
+ "dev-tools",
32
+ "console-logs",
33
+ "state-inspector"
34
+ ],
35
+ "repository": "https://github.com/junocs/react-native-backstage",
36
+ "author": "Juno Sheridan <juno.sheridan@gmail.com> (https://github.com)",
37
+ "license": "MIT",
38
+ "bugs": {
39
+ "url": "https://github.com/junocs/react-native-backstage/issues"
40
+ },
41
+ "homepage": "https://github.com/junocs/react-native-backstage#readme",
42
+ "publishConfig": {
43
+ "registry": "https://registry.npmjs.org/",
44
+ "access": "public"
45
+ },
46
+ "devDependencies": {
47
+ "@types/react": "~18.3.0",
48
+ "del-cli": "^6.0.0",
49
+ "eslint": "^9.0.0",
50
+ "prettier": "^3.0.0",
51
+ "react": "18.3.1",
52
+ "react-native": "^0.78.0",
53
+ "react-native-builder-bob": "^0.35.0",
54
+ "release-it": "^18.0.0",
55
+ "typescript": "^5.0.0",
56
+ "typescript-eslint": "^8.57.2"
57
+ },
58
+ "peerDependencies": {
59
+ "react": "*",
60
+ "react-native": "*"
61
+ },
62
+ "engines": {
63
+ "node": ">= 18.0.0"
64
+ },
65
+ "prettier": {
66
+ "quoteProps": "consistent",
67
+ "singleQuote": true,
68
+ "tabWidth": 2,
69
+ "useTabs": false,
70
+ "bracketSameLine": false,
71
+ "bracketSpacing": true,
72
+ "semi": false,
73
+ "trailingComma": "all",
74
+ "arrowParens": "avoid",
75
+ "printWidth": 100
76
+ },
77
+ "react-native-builder-bob": {
78
+ "source": "src",
79
+ "output": "lib",
80
+ "targets": [
81
+ "commonjs",
82
+ "module",
83
+ [
84
+ "typescript",
85
+ {
86
+ "project": "tsconfig.build.json"
87
+ }
88
+ ]
89
+ ]
90
+ }
91
+ }
@@ -0,0 +1,145 @@
1
+ import React, {
2
+ forwardRef,
3
+ useCallback,
4
+ useEffect,
5
+ useImperativeHandle,
6
+ useRef,
7
+ useState,
8
+ } from 'react'
9
+ import { StyleSheet, View } from 'react-native'
10
+ import { DEFAULT_MAX_LOGS } from './constants'
11
+ import { installInterceptor, LogBuffer, uninstallInterceptor } from './log-interceptor'
12
+ import { FloatingPill } from './components/FloatingPill'
13
+ import { BackstagePanel } from './components/BackstagePanel'
14
+ import type { BackstageProps, BackstageRef, LogEntry } from './types'
15
+
16
+ // ─── Component ───────────────────────────────────────────────────────────────
17
+
18
+ export const Backstage = forwardRef<BackstageRef, BackstageProps>(
19
+ (
20
+ {
21
+ visible = true,
22
+ appVersion,
23
+ buildNumber,
24
+ bundleId,
25
+ deviceInfo,
26
+ state,
27
+ quickActions,
28
+ maxLogs = DEFAULT_MAX_LOGS,
29
+ logFilters,
30
+ onCopyLogs,
31
+ extraTabs,
32
+ children,
33
+ styles: propStyles,
34
+ initialX,
35
+ initialY,
36
+ pillText,
37
+ },
38
+ ref,
39
+ ) => {
40
+ const [panelVisible, setPanelVisible] = useState(false)
41
+ const [hasError, setHasError] = useState(false)
42
+ const [logs, setLogs] = useState<LogEntry[]>([])
43
+
44
+ const logBuffer = useRef(new LogBuffer(maxLogs))
45
+
46
+ // ── Panel controls ────────────────────────────────────────
47
+
48
+ const openPanel = useCallback(() => {
49
+ setPanelVisible(true)
50
+ // Sync logs when opening panel
51
+ setLogs(logBuffer.current.getAll())
52
+ }, [])
53
+
54
+ const closePanel = useCallback(() => {
55
+ setPanelVisible(false)
56
+ }, [])
57
+
58
+ const clearLogs = useCallback(() => {
59
+ logBuffer.current.clear()
60
+ setLogs([])
61
+ setHasError(false)
62
+ }, [])
63
+
64
+ // ── Refresh logs ──────────────────────────────────────────
65
+
66
+ const refreshLogs = useCallback(() => {
67
+ setLogs(logBuffer.current.getAll())
68
+ }, [])
69
+
70
+ // ── Install console interceptor ───────────────────────────
71
+
72
+ useEffect(() => {
73
+ const handleLogEntry = (entry: LogEntry) => {
74
+ logBuffer.current.push(entry)
75
+
76
+ // Track error state for the floating pill
77
+ if (entry.level === 'error') {
78
+ setHasError(true)
79
+ }
80
+ }
81
+
82
+ installInterceptor(handleLogEntry, logFilters)
83
+
84
+ return () => {
85
+ uninstallInterceptor()
86
+ }
87
+ }, [logFilters])
88
+
89
+ // ── Expose ref methods ────────────────────────────────────
90
+
91
+ useImperativeHandle(ref, () => ({
92
+ open: openPanel,
93
+ close: closePanel,
94
+ clearLogs,
95
+ }))
96
+
97
+ // ── Render ────────────────────────────────────────────────
98
+
99
+ if (!visible) return null
100
+
101
+ const displayText = pillText || (appVersion ? `v${appVersion}` : 'DEV')
102
+
103
+ return (
104
+ <View style={styles.container} pointerEvents="box-none">
105
+ <FloatingPill
106
+ text={displayText}
107
+ hasError={hasError}
108
+ onPress={openPanel}
109
+ initialX={initialX}
110
+ initialY={initialY}
111
+ styles={propStyles}
112
+ />
113
+ <BackstagePanel
114
+ visible={panelVisible}
115
+ onClose={closePanel}
116
+ appVersion={appVersion}
117
+ buildNumber={buildNumber}
118
+ bundleId={bundleId}
119
+ deviceInfo={deviceInfo}
120
+ state={state}
121
+ quickActions={quickActions}
122
+ logs={logs}
123
+ onRefreshLogs={refreshLogs}
124
+ onCopyLogs={onCopyLogs}
125
+ extraTabs={extraTabs}
126
+ styles={propStyles}
127
+ >
128
+ {children}
129
+ </BackstagePanel>
130
+ </View>
131
+ )
132
+ },
133
+ )
134
+
135
+ Backstage.displayName = 'Backstage'
136
+
137
+ // ─── Styles ──────────────────────────────────────────────────────────────────
138
+
139
+ const styles = StyleSheet.create({
140
+ container: {
141
+ ...StyleSheet.absoluteFillObject,
142
+ zIndex: 99999,
143
+ elevation: 99999,
144
+ },
145
+ })