noboarding 0.1.0-beta → 1.0.1-beta
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/AI_CUSTOM_SCREEN_GUIDE.md +23 -7
- package/README.md +59 -0
- package/lib/OnboardingFlow.js +4 -1
- package/lib/components/ElementRenderer.js +8 -1
- package/lib/types.d.ts +1 -0
- package/package.json +9 -3
- package/src/OnboardingFlow.tsx +7 -4
- package/src/components/ElementRenderer.tsx +8 -0
- package/src/types.ts +2 -0
|
@@ -237,7 +237,11 @@ export const SummaryScreen: React.FC<CustomScreenProps> = ({
|
|
|
237
237
|
|
|
238
238
|
```typescript
|
|
239
239
|
<OnboardingFlow
|
|
240
|
-
|
|
240
|
+
// Dual API keys for automatic environment detection
|
|
241
|
+
testKey="nb_test_..."
|
|
242
|
+
productionKey="nb_live_..."
|
|
243
|
+
// SDK auto-detects __DEV__ and uses appropriate key
|
|
244
|
+
|
|
241
245
|
customComponents={{
|
|
242
246
|
NameScreen,
|
|
243
247
|
AgeScreen,
|
|
@@ -543,7 +547,12 @@ import { AgeScreen } from './screens/AgeScreen';
|
|
|
543
547
|
import { PreferencesScreen } from './screens/PreferencesScreen';
|
|
544
548
|
|
|
545
549
|
<OnboardingFlow
|
|
546
|
-
|
|
550
|
+
// Use dual API keys for automatic environment detection
|
|
551
|
+
testKey="nb_test_your_test_key"
|
|
552
|
+
productionKey="nb_live_your_production_key"
|
|
553
|
+
// The SDK automatically uses testKey when __DEV__ is true
|
|
554
|
+
// and productionKey in production builds
|
|
555
|
+
|
|
547
556
|
customComponents={{
|
|
548
557
|
NameScreen: NameScreen, // Component name MUST match exactly
|
|
549
558
|
AgeScreen: AgeScreen, // Case-sensitive!
|
|
@@ -593,10 +602,14 @@ npm start
|
|
|
593
602
|
|
|
594
603
|
### Step 5: Deploy & Publish
|
|
595
604
|
|
|
596
|
-
1.
|
|
597
|
-
2.
|
|
598
|
-
3.
|
|
599
|
-
4.
|
|
605
|
+
1. Test locally with Test API Key (development mode)
|
|
606
|
+
2. In dashboard: **Publish → Publish for Testing**
|
|
607
|
+
3. Build production app
|
|
608
|
+
4. Submit to App Store / Google Play
|
|
609
|
+
5. **WAIT for approval**
|
|
610
|
+
6. **After app is live:** In dashboard, **Publish → Publish to Production**
|
|
611
|
+
|
|
612
|
+
**Note:** Test and Production environments are separate. You can safely test changes using the Test API Key before rolling them out to production users with the Production API Key.
|
|
600
613
|
|
|
601
614
|
---
|
|
602
615
|
|
|
@@ -831,7 +844,10 @@ const styles = StyleSheet.create({
|
|
|
831
844
|
|
|
832
845
|
```typescript
|
|
833
846
|
<OnboardingFlow
|
|
834
|
-
|
|
847
|
+
// Dual API keys - SDK auto-detects environment
|
|
848
|
+
testKey="nb_test_..."
|
|
849
|
+
productionKey="nb_live_..."
|
|
850
|
+
|
|
835
851
|
customComponents={{
|
|
836
852
|
Step1EmailScreen,
|
|
837
853
|
Step2GoalsScreen,
|
package/README.md
CHANGED
|
@@ -513,6 +513,8 @@ import { API, AnalyticsManager } from 'noboarding';
|
|
|
513
513
|
|
|
514
514
|
## Development
|
|
515
515
|
|
|
516
|
+
### Building the SDK
|
|
517
|
+
|
|
516
518
|
The TestApp imports the SDK from the compiled `lib/` directory (`"main": "lib/index.js"`), not from `src/` directly. After making any changes to files in `sdk/src/`, you must rebuild before testing:
|
|
517
519
|
|
|
518
520
|
```bash
|
|
@@ -522,6 +524,63 @@ npm run build
|
|
|
522
524
|
|
|
523
525
|
Then restart the TestApp. If you skip this step, the TestApp will still be running the old compiled code and your changes won't take effect.
|
|
524
526
|
|
|
527
|
+
### Dashboard Preview Integration
|
|
528
|
+
|
|
529
|
+
The dashboard uses **local copies** of SDK source files for the preview feature. When you modify SDK source files, they need to be synced to the dashboard.
|
|
530
|
+
|
|
531
|
+
**Why copies?** Next.js/Turbopack doesn't support importing from external directories with the react-native-web setup, so the dashboard maintains local copies in `dashboard/lib/sdk/`.
|
|
532
|
+
|
|
533
|
+
#### Files That Need Syncing
|
|
534
|
+
|
|
535
|
+
When you modify these SDK files:
|
|
536
|
+
- `src/types.ts` → Auto-synced to `dashboard/lib/sdk/types.ts`
|
|
537
|
+
- `src/variableUtils.ts` → Auto-synced to `dashboard/lib/sdk/variableUtils.ts`
|
|
538
|
+
- `src/components/ElementRenderer.tsx` → ⚠️ **NOT auto-synced** (dashboard has web-specific modifications)
|
|
539
|
+
|
|
540
|
+
**ElementRenderer Special Case:**
|
|
541
|
+
|
|
542
|
+
The dashboard copy of `ElementRenderer.tsx` has web-specific modifications for icon support:
|
|
543
|
+
- Uses `react-icons` instead of `@expo/vector-icons`
|
|
544
|
+
- Renders real icons in preview (Feather, Material, Ionicons, FontAwesome)
|
|
545
|
+
- Gradients fall back to solid colors
|
|
546
|
+
|
|
547
|
+
**If you modify ElementRenderer.tsx significantly:**
|
|
548
|
+
1. Run `npm run sync:full` from project root to copy it
|
|
549
|
+
2. Manually re-add web icon imports and logic (check git diff to see what changed)
|
|
550
|
+
|
|
551
|
+
#### Syncing Methods
|
|
552
|
+
|
|
553
|
+
**Manual sync (run when needed):**
|
|
554
|
+
```bash
|
|
555
|
+
# From project root
|
|
556
|
+
npm run sync
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
**Auto-sync during development:**
|
|
560
|
+
```bash
|
|
561
|
+
# From project root
|
|
562
|
+
npm run sync:watch
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
This watches SDK files and automatically copies changes to the dashboard when you save.
|
|
566
|
+
|
|
567
|
+
**Full development mode:**
|
|
568
|
+
```bash
|
|
569
|
+
# From project root - starts dashboard + auto-sync
|
|
570
|
+
npm run dev
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
This command:
|
|
574
|
+
1. Syncs SDK files to dashboard
|
|
575
|
+
2. Starts file watcher for auto-sync
|
|
576
|
+
3. Starts dashboard dev server
|
|
577
|
+
|
|
578
|
+
#### Important Notes
|
|
579
|
+
|
|
580
|
+
- ⚠️ **Dashboard preview uses copies** - Changes to SDK files won't appear in dashboard preview until synced
|
|
581
|
+
- ✅ **Mobile app uses npm package** - TestApp uses the built SDK from `lib/`, requires `npm run build`
|
|
582
|
+
- 🔄 **Keep in sync** - Run `npm run sync:watch` while developing SDK to keep dashboard preview accurate
|
|
583
|
+
|
|
525
584
|
## Requirements
|
|
526
585
|
|
|
527
586
|
- React Native >= 0.60.0
|
package/lib/OnboardingFlow.js
CHANGED
|
@@ -110,7 +110,10 @@ const OnboardingFlow = ({ apiKey, testKey, productionKey, onComplete, onSkip, ba
|
|
|
110
110
|
// Fetch configuration
|
|
111
111
|
const configResponse = await api.getConfig();
|
|
112
112
|
// Backward compatibility: normalize legacy 'custom_screen' (with elements) to 'noboard_screen'
|
|
113
|
-
const normalizedScreens = configResponse.config.screens
|
|
113
|
+
const normalizedScreens = configResponse.config.screens
|
|
114
|
+
.map(s => (Object.assign(Object.assign({}, s), { type: (s.type === 'custom_screen' && s.elements) ? 'noboard_screen' : s.type })))
|
|
115
|
+
// Filter out hidden screens (dashboard show/hide feature)
|
|
116
|
+
.filter(s => !s.hidden);
|
|
114
117
|
setScreens(normalizedScreens);
|
|
115
118
|
setLoading(false);
|
|
116
119
|
}
|
|
@@ -204,7 +204,14 @@ const RenderNode = ({ element, toggledIds, groupSelections, onAction, variables
|
|
|
204
204
|
const wrapWithAction = (content) => {
|
|
205
205
|
if (!hasAction)
|
|
206
206
|
return content;
|
|
207
|
-
|
|
207
|
+
// Extract width/alignment styles that should apply to TouchableOpacity wrapper
|
|
208
|
+
// This ensures buttons with width: "100%" don't shrink to content
|
|
209
|
+
const wrapperStyle = {};
|
|
210
|
+
if (style.width)
|
|
211
|
+
wrapperStyle.width = style.width;
|
|
212
|
+
if (style.alignSelf)
|
|
213
|
+
wrapperStyle.alignSelf = style.alignSelf;
|
|
214
|
+
return (<react_native_1.TouchableOpacity key={element.id} activeOpacity={0.7} onPress={() => onAction(element)} style={wrapperStyle}>
|
|
208
215
|
{content}
|
|
209
216
|
</react_native_1.TouchableOpacity>);
|
|
210
217
|
};
|
package/lib/types.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export interface ScreenConfig {
|
|
|
6
6
|
props: Record<string, any>;
|
|
7
7
|
elements?: ElementNode[];
|
|
8
8
|
custom_component_name?: string;
|
|
9
|
+
hidden?: boolean;
|
|
9
10
|
}
|
|
10
11
|
export type ElementType = 'vstack' | 'hstack' | 'zstack' | 'scrollview' | 'text' | 'image' | 'video' | 'lottie' | 'icon' | 'input' | 'spacer' | 'divider';
|
|
11
12
|
export interface ElementNode {
|
package/package.json
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "noboarding",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "1.0.1-beta",
|
|
4
4
|
"description": "React Native SDK for remote onboarding flow management",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./lib/index.d.ts",
|
|
10
|
+
"default": "./lib/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./src/*": "./src/*"
|
|
13
|
+
},
|
|
7
14
|
"scripts": {
|
|
8
15
|
"build": "tsc",
|
|
9
|
-
"watch": "tsc --watch"
|
|
10
|
-
"prepare": "npm run build"
|
|
16
|
+
"watch": "tsc --watch"
|
|
11
17
|
},
|
|
12
18
|
"keywords": [
|
|
13
19
|
"react-native",
|
package/src/OnboardingFlow.tsx
CHANGED
|
@@ -102,10 +102,13 @@ export const OnboardingFlow: React.FC<OnboardingFlowProps> = ({
|
|
|
102
102
|
// Fetch configuration
|
|
103
103
|
const configResponse = await api.getConfig();
|
|
104
104
|
// Backward compatibility: normalize legacy 'custom_screen' (with elements) to 'noboard_screen'
|
|
105
|
-
const normalizedScreens = configResponse.config.screens
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
const normalizedScreens = configResponse.config.screens
|
|
106
|
+
.map(s => ({
|
|
107
|
+
...s,
|
|
108
|
+
type: (s.type === ('custom_screen' as any) && s.elements) ? 'noboard_screen' as ScreenConfig['type'] : s.type,
|
|
109
|
+
}))
|
|
110
|
+
// Filter out hidden screens (dashboard show/hide feature)
|
|
111
|
+
.filter(s => !s.hidden);
|
|
109
112
|
setScreens(normalizedScreens);
|
|
110
113
|
|
|
111
114
|
setLoading(false);
|
|
@@ -216,11 +216,19 @@ const RenderNode: React.FC<RenderNodeProps> = ({ element, toggledIds, groupSelec
|
|
|
216
216
|
const hasAction = !!element.action || (element.actions && element.actions.length > 0);
|
|
217
217
|
const wrapWithAction = (content: React.ReactElement): React.ReactElement => {
|
|
218
218
|
if (!hasAction) return content;
|
|
219
|
+
|
|
220
|
+
// Extract width/alignment styles that should apply to TouchableOpacity wrapper
|
|
221
|
+
// This ensures buttons with width: "100%" don't shrink to content
|
|
222
|
+
const wrapperStyle: any = {};
|
|
223
|
+
if (style.width) wrapperStyle.width = style.width;
|
|
224
|
+
if (style.alignSelf) wrapperStyle.alignSelf = style.alignSelf;
|
|
225
|
+
|
|
219
226
|
return (
|
|
220
227
|
<TouchableOpacity
|
|
221
228
|
key={element.id}
|
|
222
229
|
activeOpacity={0.7}
|
|
223
230
|
onPress={() => onAction(element)}
|
|
231
|
+
style={wrapperStyle}
|
|
224
232
|
>
|
|
225
233
|
{content}
|
|
226
234
|
</TouchableOpacity>
|
package/src/types.ts
CHANGED
|
@@ -12,6 +12,8 @@ export interface ScreenConfig {
|
|
|
12
12
|
elements?: ElementNode[];
|
|
13
13
|
// For custom_screen type — name of the developer-registered component
|
|
14
14
|
custom_component_name?: string;
|
|
15
|
+
// Dashboard visibility control — if true, screen is hidden from onboarding flow
|
|
16
|
+
hidden?: boolean;
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
// ─── Element Tree Types (matches dashboard primitives) ───
|