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.
@@ -237,7 +237,11 @@ export const SummaryScreen: React.FC<CustomScreenProps> = ({
237
237
 
238
238
  ```typescript
239
239
  <OnboardingFlow
240
- apiKey="sk_live_..."
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
- apiKey="sk_live_your_api_key"
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. Build production app
597
- 2. Submit to App Store / Google Play
598
- 3. **WAIT for approval**
599
- 4. **After app is live:** Publish flow in dashboard
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
- apiKey="sk_live_..."
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
@@ -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.map(s => (Object.assign(Object.assign({}, s), { type: (s.type === 'custom_screen' && s.elements) ? 'noboard_screen' : s.type })));
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
- return (<react_native_1.TouchableOpacity key={element.id} activeOpacity={0.7} onPress={() => onAction(element)}>
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.0-beta",
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",
@@ -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.map(s => ({
106
- ...s,
107
- type: (s.type === ('custom_screen' as any) && s.elements) ? 'noboard_screen' as ScreenConfig['type'] : s.type,
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) ───