Skip to content

Commit 9d3497a

Browse files
committed
chore: use ts files instead of json files
1 parent ca375da commit 9d3497a

33 files changed

Lines changed: 971 additions & 584 deletions

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
blank_issues_enabled: false
22
contact_links:
33
- name: Feature Request 💡
4-
url: https://github.com/shobbak/react-native-auto-skeleton/discussions/new?category=ideas
4+
url: https://github.com/numandev1/react-native-auto-skeleton/discussions/new?category=ideas
55
about: If you have a feature request, please create a new discussion on GitHub.
66
- name: Discussions on GitHub 💬
7-
url: https://github.com/shobbak/react-native-auto-skeleton/discussions
7+
url: https://github.com/numandev1/react-native-auto-skeleton/discussions
88
about: If this library works as promised but you need help, please ask questions there.

README.md

Lines changed: 92 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,17 +101,17 @@ Your app (simulator / device) React Native DevTools
101101

102102
1. Wrap your component with `<SkeletonCapture name="card">`
103103
2. Open Skeleton Inspector in React Native DevTools
104-
3. Click **Capture** — real skeleton geometry is measured instantly
104+
3. Click **Capture** — real skeleton geometry is measured instantly
105105
4. Remove any unwanted skeletons by clicking the trash icon
106-
5. Click **Save** `card.skeletons.json` is written to your project
107-
6. Import the JSON and pass it to `<Skeleton initialSkeletons={…}>`
106+
5. Click **Save Descriptor (.ts)** for a cross-platform `.ts` file, or **↓ Save skeletons.json** for a static JSON snapshot
107+
6. The inspector shows the exact import + `<Skeleton>` snippet — copy and paste it
108108
7. Ship. Done.
109109

110110
<div align="center">
111111

112112
![Skeleton Inspector live capture](media/simulator_with_debugger.png)
113113

114-
*Live capture — simulator on the left, Skeleton Inspector DevTools panel on the right*
114+
*Live capture —> simulator on the right, Skeleton Inspector DevTools panel on the left*
115115

116116
</div>
117117

@@ -129,13 +129,85 @@ yarn add react-native-auto-shimmer
129129
130130
---
131131

132+
## Two approaches to skeleton data
133+
134+
There are two ways to provide skeleton data to `<Skeleton>`. Choose based on your needs:
135+
136+
| | **Descriptor** (TypeScript) ⭐ | **Capture** (Inspector → JSON) |
137+
|---|---|---|
138+
| How | Describe component structure in a `.ts` file | Inspector measures live layout, saves `.skeletons.json` |
139+
| Cross-platform | ✅ Perfect on every device & screen size | ⚠️ Vertical positions are device-specific |
140+
| Accuracy | Adapts at runtime to any container width | Pixel-perfect on the capture device |
141+
| Dynamic logic |`Platform.OS`, breakpoints, content length | ❌ Static JSON |
142+
| Auto-generate | ✅ Inspector generates a `.ts` starting point | ✅ Inspector saves directly |
143+
| Prop | `descriptor={myDescriptor}` | `initialSkeletons={data}` |
144+
145+
**Use Descriptor** when you target multiple screen sizes, need Android precision, or want live adaptability — **recommended**.
146+
**Use JSON Capture** when you want a quick pixel-perfect result on a single device or to verify layout visually.
147+
148+
---
149+
132150
## Quick start
133151

134-
### 1. Wrap your screen
152+
### Option A — Descriptor ⭐ (recommended, cross-platform)
153+
154+
The inspector can **auto-generate** a `.ts` descriptor from your live layout. Click **Save Descriptor (.ts)** after capturing — it writes a starting-point `.ts` file you can refine. Or write one by hand:
155+
156+
```tsx
157+
// card.skeletons.ts
158+
import type { SkeletonDescriptor } from 'react-native-auto-shimmer';
159+
160+
const cardDescriptor: SkeletonDescriptor = {
161+
display: 'flex',
162+
flexDirection: 'column',
163+
children: [
164+
{ aspectRatio: 16 / 9, borderRadius: 0 }, // hero image
165+
{
166+
display: 'flex', flexDirection: 'column',
167+
padding: 16, gap: 8,
168+
children: [
169+
{ text: 'Article Title Here', font: '700 18px Inter', lineHeight: 26 },
170+
{ text: 'Article body that may wrap across several lines of text.', font: '14px Inter', lineHeight: 20 },
171+
{
172+
display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 10,
173+
children: [
174+
{ width: 32, height: 32, borderRadius: '50%' }, // avatar
175+
{ text: 'Author Name', font: '600 14px Inter', lineHeight: 20 },
176+
],
177+
},
178+
],
179+
},
180+
],
181+
};
182+
183+
export default cardDescriptor;
184+
```
185+
186+
```tsx
187+
// ArticleScreen.tsx
188+
import { Skeleton } from 'react-native-auto-shimmer';
189+
import cardDescriptor from './skeletons/card.skeletons';
190+
191+
export function ArticleScreen() {
192+
const [loading, setLoading] = useState(true);
193+
194+
return (
195+
<Skeleton loading={loading} descriptor={cardDescriptor} style={styles.card}>
196+
<ArticleCard />
197+
</Skeleton>
198+
);
199+
}
200+
```
201+
202+
> `<Skeleton>` measures its own width via `onLayout` and runs `computeLayout()` automatically — no manual width tracking needed. Works identically on iOS and Android at any screen size.
203+
204+
### Option B — JSON Capture (pixel-perfect on capture device)
205+
206+
Run the [Skeleton Inspector](#capturing-skeletons-with-skeleton-inspector), click **Capture → Save skeletons.json**, then use the generated file:
135207

136208
```tsx
137209
import { Skeleton } from 'react-native-auto-shimmer';
138-
import cardSkeletons from './skeletons/card.skeletons.json'; // added after first capture
210+
import cardSkeletons from './skeletons/card.skeletons.json'; // generated by inspector
139211

140212
export function ArticleScreen() {
141213
const [loading, setLoading] = useState(true);
@@ -148,7 +220,7 @@ export function ArticleScreen() {
148220
}
149221
```
150222

151-
Before you've captured skeletons, `<Skeleton>` shows a blank fallback. The next section walks through capturing the real geometry.
223+
Before you've set up skeleton data, `<Skeleton>` shows a blank fallback. The next section walks through the inspector capture workflow.
152224

153225
---
154226

@@ -246,12 +318,22 @@ The panel draws every skeleton with a numbered colour overlay and a data table b
246318

247319
### Step 9 — Save
248320

249-
Click **↓ Save skeleton.json**. The file lands in the Output Directory shown in the sidebar (default `src/skeletons`):
321+
Two buttons appear after capture:
322+
323+
| Button | Output | Best for |
324+
|---|---|---|
325+
| **↓ Save Descriptor (.ts)**| `card.skeletons.ts` | Cross-platform, all Android sizes |
326+
| **↓ Save skeletons.json** | `card.skeletons.json` | Quick snapshot, single device |
327+
328+
Files land in the Output Directory shown in the sidebar (default `src/skeletons`):
250329

251330
```
252-
src/skeletons/card.skeletons.json ✓
331+
src/skeletons/card.skeletons.ts ✓ ← descriptor (recommended)
332+
src/skeletons/card.skeletons.json ✓ ← json snapshot
253333
```
254334

335+
After saving, the inspector shows a **ready-to-paste code snippet** with the exact import line and `<Skeleton>` usage — just copy and drop it into your screen file.
336+
255337
---
256338

257339
## Using saved skeletons
@@ -558,7 +640,7 @@ We welcome contributions of all sizes — bug fixes, new features, docs improvem
558640

559641
## License
560642

561-
MIT © [Numan](https://github.com/shobbak)
643+
MIT © [Numan](https://github.com/numandev1)
562644

563645
---
564646

example/metro.config.js

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ function skeletonSaveMiddleware(middleware) {
3636
req.on('data', (chunk) => (body += chunk));
3737
req.on('end', () => {
3838
try {
39-
const { name, outDir, viewportWidth, height, skeletons } = JSON.parse(body);
39+
const { name, outDir, viewportWidth, height, skeletons, asDescriptor, descriptorSource } = JSON.parse(body);
4040

4141
if (!name || !Array.isArray(skeletons) || !viewportWidth || !outDir) {
4242
res.writeHead(400);
@@ -49,30 +49,40 @@ function skeletonSaveMiddleware(middleware) {
4949
: path.resolve(__dirname, outDir);
5050
fs.mkdirSync(absOut, { recursive: true });
5151

52-
const jsonFile = path.join(absOut, `${name}.skeletons.json`);
53-
54-
let existing = { breakpoints: {} };
55-
if (fs.existsSync(jsonFile)) {
56-
try { existing = JSON.parse(fs.readFileSync(jsonFile, 'utf8')); }
57-
catch { existing = { breakpoints: {} }; }
52+
if (asDescriptor && descriptorSource) {
53+
// ── Save as .ts (ResponsiveSkeletons) ──────────────────────────
54+
const tsFile = path.join(absOut, `${name}.skeletons.ts`);
55+
fs.writeFileSync(tsFile, descriptorSource, 'utf8');
56+
const relFile = path.relative(__dirname, tsFile);
57+
console.log(`\n [Skeleton Inspector] ✓ ${name}${skeletons.length} skeletons → ${relFile}\n`);
58+
res.writeHead(200);
59+
res.end(JSON.stringify({ ok: true, file: relFile, skeletons: skeletons.length }));
60+
} else {
61+
// ── Save as .json (raw breakpoints) ────────────────────────────
62+
const jsonFile = path.join(absOut, `${name}.skeletons.json`);
63+
64+
let existing = { breakpoints: {} };
65+
if (fs.existsSync(jsonFile)) {
66+
try { existing = JSON.parse(fs.readFileSync(jsonFile, 'utf8')); }
67+
catch { existing = { breakpoints: {} }; }
68+
}
69+
70+
const key = String(Math.round(viewportWidth));
71+
existing.breakpoints[key] = {
72+
name,
73+
viewportWidth: Math.round(viewportWidth),
74+
width: Math.round(viewportWidth),
75+
height: Math.round(height || 0),
76+
skeletons,
77+
};
78+
79+
fs.writeFileSync(jsonFile, JSON.stringify(existing, null, 2) + '\n');
80+
81+
const relFile = path.relative(__dirname, jsonFile);
82+
console.log(`\n [Skeleton Inspector] ✓ ${name}${skeletons.length} skeletons → ${relFile}\n`);
83+
res.writeHead(200);
84+
res.end(JSON.stringify({ ok: true, file: relFile, skeletons: skeletons.length }));
5885
}
59-
60-
const key = String(Math.round(viewportWidth));
61-
existing.breakpoints[key] = {
62-
name,
63-
viewportWidth: Math.round(viewportWidth),
64-
width: Math.round(viewportWidth),
65-
height: Math.round(height || 0),
66-
skeletons,
67-
};
68-
69-
fs.writeFileSync(jsonFile, JSON.stringify(existing, null, 2) + '\n');
70-
71-
const relFile = path.relative(__dirname, jsonFile);
72-
console.log(`\n [Skeleton Inspector] ✓ ${name}${skeletons.length} skeletons → ${relFile}\n`);
73-
74-
res.writeHead(200);
75-
res.end(JSON.stringify({ ok: true, file: relFile, skeletons: skeletons.length }));
7686
} catch (e) {
7787
console.error('[skeleton-save] Error:', e.message);
7888
res.writeHead(500);

example/src/screens/CardScreen.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
type AnimationStyle,
1515
} from 'react-native-auto-shimmer';
1616
import { ScreenShell } from '../navigation';
17-
import cardSkeletons from '../skeletons/card.skeletons.json';
17+
import cardSkeletons from '../skeletons/card.skeletons';
1818

1919
const PAD = 16;
2020

example/src/screens/FeedScreen.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ import {
1414
type AnimationStyle,
1515
} from 'react-native-auto-shimmer';
1616
import { ScreenShell } from '../navigation';
17-
import feedPostSkeletons from '../skeletons/feedPost.skeletons.json';
18-
import feedPostTextSkeletons from '../skeletons/feedPostText.skeletons.json';
17+
import feedPostSkeletons from '../skeletons/feedPost.skeletons';
18+
import feedPostTextSkeletons from '../skeletons/feedPostText.skeletons';
1919

2020
const PAD = 16;
2121

example/src/screens/KitchenSinkScreen.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ import {
2323
} from 'react-native-auto-shimmer';
2424
import { ScreenShell } from '../navigation';
2525

26-
// ── Skeletons ──────────────────────────────────────────────────────────────────────
27-
import cardSkeletons from '../skeletons/card.skeletons.json';
28-
import feedPostSkeletons from '../skeletons/feedPost.skeletons.json';
29-
import feedPostTextSkeletons from '../skeletons/feedPostText.skeletons.json';
30-
import profileSkeletons from '../skeletons/profile.skeletons.json';
31-
import productItemSkeletons from '../skeletons/productItem.skeletons.json';
32-
import notificationSkeletons from '../skeletons/notification.skeletons.json';
26+
// ── Skeletons (descriptor-driven — responsive on every device) ─────────────────────
27+
import cardSkeletons from '../skeletons/card.skeletons';
28+
import feedPostSkeletons from '../skeletons/feedPost.skeletons';
29+
import feedPostTextSkeletons from '../skeletons/feedPostText.skeletons';
30+
import profileSkeletons from '../skeletons/profile.skeletons';
31+
import productItemSkeletons from '../skeletons/productItem.skeletons';
32+
import notificationSkeletons from '../skeletons/notification.skeletons';
3333

3434
// ── Layout constants ───────────────────────────────────────────────────────────
3535
const { width: SCREEN_W } = Dimensions.get('window');

example/src/screens/NotificationsScreen.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
type AnimationStyle,
1414
} from 'react-native-auto-shimmer';
1515
import { ScreenShell } from '../navigation';
16-
import notificationSkeletons from '../skeletons/notification.skeletons.json';
16+
import notificationSkeletons from '../skeletons/notification.skeletons';
1717

1818
const PAD = 16;
1919

example/src/screens/ProductGridScreen.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
type AnimationStyle,
1616
} from 'react-native-auto-shimmer';
1717
import { ScreenShell } from '../navigation';
18-
import productItemSkeletons from '../skeletons/productItem.skeletons.json';
18+
import productItemSkeletons from '../skeletons/productItem.skeletons';
1919

2020
const W = Dimensions.get('window').width;
2121
const PAD = 16;

example/src/screens/ProfileScreen.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
type AnimationStyle,
1515
} from 'react-native-auto-shimmer';
1616
import { ScreenShell } from '../navigation';
17-
import profileSkeletons from '../skeletons/profile.skeletons.json';
17+
import profileSkeletons from '../skeletons/profile.skeletons';
1818

1919
const PAD = 16;
2020

example/src/skeletons/card.skeletons.json

Lines changed: 0 additions & 47 deletions
This file was deleted.

0 commit comments

Comments
 (0)