@scribeup/react-native-scribeup 0.3.1 → 0.4.0

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 CHANGED
@@ -11,11 +11,14 @@ The package is a thin wrapper around the native [iOS](https://github.com/ScribeU
11
11
  1. [Bare React-Native](#bare-react-native)
12
12
  2. [Expo Projects](#expo-projects)
13
13
  2. [Quick Start](#quick-start)
14
- 3. [API Reference](#api-reference)
15
- 4. [Example Projects](#example-projects)
16
- 5. [Troubleshooting](#troubleshooting)
17
- 6. [Author](#author)
18
- 7. [License](#license)
14
+ 3. [Components](#components)
15
+ 1. [ScribeUp (Full Screen)](#scribeup-full-screen)
16
+ 2. [ScribeUpWidget (Embeddable)](#scribeupwidget-embeddable)
17
+ 4. [API Reference](#api-reference)
18
+ 5. [Example Projects](#example-projects)
19
+ 6. [Troubleshooting](#troubleshooting)
20
+ 7. [Author](#author)
21
+ 8. [License](#license)
19
22
 
20
23
 
21
24
  ## Installation
@@ -81,9 +84,51 @@ export default function App() {
81
84
 
82
85
  ---
83
86
 
87
+ ## Components
88
+
89
+ The SDK provides two components for different integration scenarios:
90
+
91
+ ### ScribeUp (Full Screen)
92
+
93
+ The main component that presents a full-screen modal subscription manager.
94
+
95
+ ### ScribeUpWidget (Embeddable)
96
+
97
+ A lightweight widget view that can be embedded anywhere in your app and sized however you want.
98
+
99
+ ```tsx
100
+ import { ScribeUpWidget, ScribeupWidgetViewRef } from "@scribeup/react-native-scribeup";
101
+
102
+ export default function MyComponent() {
103
+ const widgetRef = useRef<ScribeupWidgetViewRef>(null);
104
+
105
+ const handleReload = () => {
106
+ widgetRef.current?.reload();
107
+ };
108
+
109
+
110
+ return (
111
+ <ScribeUpWidget
112
+ ref={widgetRef}
113
+ url="https://your-subscription-url.com"
114
+ style={{ width: '100%', height: 400 }}
115
+ />
116
+ );
117
+ }
118
+ ```
119
+
120
+ **Key differences from the full-screen component:**
121
+ - Takes only one required parameter: `url`
122
+ - Has no header or navigation controls
123
+ - Can be sized and positioned flexibly
124
+ - Focused purely on displaying web content
125
+ - Provides imperative methods via ref (`reload()`, `loadURL()`)
126
+
127
+ ---
128
+
84
129
  ## API Reference
85
130
 
86
- ScribeUp is a *React component*. Mounting it immediately presents the native subscription-manager UI.
131
+ ### ScribeUp (Full Screen)
87
132
 
88
133
  ```
89
134
  <ScribeUp
@@ -93,6 +138,20 @@ ScribeUp is a *React component*. Mounting it immediately presents the native sub
93
138
  />
94
139
  ```
95
140
 
141
+ ### ScribeUpWidget (Embeddable)
142
+
143
+ ```
144
+ <ScribeUpWidget
145
+ url: string; // required – authenticated manage-subscriptions URL
146
+ style?: ViewStyle; // optional – styling for the widget container
147
+ ref?: ScribeupWidgetViewRef; // optional – ref for imperative methods
148
+ />
149
+ ```
150
+
151
+ **Ref methods:**
152
+ - `reload()` – reloads the current page
153
+ - `loadURL(url: string)` – loads a new URL
154
+
96
155
  ### Exit Callback
97
156
 
98
157
  `onExit` receives an object with two optional fields:
@@ -11,6 +11,6 @@ class RNScribeupSDKPackage : ReactPackage {
11
11
  }
12
12
 
13
13
  override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
14
- return emptyList()
14
+ return listOf(ScribeupWidgetViewManager(reactContext))
15
15
  }
16
16
  }
@@ -0,0 +1,83 @@
1
+ package com.rnscribeupsdk
2
+
3
+ import android.view.View
4
+ import com.facebook.react.bridge.ReactApplicationContext
5
+ import com.facebook.react.bridge.ReadableArray
6
+ import com.facebook.react.common.MapBuilder
7
+ import com.facebook.react.uimanager.SimpleViewManager
8
+ import com.facebook.react.uimanager.ThemedReactContext
9
+ import com.facebook.react.uimanager.annotations.ReactProp
10
+ import io.scribeup.scribeupsdk.ui.SubscriptionManagerWidgetView
11
+
12
+ class ScribeupWidgetViewManager(private val reactContext: ReactApplicationContext) : SimpleViewManager<SubscriptionManagerWidgetView>() {
13
+
14
+ companion object {
15
+ const val REACT_CLASS = "ScribeupWidgetView"
16
+ const val COMMAND_RELOAD = 1
17
+ const val COMMAND_LOAD_URL = 2
18
+ }
19
+
20
+ override fun getName(): String {
21
+ return REACT_CLASS
22
+ }
23
+
24
+ override fun createViewInstance(reactContext: ThemedReactContext): SubscriptionManagerWidgetView {
25
+ return SubscriptionManagerWidgetView(reactContext)
26
+ }
27
+
28
+ @ReactProp(name = "url")
29
+ fun setUrl(view: SubscriptionManagerWidgetView, url: String?) {
30
+ if (!url.isNullOrEmpty()) {
31
+ view.loadURL(url)
32
+ }
33
+ }
34
+
35
+ override fun getCommandsMap(): Map<String, Int>? {
36
+ return MapBuilder.of(
37
+ "reload", COMMAND_RELOAD,
38
+ "loadURL", COMMAND_LOAD_URL
39
+ )
40
+ }
41
+
42
+ override fun receiveCommand(
43
+ root: SubscriptionManagerWidgetView,
44
+ commandId: String?,
45
+ args: ReadableArray?
46
+ ) {
47
+ super.receiveCommand(root, commandId, args)
48
+
49
+ when (commandId?.toIntOrNull()) {
50
+ COMMAND_RELOAD -> {
51
+ root.reload()
52
+ }
53
+ COMMAND_LOAD_URL -> {
54
+ if (args != null && args.size() > 0) {
55
+ val url = args.getString(0)
56
+ if (!url.isNullOrEmpty()) {
57
+ root.loadURL(url)
58
+ }
59
+ }
60
+ }
61
+ }
62
+ }
63
+
64
+ override fun receiveCommand(
65
+ root: SubscriptionManagerWidgetView,
66
+ commandId: Int,
67
+ args: ReadableArray?
68
+ ) {
69
+ when (commandId) {
70
+ COMMAND_RELOAD -> {
71
+ root.reload()
72
+ }
73
+ COMMAND_LOAD_URL -> {
74
+ if (args != null && args.size() > 0) {
75
+ val url = args.getString(0)
76
+ if (!url.isNullOrEmpty()) {
77
+ root.loadURL(url)
78
+ }
79
+ }
80
+ }
81
+ }
82
+ }
83
+ }
package/ios/Scribeup.m CHANGED
@@ -1,5 +1,6 @@
1
1
  #import <React/RCTBridgeModule.h>
2
2
  #import <React/RCTEventEmitter.h>
3
+ #import <React/RCTViewManager.h>
3
4
 
4
5
  @interface RCT_EXTERN_MODULE(Scribeup, RCTEventEmitter)
5
6
 
@@ -9,3 +10,11 @@ RCT_EXTERN_METHOD(presentWithUrl:(NSString *)url
9
10
  rejecter:(RCTPromiseRejectBlock)reject)
10
11
 
11
12
  @end
13
+
14
+ @interface RCT_EXTERN_MODULE(ScribeupWidgetViewManager, RCTViewManager)
15
+
16
+ RCT_EXPORT_VIEW_PROPERTY(url, NSString)
17
+ RCT_EXTERN_METHOD(reload:(nonnull NSNumber *)reactTag)
18
+ RCT_EXTERN_METHOD(loadURL:(nonnull NSNumber *)reactTag url:(NSString *)url)
19
+
20
+ @end
@@ -0,0 +1,95 @@
1
+ import Foundation
2
+ import ScribeUpSDK
3
+ import React
4
+
5
+ @objc(ScribeupWidgetViewManager)
6
+ class ScribeupWidgetViewManager: RCTViewManager {
7
+
8
+ override func view() -> UIView! {
9
+ return ScribeupWidgetView()
10
+ }
11
+
12
+ @objc override static func requiresMainQueueSetup() -> Bool {
13
+ return true
14
+ }
15
+
16
+ @objc func reload(_ reactTag: NSNumber) {
17
+ DispatchQueue.main.async {
18
+ self.bridge.uiManager.addUIBlock { (uiManager, viewRegistry) in
19
+ if let view = viewRegistry?[reactTag] as? ScribeupWidgetView {
20
+ view.reload()
21
+ }
22
+ }
23
+ }
24
+ }
25
+
26
+ @objc func loadURL(_ reactTag: NSNumber, url: String) {
27
+ DispatchQueue.main.async {
28
+ self.bridge.uiManager.addUIBlock { (uiManager, viewRegistry) in
29
+ if let view = viewRegistry?[reactTag] as? ScribeupWidgetView {
30
+ view.loadURL(url)
31
+ }
32
+ }
33
+ }
34
+ }
35
+ }
36
+
37
+ class ScribeupWidgetView: UIView {
38
+
39
+ private var widgetView: SubscriptionManagerWidgetView?
40
+ private var _url: String = ""
41
+
42
+ @objc var url: String = "" {
43
+ didSet {
44
+ _url = url
45
+ updateWidgetView()
46
+ }
47
+ }
48
+
49
+ override init(frame: CGRect) {
50
+ super.init(frame: frame)
51
+ setupView()
52
+ }
53
+
54
+ required init?(coder: NSCoder) {
55
+ super.init(coder: coder)
56
+ setupView()
57
+ }
58
+
59
+ private func setupView() {
60
+ backgroundColor = UIColor.clear
61
+ }
62
+
63
+ private func updateWidgetView() {
64
+ // Remove existing widget view if any
65
+ widgetView?.removeFromSuperview()
66
+ widgetView = nil
67
+
68
+ // Create new widget view if URL is provided
69
+ if !_url.isEmpty {
70
+ widgetView = SubscriptionManagerWidgetView(url: _url)
71
+
72
+ if let widgetView = widgetView {
73
+ addSubview(widgetView)
74
+ widgetView.translatesAutoresizingMaskIntoConstraints = false
75
+
76
+ NSLayoutConstraint.activate([
77
+ widgetView.topAnchor.constraint(equalTo: topAnchor),
78
+ widgetView.bottomAnchor.constraint(equalTo: bottomAnchor),
79
+ widgetView.leadingAnchor.constraint(equalTo: leadingAnchor),
80
+ widgetView.trailingAnchor.constraint(equalTo: trailingAnchor)
81
+ ])
82
+ }
83
+ }
84
+ }
85
+
86
+ // MARK: - Public Methods for React Native
87
+
88
+ @objc func reload() {
89
+ widgetView?.reload()
90
+ }
91
+
92
+ @objc func loadURL(_ urlString: String) {
93
+ widgetView?.loadURL(urlString)
94
+ }
95
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scribeup/react-native-scribeup",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -52,8 +52,8 @@
52
52
  },
53
53
  "config": {
54
54
  "nativeSDKVersions": {
55
- "android": "0.7.1",
56
- "ios": "0.7.7"
55
+ "android": "0.8.0",
56
+ "ios": "0.8.0"
57
57
  }
58
58
  }
59
59
  }
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+ import { ViewStyle } from 'react-native';
3
+
4
+ export interface ScribeupWidgetViewProps {
5
+ /**
6
+ * The URL to load in the widget
7
+ */
8
+ url: string;
9
+
10
+ /**
11
+ * Optional style for the widget container
12
+ */
13
+ style?: ViewStyle;
14
+ }
15
+
16
+ export interface ScribeupWidgetViewRef {
17
+ /**
18
+ * Reload the current page in the widget
19
+ */
20
+ reload: () => void;
21
+
22
+ /**
23
+ * Load a new URL in the widget
24
+ * @param url The new URL to load
25
+ */
26
+ loadURL: (url: string) => void;
27
+ }
28
+
29
+ /**
30
+ * ScribeUp Widget Component
31
+ *
32
+ * A lightweight widget view that displays a webview for subscription management.
33
+ * This is a flexible alternative to the full-screen ScribeUp component that can be
34
+ * embedded anywhere in your app and sized however you want.
35
+ *
36
+ * Unlike the full ScribeUp component, this widget:
37
+ * - Takes only one required parameter: url
38
+ * - Has no header or navigation controls
39
+ * - Is a simple View that can be sized flexibly
40
+ * - Is focused purely on displaying web content
41
+ */
42
+ declare const ScribeUpWidget: React.ForwardRefExoticComponent<
43
+ ScribeupWidgetViewProps & React.RefAttributes<ScribeupWidgetViewRef>
44
+ >;
45
+
46
+ export default ScribeUpWidget;
@@ -0,0 +1,121 @@
1
+ import React, { useRef, useImperativeHandle, forwardRef } from 'react';
2
+ import { ViewStyle, UIManager, findNodeHandle, Platform } from 'react-native';
3
+ import { requireNativeComponent } from 'react-native';
4
+
5
+ const LINKING_ERROR =
6
+ `The package 'scribeup-react-native-scribeup' doesn't seem to be linked. Make sure: \n\n` +
7
+ Platform.select({
8
+ ios: "- You have run 'pod install'\n",
9
+ default: "",
10
+ }) +
11
+ "- You rebuilt the app after installing the package\n";
12
+
13
+ const ComponentName = 'ScribeupWidgetView';
14
+
15
+ const ScribeupWidgetViewNative =
16
+ UIManager.getViewManagerConfig(ComponentName) != null
17
+ ? requireNativeComponent<ScribeupWidgetViewProps>(ComponentName)
18
+ : () => {
19
+ throw new Error(LINKING_ERROR);
20
+ };
21
+
22
+ export interface ScribeupWidgetViewProps {
23
+ /**
24
+ * The URL to load in the widget
25
+ */
26
+ url: string;
27
+
28
+ /**
29
+ * Optional style for the widget container
30
+ */
31
+ style?: ViewStyle;
32
+ }
33
+
34
+ export interface ScribeupWidgetViewRef {
35
+ /**
36
+ * Reload the current page in the widget
37
+ */
38
+ reload: () => void;
39
+
40
+ /**
41
+ * Load a new URL in the widget
42
+ * @param url The new URL to load
43
+ */
44
+ loadURL: (url: string) => void;
45
+ }
46
+
47
+ /**
48
+ * ScribeUp Widget Component
49
+ *
50
+ * A lightweight widget view that displays a webview for subscription management.
51
+ * This is a flexible alternative to the full-screen ScribeUp component that can be
52
+ * embedded anywhere in your app and sized however you want.
53
+ *
54
+ * Unlike the full ScribeUp component, this widget:
55
+ * - Takes only one required parameter: url
56
+ * - Has no header or navigation controls
57
+ * - Is a simple View that can be sized flexibly
58
+ * - Is focused purely on displaying web content
59
+ *
60
+ * @example
61
+ * ```tsx
62
+ * import { ScribeUpWidget } from 'scribeup-react-native-scribeup';
63
+ *
64
+ * const MyComponent = () => {
65
+ * const widgetRef = useRef<ScribeupWidgetViewRef>(null);
66
+ *
67
+ * const handleReload = () => {
68
+ * widgetRef.current?.reload();
69
+ * };
70
+ *
71
+ *
72
+ * return (
73
+ * <ScribeUpWidget
74
+ * ref={widgetRef}
75
+ * url="https://your-subscription-url.com"
76
+ * style={{ width: '100%', height: 400 }}
77
+ * />
78
+ * );
79
+ * };
80
+ * ```
81
+ */
82
+ const ScribeUpWidget = forwardRef<ScribeupWidgetViewRef, ScribeupWidgetViewProps>(
83
+ ({ url, style }, ref) => {
84
+ const nativeRef = useRef(null);
85
+
86
+ useImperativeHandle(ref, () => ({
87
+ reload: () => {
88
+ const viewId = findNodeHandle(nativeRef.current);
89
+ if (viewId) {
90
+ if (Platform.OS === 'ios') {
91
+ UIManager.dispatchViewManagerCommand(viewId, 'reload', []);
92
+ } else {
93
+ UIManager.dispatchViewManagerCommand(viewId, UIManager.getViewManagerConfig(ComponentName).Commands.reload, []);
94
+ }
95
+ }
96
+ },
97
+ loadURL: (newUrl: string) => {
98
+ const viewId = findNodeHandle(nativeRef.current);
99
+ if (viewId) {
100
+ if (Platform.OS === 'ios') {
101
+ UIManager.dispatchViewManagerCommand(viewId, 'loadURL', [newUrl]);
102
+ } else {
103
+ UIManager.dispatchViewManagerCommand(viewId, UIManager.getViewManagerConfig(ComponentName).Commands.loadURL, [newUrl]);
104
+ }
105
+ }
106
+ },
107
+ }));
108
+
109
+ return (
110
+ <ScribeupWidgetViewNative
111
+ ref={nativeRef}
112
+ url={url}
113
+ style={style}
114
+ />
115
+ );
116
+ }
117
+ );
118
+
119
+ ScribeUpWidget.displayName = 'ScribeUpWidget';
120
+
121
+ export default ScribeUpWidget;
package/src/index.d.ts CHANGED
@@ -1,2 +1,5 @@
1
1
  import ScribeUp from "./ScribeUp";
2
+ import ScribeUpWidget from "./ScribeUpWidget";
3
+
4
+ export { ScribeUpWidget };
2
5
  export default ScribeUp;
package/src/index.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  import ScribeUp from "./ScribeUp";
2
+ import ScribeUpWidget from "./ScribeUpWidget";
2
3
 
4
+ export { ScribeUpWidget };
3
5
  export default ScribeUp;