rn-studio 0.2.1 → 0.3.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.
- package/bin/rn-studio-init.js +173 -0
- package/bin/rn-studio-server.js +143 -15
- package/dist/StudioProvider.d.ts +5 -18
- package/dist/StudioProvider.d.ts.map +1 -1
- package/dist/StudioProvider.js +190 -41
- package/dist/StudioProvider.js.map +1 -1
- package/dist/ast/AstEngine.d.ts.map +1 -1
- package/dist/ast/AstEngine.js +17 -0
- package/dist/ast/AstEngine.js.map +1 -1
- package/dist/ast/PreviewState.d.ts +41 -0
- package/dist/ast/PreviewState.d.ts.map +1 -0
- package/dist/ast/PreviewState.js +159 -0
- package/dist/ast/PreviewState.js.map +1 -0
- package/dist/ast/UndoStack.d.ts +18 -0
- package/dist/ast/UndoStack.d.ts.map +1 -0
- package/dist/ast/UndoStack.js +105 -0
- package/dist/ast/UndoStack.js.map +1 -0
- package/dist/components/AddPropertyModal.d.ts +19 -0
- package/dist/components/AddPropertyModal.d.ts.map +1 -0
- package/dist/components/AddPropertyModal.js +174 -0
- package/dist/components/AddPropertyModal.js.map +1 -0
- package/dist/components/InspectorPanel.js +101 -6
- package/dist/components/InspectorPanel.js.map +1 -1
- package/dist/components/SelectionOverlay.d.ts.map +1 -1
- package/dist/components/SelectionOverlay.js +5 -0
- package/dist/components/SelectionOverlay.js.map +1 -1
- package/dist/components/StyleEditor.d.ts +5 -3
- package/dist/components/StyleEditor.d.ts.map +1 -1
- package/dist/components/StyleEditor.js +45 -11
- package/dist/components/StyleEditor.js.map +1 -1
- package/dist/data/styleProperties.d.ts +26 -0
- package/dist/data/styleProperties.d.ts.map +1 -0
- package/dist/data/styleProperties.js +142 -0
- package/dist/data/styleProperties.js.map +1 -0
- package/dist/types.d.ts +37 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/autoScroll.d.ts +15 -0
- package/dist/utils/autoScroll.d.ts.map +1 -0
- package/dist/utils/autoScroll.js +132 -0
- package/dist/utils/autoScroll.js.map +1 -0
- package/dist/utils/findFiberBySource.d.ts +17 -0
- package/dist/utils/findFiberBySource.d.ts.map +1 -0
- package/dist/utils/findFiberBySource.js +76 -0
- package/dist/utils/findFiberBySource.js.map +1 -0
- package/dist/utils/persistence.d.ts +12 -0
- package/dist/utils/persistence.d.ts.map +1 -0
- package/dist/utils/persistence.js +44 -0
- package/dist/utils/persistence.js.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* eslint-disable no-console */
|
|
3
|
+
/**
|
|
4
|
+
* rn-studio init
|
|
5
|
+
*
|
|
6
|
+
* Zero-config bootstrap for consumer apps. Run:
|
|
7
|
+
*
|
|
8
|
+
* npx rn-studio init
|
|
9
|
+
*
|
|
10
|
+
* This command:
|
|
11
|
+
* 1. Adds `rn-studio/babel-plugin` to the project's babel.config.js
|
|
12
|
+
* (gated on `process.env.NODE_ENV !== 'production'`)
|
|
13
|
+
* 2. Adds a `"studio": "rn-studio-server"` script to package.json
|
|
14
|
+
* 3. Prints the exact snippet to paste into App.tsx
|
|
15
|
+
*/
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
const cwd = process.cwd();
|
|
20
|
+
const INDIGO = '\x1b[38;5;111m';
|
|
21
|
+
const GREEN = '\x1b[32m';
|
|
22
|
+
const GREY = '\x1b[90m';
|
|
23
|
+
const BOLD = '\x1b[1m';
|
|
24
|
+
const RESET = '\x1b[0m';
|
|
25
|
+
|
|
26
|
+
function log(msg) { console.log(msg); }
|
|
27
|
+
function ok(msg) { console.log(`${GREEN}✓${RESET} ${msg}`); }
|
|
28
|
+
function info(msg) { console.log(`${INDIGO}→${RESET} ${msg}`); }
|
|
29
|
+
function warn(msg) { console.log(`${GREY}! ${msg}${RESET}`); }
|
|
30
|
+
|
|
31
|
+
function banner() {
|
|
32
|
+
console.log('');
|
|
33
|
+
console.log(` ${INDIGO}${BOLD}rn-studio init${RESET}`);
|
|
34
|
+
console.log(` ${GREY}Live UI editor for React Native${RESET}`);
|
|
35
|
+
console.log('');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* ───────────────── package.json ───────────────── */
|
|
39
|
+
function patchPackageJson() {
|
|
40
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
41
|
+
if (!fs.existsSync(pkgPath)) {
|
|
42
|
+
warn('No package.json found — skipping script injection.');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const raw = fs.readFileSync(pkgPath, 'utf-8');
|
|
46
|
+
const pkg = JSON.parse(raw);
|
|
47
|
+
pkg.scripts = pkg.scripts || {};
|
|
48
|
+
|
|
49
|
+
if (pkg.scripts.studio === 'rn-studio-server') {
|
|
50
|
+
ok('package.json already has a "studio" script.');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (pkg.scripts.studio && pkg.scripts.studio !== 'rn-studio-server') {
|
|
54
|
+
warn(`package.json has a different "studio" script (${pkg.scripts.studio}). Leaving untouched.`);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
pkg.scripts.studio = 'rn-studio-server';
|
|
58
|
+
// Preserve two-space indentation convention.
|
|
59
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
|
|
60
|
+
ok('Added `"studio": "rn-studio-server"` to package.json scripts.');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* ───────────────── babel.config.js ───────────────── */
|
|
64
|
+
function patchBabelConfig() {
|
|
65
|
+
const candidates = [
|
|
66
|
+
'babel.config.js',
|
|
67
|
+
'babel.config.cjs',
|
|
68
|
+
'babel.config.mjs',
|
|
69
|
+
'.babelrc.js',
|
|
70
|
+
'.babelrc',
|
|
71
|
+
];
|
|
72
|
+
const found = candidates
|
|
73
|
+
.map((c) => path.join(cwd, c))
|
|
74
|
+
.find((p) => fs.existsSync(p));
|
|
75
|
+
|
|
76
|
+
if (!found) {
|
|
77
|
+
warn('No babel.config.js found — creating one.');
|
|
78
|
+
const fresh = `module.exports = {
|
|
79
|
+
presets: ['module:@react-native/babel-preset'],
|
|
80
|
+
plugins: [
|
|
81
|
+
...(process.env.NODE_ENV !== 'production' ? ['rn-studio/babel-plugin'] : []),
|
|
82
|
+
],
|
|
83
|
+
};
|
|
84
|
+
`;
|
|
85
|
+
fs.writeFileSync(path.join(cwd, 'babel.config.js'), fresh, 'utf-8');
|
|
86
|
+
ok('Created babel.config.js with rn-studio plugin registered.');
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const content = fs.readFileSync(found, 'utf-8');
|
|
91
|
+
if (content.indexOf('rn-studio/babel-plugin') !== -1) {
|
|
92
|
+
ok(`${path.basename(found)} already references rn-studio/babel-plugin.`);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Attempt a light, string-based injection. If the file has a
|
|
97
|
+
// `plugins: [ ... ]` array, append the spread expression; otherwise
|
|
98
|
+
// add a new plugins property after the presets line.
|
|
99
|
+
let patched;
|
|
100
|
+
if (/plugins\s*:\s*\[/.test(content)) {
|
|
101
|
+
patched = content.replace(
|
|
102
|
+
/plugins\s*:\s*\[/,
|
|
103
|
+
`plugins: [\n ...(process.env.NODE_ENV !== 'production' ? ['rn-studio/babel-plugin'] : []),`,
|
|
104
|
+
);
|
|
105
|
+
} else {
|
|
106
|
+
patched = content.replace(
|
|
107
|
+
/presets\s*:\s*\[[^\]]*\]\s*,?/,
|
|
108
|
+
(m) => `${m.replace(/,?\s*$/, ',')}\n plugins: [\n ...(process.env.NODE_ENV !== 'production' ? ['rn-studio/babel-plugin'] : []),\n ],`,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (patched === content) {
|
|
113
|
+
warn(`Could not auto-patch ${path.basename(found)} — add this manually:`);
|
|
114
|
+
console.log(
|
|
115
|
+
` plugins: [\n ...(process.env.NODE_ENV !== 'production' ? ['rn-studio/babel-plugin'] : []),\n ],`,
|
|
116
|
+
);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
fs.writeFileSync(found, patched, 'utf-8');
|
|
121
|
+
ok(`Patched ${path.basename(found)} to include rn-studio/babel-plugin.`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* ───────────────── App.tsx snippet ───────────────── */
|
|
125
|
+
function printAppSnippet() {
|
|
126
|
+
console.log('');
|
|
127
|
+
info('Add this to your App.tsx (or wherever you mount the root):');
|
|
128
|
+
console.log('');
|
|
129
|
+
console.log(`${GREY}────────────────────────────────────────────────${RESET}`);
|
|
130
|
+
console.log(`${INDIGO}import${RESET} { StudioProvider } ${INDIGO}from${RESET} 'rn-studio';`);
|
|
131
|
+
console.log('');
|
|
132
|
+
console.log(`${INDIGO}export default function${RESET} App() {`);
|
|
133
|
+
console.log(' return (');
|
|
134
|
+
console.log(` <StudioProvider enabled={__DEV__} bubblePosition="bottom-right">`);
|
|
135
|
+
console.log(' <YourApp />');
|
|
136
|
+
console.log(' </StudioProvider>');
|
|
137
|
+
console.log(' );');
|
|
138
|
+
console.log('}');
|
|
139
|
+
console.log(`${GREY}────────────────────────────────────────────────${RESET}`);
|
|
140
|
+
console.log('');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* ───────────────── run instructions ───────────────── */
|
|
144
|
+
function printRunInstructions() {
|
|
145
|
+
console.log(`${BOLD}Next steps:${RESET}`);
|
|
146
|
+
console.log('');
|
|
147
|
+
console.log(` ${GREY}#${RESET} Terminal 1 — Metro`);
|
|
148
|
+
console.log(` ${INDIGO}npx${RESET} react-native start`);
|
|
149
|
+
console.log('');
|
|
150
|
+
console.log(` ${GREY}#${RESET} Terminal 2 — rn-studio server`);
|
|
151
|
+
console.log(` ${INDIGO}npm run${RESET} studio`);
|
|
152
|
+
console.log('');
|
|
153
|
+
console.log(
|
|
154
|
+
`${GREEN}✓ Setup complete.${RESET} Launch your app, tap the floating bubble,\n then tap any component to edit its styles live.`,
|
|
155
|
+
);
|
|
156
|
+
console.log('');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/* ───────────────── main ───────────────── */
|
|
160
|
+
function main() {
|
|
161
|
+
banner();
|
|
162
|
+
try {
|
|
163
|
+
patchPackageJson();
|
|
164
|
+
patchBabelConfig();
|
|
165
|
+
printAppSnippet();
|
|
166
|
+
printRunInstructions();
|
|
167
|
+
} catch (err) {
|
|
168
|
+
console.error(`\n${GREY}!${RESET} rn-studio init failed:`, err && err.message);
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
main();
|
package/bin/rn-studio-server.js
CHANGED
|
@@ -5,19 +5,23 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Run alongside Metro: npm run studio
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* Handles:
|
|
9
|
+
* - STYLE_CHANGE → AST engine rewrites the source file
|
|
10
|
+
* - UNDO / REDO → pops/pushes the in-memory edit stack
|
|
11
|
+
* - STACK_STATE broadcast so clients can enable/disable buttons
|
|
12
12
|
*/
|
|
13
13
|
const { WebSocketServer } = require('ws');
|
|
14
14
|
|
|
15
|
-
let
|
|
15
|
+
let AstEngine;
|
|
16
|
+
let UndoStack;
|
|
17
|
+
let PreviewState;
|
|
16
18
|
try {
|
|
17
|
-
|
|
19
|
+
AstEngine = require('../dist/ast/AstEngine');
|
|
20
|
+
UndoStack = require('../dist/ast/UndoStack');
|
|
21
|
+
PreviewState = require('../dist/ast/PreviewState');
|
|
18
22
|
} catch (err) {
|
|
19
23
|
console.error(
|
|
20
|
-
'[rn-studio] Unable to load dist
|
|
24
|
+
'[rn-studio] Unable to load dist modules. Did you run `npm run build`?',
|
|
21
25
|
);
|
|
22
26
|
console.error(err.message);
|
|
23
27
|
process.exit(1);
|
|
@@ -29,8 +33,22 @@ const wss = new WebSocketServer({ port: PORT });
|
|
|
29
33
|
console.log(`[rn-studio] Server running on ws://localhost:${PORT}`);
|
|
30
34
|
console.log('[rn-studio] Waiting for React Native runtime to connect...');
|
|
31
35
|
|
|
36
|
+
function broadcastStackState(ws) {
|
|
37
|
+
const state = UndoStack.getStackState();
|
|
38
|
+
const payload = JSON.stringify({ type: 'STACK_STATE', payload: state });
|
|
39
|
+
if (ws) {
|
|
40
|
+
ws.send(payload);
|
|
41
|
+
} else {
|
|
42
|
+
wss.clients.forEach((c) => {
|
|
43
|
+
if (c.readyState === 1) c.send(payload);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
32
48
|
wss.on('connection', (ws) => {
|
|
33
49
|
console.log('[rn-studio] Client connected');
|
|
50
|
+
// Sync new clients with the current stack depths.
|
|
51
|
+
broadcastStackState(ws);
|
|
34
52
|
|
|
35
53
|
ws.on('message', async (raw) => {
|
|
36
54
|
let msg;
|
|
@@ -41,7 +59,7 @@ wss.on('connection', (ws) => {
|
|
|
41
59
|
JSON.stringify({
|
|
42
60
|
type: 'ERROR',
|
|
43
61
|
payload: { message: 'Invalid JSON payload' },
|
|
44
|
-
})
|
|
62
|
+
}),
|
|
45
63
|
);
|
|
46
64
|
return;
|
|
47
65
|
}
|
|
@@ -54,7 +72,7 @@ wss.on('connection', (ws) => {
|
|
|
54
72
|
|
|
55
73
|
if (msg.type === 'STYLE_CHANGE') {
|
|
56
74
|
const { source, key, value } = msg.payload;
|
|
57
|
-
await rewriteStyle({
|
|
75
|
+
await AstEngine.rewriteStyle({
|
|
58
76
|
file: source.file,
|
|
59
77
|
line: source.line,
|
|
60
78
|
column: source.column,
|
|
@@ -63,18 +81,119 @@ wss.on('connection', (ws) => {
|
|
|
63
81
|
});
|
|
64
82
|
ws.send(JSON.stringify({ type: 'ACK', payload: { success: true } }));
|
|
65
83
|
console.log(
|
|
66
|
-
`[rn-studio] ✓ ${source.componentName} → ${key}: ${value}
|
|
84
|
+
`[rn-studio] ✓ ${source.componentName} → ${key}: ${value}`,
|
|
85
|
+
);
|
|
86
|
+
broadcastStackState();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (msg.type === 'UNDO') {
|
|
91
|
+
const entry = UndoStack.undo();
|
|
92
|
+
if (entry) {
|
|
93
|
+
console.log(`[rn-studio] ↶ undo: ${entry.label} (${entry.file})`);
|
|
94
|
+
ws.send(
|
|
95
|
+
JSON.stringify({
|
|
96
|
+
type: 'ACK',
|
|
97
|
+
payload: { success: true, message: 'undo' },
|
|
98
|
+
}),
|
|
99
|
+
);
|
|
100
|
+
} else {
|
|
101
|
+
ws.send(
|
|
102
|
+
JSON.stringify({
|
|
103
|
+
type: 'ACK',
|
|
104
|
+
payload: { success: false, message: 'Nothing to undo' },
|
|
105
|
+
}),
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
broadcastStackState();
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (msg.type === 'REDO') {
|
|
113
|
+
const entry = UndoStack.redo();
|
|
114
|
+
if (entry) {
|
|
115
|
+
console.log(`[rn-studio] ↷ redo: ${entry.label} (${entry.file})`);
|
|
116
|
+
ws.send(
|
|
117
|
+
JSON.stringify({
|
|
118
|
+
type: 'ACK',
|
|
119
|
+
payload: { success: true, message: 'redo' },
|
|
120
|
+
}),
|
|
121
|
+
);
|
|
122
|
+
} else {
|
|
123
|
+
ws.send(
|
|
124
|
+
JSON.stringify({
|
|
125
|
+
type: 'ACK',
|
|
126
|
+
payload: { success: false, message: 'Nothing to redo' },
|
|
127
|
+
}),
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
broadcastStackState();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (msg.type === 'BEGIN_PREVIEW') {
|
|
135
|
+
const file = msg.payload && msg.payload.file;
|
|
136
|
+
if (file) {
|
|
137
|
+
PreviewState.begin(file);
|
|
138
|
+
console.log(`[rn-studio] ⋯ preview begin: ${file}`);
|
|
139
|
+
}
|
|
140
|
+
ws.send(JSON.stringify({ type: 'ACK', payload: { success: true } }));
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (msg.type === 'COMMIT_PREVIEW') {
|
|
145
|
+
const result = PreviewState.commit();
|
|
146
|
+
if (result && result.editCount > 0) {
|
|
147
|
+
console.log(
|
|
148
|
+
`[rn-studio] ✓ preview commit: ${result.editCount} edit${
|
|
149
|
+
result.editCount === 1 ? '' : 's'
|
|
150
|
+
} (${result.file})`,
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
ws.send(
|
|
154
|
+
JSON.stringify({
|
|
155
|
+
type: 'ACK',
|
|
156
|
+
payload: {
|
|
157
|
+
success: true,
|
|
158
|
+
message: result ? `committed ${result.editCount}` : 'nothing to commit',
|
|
159
|
+
},
|
|
160
|
+
}),
|
|
161
|
+
);
|
|
162
|
+
broadcastStackState();
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (msg.type === 'CANCEL_PREVIEW') {
|
|
167
|
+
const result = PreviewState.cancel();
|
|
168
|
+
if (result && result.editCount > 0) {
|
|
169
|
+
console.log(
|
|
170
|
+
`[rn-studio] ↺ preview cancel: reverted ${result.editCount} edit${
|
|
171
|
+
result.editCount === 1 ? '' : 's'
|
|
172
|
+
} (${result.file})`,
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
ws.send(
|
|
176
|
+
JSON.stringify({
|
|
177
|
+
type: 'ACK',
|
|
178
|
+
payload: {
|
|
179
|
+
success: true,
|
|
180
|
+
message: result ? `reverted ${result.editCount}` : 'nothing to cancel',
|
|
181
|
+
},
|
|
182
|
+
}),
|
|
67
183
|
);
|
|
184
|
+
broadcastStackState();
|
|
68
185
|
return;
|
|
69
186
|
}
|
|
70
187
|
|
|
71
188
|
if (msg.type === 'PROP_CHANGE') {
|
|
72
|
-
// Reserved for future prop editing. Ack for now.
|
|
73
189
|
ws.send(
|
|
74
190
|
JSON.stringify({
|
|
75
191
|
type: 'ACK',
|
|
76
|
-
payload: {
|
|
77
|
-
|
|
192
|
+
payload: {
|
|
193
|
+
success: true,
|
|
194
|
+
message: 'PROP_CHANGE not yet implemented',
|
|
195
|
+
},
|
|
196
|
+
}),
|
|
78
197
|
);
|
|
79
198
|
return;
|
|
80
199
|
}
|
|
@@ -84,12 +203,21 @@ wss.on('connection', (ws) => {
|
|
|
84
203
|
JSON.stringify({
|
|
85
204
|
type: 'ERROR',
|
|
86
205
|
payload: { message: err && err.message ? err.message : String(err) },
|
|
87
|
-
})
|
|
206
|
+
}),
|
|
88
207
|
);
|
|
89
208
|
}
|
|
90
209
|
});
|
|
91
210
|
|
|
92
|
-
ws.on('close', () =>
|
|
211
|
+
ws.on('close', () => {
|
|
212
|
+
console.log('[rn-studio] Client disconnected');
|
|
213
|
+
// Abandon any in-flight preview so a stale buffer can't bleed
|
|
214
|
+
// into a later session on a different file.
|
|
215
|
+
if (PreviewState.isActive()) {
|
|
216
|
+
PreviewState.cancel();
|
|
217
|
+
console.log('[rn-studio] (preview auto-cancelled on disconnect)');
|
|
218
|
+
broadcastStackState();
|
|
219
|
+
}
|
|
220
|
+
});
|
|
93
221
|
});
|
|
94
222
|
|
|
95
223
|
process.on('SIGINT', () => {
|
package/dist/StudioProvider.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { MutableRefObject } from 'react';
|
|
2
|
-
import type { BubblePosition, StudioConfig, StudioContextValue } from './types';
|
|
2
|
+
import type { BubblePosition, SourceLocation, StudioConfig, StudioContextValue } from './types';
|
|
3
3
|
interface Props extends Partial<StudioConfig> {
|
|
4
4
|
enabled?: boolean;
|
|
5
5
|
serverPort?: number;
|
|
@@ -8,26 +8,13 @@ interface Props extends Partial<StudioConfig> {
|
|
|
8
8
|
children: React.ReactNode;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* Shared mutable ref to the app root view. Populated by
|
|
12
|
-
* and consumed by `<SelectionOverlay>` for
|
|
13
|
-
*
|
|
14
|
-
* scope avoids having to thread it through context (and keeps the
|
|
15
|
-
* context value shape unchanged for consumers).
|
|
11
|
+
* Shared mutable ref to the app root view. Populated by
|
|
12
|
+
* `<StudioProvider>` and consumed by `<SelectionOverlay>` for
|
|
13
|
+
* hit-testing via `getInspectorDataForViewAtPoint`.
|
|
16
14
|
*/
|
|
17
15
|
export declare const appRootRef: MutableRefObject<any>;
|
|
18
|
-
/**
|
|
19
|
-
* <StudioProvider>
|
|
20
|
-
*
|
|
21
|
-
* Wrap your App.tsx with this provider. When `enabled` is false (the
|
|
22
|
-
* default, intended for production), it renders children verbatim and
|
|
23
|
-
* introduces zero overhead — no context, no bridge, no overlay.
|
|
24
|
-
*
|
|
25
|
-
* When enabled, it manages the studio state machine, opens a WebSocket
|
|
26
|
-
* connection to the CLI server, and renders the floating bubble,
|
|
27
|
-
* selection overlay, and inspector panel above your app.
|
|
28
|
-
*/
|
|
29
16
|
export declare function StudioProvider({ children, enabled, serverPort, bubblePosition, }: Props): React.JSX.Element;
|
|
17
|
+
export type { SourceLocation };
|
|
30
18
|
/** Hook for any descendant of `<StudioProvider>` to read studio state. */
|
|
31
19
|
export declare function useStudio(): StudioContextValue;
|
|
32
|
-
export {};
|
|
33
20
|
//# sourceMappingURL=StudioProvider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StudioProvider.d.ts","sourceRoot":"","sources":["../src/StudioProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EACZ,gBAAgB,
|
|
1
|
+
{"version":3,"file":"StudioProvider.d.ts","sourceRoot":"","sources":["../src/StudioProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EACZ,gBAAgB,EAMjB,MAAM,OAAO,CAAC;AAYf,OAAO,KAAK,EACV,cAAc,EAEd,cAAc,EACd,YAAY,EACZ,kBAAkB,EAEnB,MAAM,SAAS,CAAC;AAEjB,UAAU,KAAM,SAAQ,OAAO,CAAC,YAAY,CAAC;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED;;;;GAIG;AAEH,eAAO,MAAM,UAAU,EAAE,gBAAgB,CAAC,GAAG,CAAqB,CAAC;AAEnE,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,OAAe,EACf,UAAiB,EACjB,cAA+B,GAChC,EAAE,KAAK,qBAYP;AA0QD,YAAY,EAAE,cAAc,EAAE,CAAC;AAE/B,0EAA0E;AAC1E,wBAAgB,SAAS,IAAI,kBAAkB,CAM9C"}
|