rn-studio 0.3.2 β 0.3.3
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/README.md +213 -54
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,66 +1,76 @@
|
|
|
1
|
-
# rn-studio
|
|
1
|
+
# π¨ rn-studio
|
|
2
2
|
|
|
3
|
-
> Live UI editor for React Native
|
|
3
|
+
> **Live UI editor for React Native.** Tap any component in your running simulator and edit its styles β every change is written straight back to your source code, with Metro Fast Refresh updating the UI in milliseconds.
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/rn-studio)
|
|
6
|
-
[](https://github.com/dgutierrezd/rn-studio/blob/main/LICENSE)
|
|
7
|
-
[](https://www.npmjs.com/package/rn-studio)
|
|
6
|
+
[](https://github.com/dgutierrezd/rn-studio/blob/main/LICENSE)
|
|
7
|
+
[](https://github.com/dgutierrezd/rn-studio)
|
|
8
|
+
[](https://github.com/dgutierrezd/rn-studio)
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
---
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
## Demo
|
|
12
|
+
## π¬ Demo
|
|
14
13
|
|
|
15
14
|
[](https://github.com/dgutierrezd/rn-studio/releases/download/v0.2.0/rn-studio-demo.mov)
|
|
16
15
|
|
|
17
16
|
> Tap the floating bubble β selection mode activates β tap any component β the inspector panel slides up with the component's styles, tree, and props. Edit a value, and the source file is rewritten via AST in real time while Metro Fast Refresh re-renders the UI.
|
|
18
17
|
>
|
|
19
|
-
> _Click the thumbnail to watch the full
|
|
18
|
+
> _Click the thumbnail to watch the full video._
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## β¨ What you get
|
|
23
|
+
|
|
24
|
+
| | Feature | Details |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| π― | **Tap-to-inspect** | Tap any on-screen component. Walks the React fiber tree to find the nearest user-code source, skipping library internals. Works on both **Fabric** and the **legacy architecture**. |
|
|
27
|
+
| π
| **Live style editing** | Edit any style and watch it apply instantly via Metro Fast Refresh. The AST engine rewrites the exact JSX element in your source β including `style={styles.foo}` references, which are resolved back into your `StyleSheet.create()` declaration. |
|
|
28
|
+
| π | **Preview mode** | Every edit is held in a server-side preview buffer until you tap **β Commit** or **βΊ Cancel**. Cancel reverts the file to its exact original state β your git diff stays clean. |
|
|
29
|
+
| βΆβ· | **Undo / Redo** | 50-deep edit history. Commit a preview β get a single consolidated undo entry. Tap βΆ to revert the whole batch in one go. |
|
|
30
|
+
| β | **Add any RN property** | Tap "+ Add property" to open a searchable modal of ~80 React Native style properties, grouped by category (Layout, Flex, Spacing, Sizing, Position, Background, Border, Shadow, Typography, Transform, Visibility). |
|
|
31
|
+
| π | **Auto-scroll on select** | Tap a component hidden behind the inspector panel and rn-studio walks the fiber tree to find the nearest `ScrollView` / `FlatList` / `SectionList` ancestor and scrolls it so your component lands in the top 12% of the screen. |
|
|
32
|
+
| πΎ | **Selection persists across reloads** | Cmd+R the simulator and your last-selected component is re-selected automatically via the React DevTools fiber-root walker. |
|
|
33
|
+
| ποΈ | **Three-tab inspector** | **Styles** (edit), **Tree** (component hierarchy), **Props** (read-only inspection). All scrollable. |
|
|
34
|
+
| π¨ | **Minimal indigo UI** | Clean `#7C9BFF` accent on a pure `#111` dark background. No distracting lime greens. |
|
|
35
|
+
| πͺΆ | **Zero extra deps** | No `react-native-reanimated`, no `react-native-gesture-handler` required. Pure RN + stock `Animated` API. |
|
|
36
|
+
| π« | **Zero production overhead** | `<StudioProvider enabled={__DEV__}>` short-circuits to `{children}` in release builds. Babel plugin is dev-only. |
|
|
37
|
+
| π | **One-command setup** | `npx rn-studio init` wires up `babel.config.js` and `package.json` for you. |
|
|
20
38
|
|
|
21
|
-
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## π¦ Install
|
|
22
42
|
|
|
23
43
|
```bash
|
|
24
44
|
npm install rn-studio
|
|
25
45
|
```
|
|
26
46
|
|
|
27
|
-
|
|
47
|
+
Then run the init command β it patches `babel.config.js`, adds the `studio` script to `package.json`, and prints the snippet to paste into `App.tsx`:
|
|
28
48
|
|
|
29
49
|
```bash
|
|
30
|
-
|
|
50
|
+
npx rn-studio init
|
|
31
51
|
```
|
|
32
52
|
|
|
33
|
-
>
|
|
34
|
-
|
|
35
|
-
> `Animated` API so consumers don't need the worklets babel plugin.
|
|
36
|
-
|
|
37
|
-
## Setup
|
|
53
|
+
<details>
|
|
54
|
+
<summary><strong>π Manual setup (if you prefer)</strong></summary>
|
|
38
55
|
|
|
39
|
-
### 1.
|
|
56
|
+
### 1. Register the babel plugin (dev only)
|
|
40
57
|
|
|
41
58
|
```js
|
|
42
59
|
// babel.config.js
|
|
43
60
|
module.exports = {
|
|
44
|
-
presets: ['module
|
|
61
|
+
presets: ['module:@react-native/babel-preset'],
|
|
45
62
|
plugins: [
|
|
46
|
-
...(process.env.NODE_ENV !== 'production'
|
|
63
|
+
...(process.env.NODE_ENV !== 'production'
|
|
64
|
+
? ['rn-studio/babel-plugin']
|
|
65
|
+
: []),
|
|
47
66
|
],
|
|
48
67
|
};
|
|
49
68
|
```
|
|
50
69
|
|
|
51
|
-
### 2.
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
# Terminal 1
|
|
55
|
-
npx react-native start
|
|
56
|
-
|
|
57
|
-
# Terminal 2
|
|
58
|
-
npm run studio
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
Add to your app's `package.json`:
|
|
70
|
+
### 2. Add the studio script
|
|
62
71
|
|
|
63
72
|
```json
|
|
73
|
+
// package.json
|
|
64
74
|
{
|
|
65
75
|
"scripts": {
|
|
66
76
|
"studio": "rn-studio-server"
|
|
@@ -82,47 +92,196 @@ export default function App() {
|
|
|
82
92
|
}
|
|
83
93
|
```
|
|
84
94
|
|
|
85
|
-
|
|
95
|
+
</details>
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## βΆοΈ Run it
|
|
100
|
+
|
|
101
|
+
Open two terminal tabs:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Terminal 1 β Metro
|
|
105
|
+
npx react-native start
|
|
106
|
+
|
|
107
|
+
# Terminal 2 β rn-studio server
|
|
108
|
+
npm run studio
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Launch your app in the simulator. A floating π¨ bubble appears in the bottom-right. Tap it, tap any component, and start editing.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## π§ How it works
|
|
86
116
|
|
|
87
117
|
| Layer | What it does |
|
|
88
118
|
|---|---|
|
|
89
|
-
| Babel plugin | Annotates every JSX element with file
|
|
90
|
-
| Floating bubble | Toggles selection mode
|
|
91
|
-
| Selection overlay |
|
|
92
|
-
| Inspector panel |
|
|
93
|
-
| WebSocket bridge |
|
|
94
|
-
| AST engine |
|
|
95
|
-
| Metro Fast Refresh | Picks up the file change and updates
|
|
119
|
+
| π§ **Babel plugin** | Annotates every JSX element at compile time with `__rnStudioSource = { file, line, column, componentName }` |
|
|
120
|
+
| π«§ **Floating bubble** | Toggles selection mode with a spring-animated draggable overlay |
|
|
121
|
+
| π― **Selection overlay** | Uses RN's built-in `getInspectorDataForViewAtPoint` (Fabric + legacy) to hit-test touches, then walks the fiber `.return` chain to the nearest user-code source |
|
|
122
|
+
| πͺ **Inspector panel** | Bottom-sheet with Styles / Tree / Props tabs β fully scrollable, auto-scrolls the underlying `ScrollView` so the selected component stays visible |
|
|
123
|
+
| π **WebSocket bridge** | Streams edits from the app over `ws://localhost:7878` with exponential-backoff reconnect |
|
|
124
|
+
| π οΈ **AST engine** | Reads the target file with `recast` + `@babel/parser`, locates the exact JSX opening element by `(line, column)`, and rewrites the `style` prop. Handles inline objects, array styles, and `StyleSheet.create()` references. Refuses to touch `node_modules`. |
|
|
125
|
+
| π **Metro Fast Refresh** | Picks up the file change and updates your UI in milliseconds |
|
|
126
|
+
| π **Undo / Preview state** | Server keeps a 50-deep undo stack plus a preview buffer for uncommitted edits |
|
|
127
|
+
|
|
128
|
+
---
|
|
96
129
|
|
|
97
|
-
## API
|
|
130
|
+
## π API
|
|
98
131
|
|
|
99
132
|
### `<StudioProvider>` props
|
|
100
133
|
|
|
101
134
|
| Prop | Type | Default | Description |
|
|
102
135
|
|---|---|---|---|
|
|
103
|
-
| `enabled` | `boolean` | `false` | Show the studio UI |
|
|
136
|
+
| `enabled` | `boolean` | `false` | Show the studio UI. Pass `__DEV__` to enable in development only. |
|
|
104
137
|
| `serverPort` | `number` | `7878` | CLI server port |
|
|
105
|
-
| `bubblePosition` | `'bottom-right' \| 'bottom-left' \| 'top-right' \| 'top-left'` | `'bottom-right'` |
|
|
106
|
-
| `theme` | `'dark' \| 'light'` | `'dark'` | Panel theme |
|
|
138
|
+
| `bubblePosition` | `'bottom-right' \| 'bottom-left' \| 'top-right' \| 'top-left'` | `'bottom-right'` | Starting corner for the floating bubble |
|
|
139
|
+
| `theme` | `'dark' \| 'light'` | `'dark'` | Panel theme (currently dark only) |
|
|
107
140
|
|
|
108
141
|
### `useStudio()`
|
|
109
142
|
|
|
110
143
|
```ts
|
|
111
144
|
const {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
145
|
+
// Selection state
|
|
146
|
+
isActive, // boolean β selection mode toggled?
|
|
147
|
+
isSelecting, // boolean β waiting for a tap?
|
|
148
|
+
selectedComponent, // ComponentNode | null
|
|
149
|
+
|
|
150
|
+
// Actions
|
|
151
|
+
toggleActive, // () => void
|
|
152
|
+
selectComponent, // (node: ComponentNode) => void
|
|
153
|
+
clearSelection, // () => void
|
|
154
|
+
|
|
155
|
+
// Style editing
|
|
156
|
+
updateStyle, // (key: string, value: string | number) => void
|
|
157
|
+
addStyleProperty, // (key: string, value: string | number | boolean) => void
|
|
158
|
+
|
|
159
|
+
// Undo / Redo
|
|
160
|
+
undo, // () => void
|
|
161
|
+
redo, // () => void
|
|
162
|
+
canUndo, // boolean
|
|
163
|
+
canRedo, // boolean
|
|
164
|
+
|
|
165
|
+
// Preview mode
|
|
166
|
+
hasPendingPreview, // boolean
|
|
167
|
+
commitPreview, // () => void
|
|
168
|
+
cancelPreview, // () => void
|
|
119
169
|
} = useStudio();
|
|
120
170
|
```
|
|
121
171
|
|
|
122
|
-
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## π‘οΈ Preview mode explained
|
|
175
|
+
|
|
176
|
+
Every edit made while a component is selected is held in a **server-side preview buffer** until you explicitly commit or cancel.
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
180
|
+
β Tap component β BEGIN_PREVIEW β server snapshots β
|
|
181
|
+
β the file β
|
|
182
|
+
β β
|
|
183
|
+
β Edit fontSize 14β28 β β
|
|
184
|
+
β Edit color #fffβblue βββ each write hits disk β
|
|
185
|
+
β Edit padding 10β24 β Metro Fast Refresh shows it β
|
|
186
|
+
β β BUT nothing enters the undo stack β
|
|
187
|
+
β β
|
|
188
|
+
β βββββ Preview badge shows in panel header βββββ β
|
|
189
|
+
β β βΊ β replace βΆ β· β β
|
|
190
|
+
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
|
|
191
|
+
β β
|
|
192
|
+
β Your choice: β
|
|
193
|
+
β β
|
|
194
|
+
β β Commit β server packs all edits into a SINGLE undo β
|
|
195
|
+
β entry labeled "preview (N edits)". β
|
|
196
|
+
β You can still βΆ to revert the whole batch. β
|
|
197
|
+
β β
|
|
198
|
+
β βΊ Cancel β server writes the original snapshot back. β
|
|
199
|
+
β File is pristine. No undo entry created. β
|
|
200
|
+
β Your git diff stays clean. β
|
|
201
|
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Auto-commit triggers:** switching to a different component, closing the panel, toggling the bubble off. **Auto-cancel triggers:** client disconnect (app reload, server restart).
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## π‘ Tips
|
|
209
|
+
|
|
210
|
+
- ποΈ **Drag the floating bubble** anywhere on screen β its position is saved to `AsyncStorage` (optional dependency).
|
|
211
|
+
- β« **Cmd+R** in the simulator β your last-selected component is re-selected automatically.
|
|
212
|
+
- π¨ **Tap a color swatch** to see it highlighted, then edit the hex directly.
|
|
213
|
+
- β **Tap "+ Add property"** inside the Styles tab to search all ~80 React Native style properties.
|
|
214
|
+
- π **Switch to the Props tab** to inspect every non-style prop of the selected component (read-only for now).
|
|
215
|
+
- π³ **Switch to the Tree tab** to navigate nested rn-studio-annotated children.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## π« Production safety
|
|
220
|
+
|
|
221
|
+
Three independent guarantees ensure **zero production overhead**:
|
|
222
|
+
|
|
223
|
+
1. π **Babel plugin** early-returns when `NODE_ENV === 'production'` β `__rnStudioSource` is never emitted in release bundles.
|
|
224
|
+
2. π§© **`<StudioProvider enabled={false}>`** short-circuits to `<>{children}</>` β no context, no WebSocket, no overlay.
|
|
225
|
+
3. π¦ **Consumer convention** β pass `enabled={__DEV__}` so the whole system ties to React Native's own dev flag.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## π Changelog highlights
|
|
230
|
+
|
|
231
|
+
<details>
|
|
232
|
+
<summary><strong>v0.3.2</strong> β Fix styles disappearing on undo</summary>
|
|
233
|
+
|
|
234
|
+
Undo/redo/cancel now refresh the inspector's style list from the live fiber tree instead of leaving stale or empty state. New shared `extractStylesFromFiber` utility used by both the overlay and the provider.
|
|
235
|
+
|
|
236
|
+
</details>
|
|
237
|
+
|
|
238
|
+
<details>
|
|
239
|
+
<summary><strong>v0.3.1</strong> β Preview mode β βΊ</summary>
|
|
240
|
+
|
|
241
|
+
Every style edit is held in a server-side preview buffer. Tap β to commit (single consolidated undo entry) or βΊ to revert the file to its exact state at selection time. Auto-commits on deselect, auto-cancels on disconnect.
|
|
242
|
+
|
|
243
|
+
</details>
|
|
244
|
+
|
|
245
|
+
<details>
|
|
246
|
+
<summary><strong>v0.3.0</strong> β Add property picker, init CLI, undo/redo, persistence, auto-scroll</summary>
|
|
247
|
+
|
|
248
|
+
Five major features shipped together:
|
|
249
|
+
- Searchable modal listing ~80 RN style properties across 11 groups
|
|
250
|
+
- `npx rn-studio init` β zero-config project bootstrap
|
|
251
|
+
- 50-deep undo/redo stack with βΆ β· buttons
|
|
252
|
+
- Selection persistence across Cmd+R via AsyncStorage + fiber walker
|
|
253
|
+
- Auto-scroll walks the fiber tree to bring the selected component into view above the 60% panel
|
|
254
|
+
|
|
255
|
+
</details>
|
|
256
|
+
|
|
257
|
+
<details>
|
|
258
|
+
<summary><strong>v0.2.0</strong> β Selection flow fix for Fabric + AST StyleSheet resolution</summary>
|
|
259
|
+
|
|
260
|
+
Replaces legacy `UIManager.findSubviewIn` with `getInspectorDataForViewAtPoint`. Walks the fiber `.return` chain instead of the flat hierarchy. AST engine resolves `style={styles.foo}` into `StyleSheet.create()` entries. Dropped hard peer deps on reanimated and gesture-handler.
|
|
261
|
+
|
|
262
|
+
</details>
|
|
263
|
+
|
|
264
|
+
Full history: [GitHub Releases](https://github.com/dgutierrezd/rn-studio/releases)
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## π€ Contributing
|
|
269
|
+
|
|
270
|
+
Pull requests welcome! For major changes, please open an issue first so we can talk it through.
|
|
271
|
+
|
|
272
|
+
Local development:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
git clone https://github.com/dgutierrezd/rn-studio.git
|
|
276
|
+
cd rn-studio
|
|
277
|
+
npm install
|
|
278
|
+
npm run build # compile TS to dist/
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
The `dist/` output is what gets published to npm. The `bin/` folder contains the CLI entry points (`rn-studio-server`, `rn-studio-init`), which run against the compiled `dist/ast/AstEngine.js`.
|
|
123
282
|
|
|
124
|
-
|
|
283
|
+
---
|
|
125
284
|
|
|
126
|
-
## License
|
|
285
|
+
## π License
|
|
127
286
|
|
|
128
287
|
MIT Β© [dgutierrezd](https://github.com/dgutierrezd)
|