@superwall/paywalls-react 0.1.5 → 0.2.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.
@@ -1,46 +1,11 @@
1
1
  $ tsc --noEmit
2
- ../paywalls-js/src/internal/audience.ts(32,3): error TS2322: Type 'Promise<typeof import("/Users/ianrumac/Workspace/Superwall/Superwall-Web/node_modules/.bun/@superwall+superscript@0.2.5/node_modules/@superwall/superscript/dist/types/browser")>' is not assignable to type 'Promise<{ evaluateWithContext: (input: ExecutionContext, host: SuperscriptHostContext) => string | boolean; }>'.
3
- Type 'typeof import("/Users/ianrumac/Workspace/Superwall/Superwall-Web/node_modules/.bun/@superwall+superscript@0.2.5/node_modules/@superwall/superscript/dist/types/browser")' is not assignable to type '{ evaluateWithContext: (input: ExecutionContext, host: SuperscriptHostContext) => string | boolean; }'.
4
- The types returned by 'evaluateWithContext(...)' are incompatible between these types.
5
- Type 'Promise<string>' is not assignable to type 'string | boolean'.
6
- ../paywalls-js/src/internal/audience.ts(232,18): error TS18047: 'mod' is possibly 'null'.
7
- ../paywalls-js/src/internal/redemption.ts(133,21): error TS2379: Argument of type '{ deviceId: string; appUserId: string | undefined; aliasId: string; codes: { code: string; firstRedemption?: boolean; }[]; }' is not assignable to parameter of type 'RedeemRequest' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
8
- Types of property 'appUserId' are incompatible.
9
- Type 'string | undefined' is not assignable to type 'string'.
10
- Type 'undefined' is not assignable to type 'string'.
11
- ../paywalls-js/src/superwall.ts(947,7): error TS2379: Argument of type 'Effect<void, StorageSetError, StorageService>' is not assignable to parameter of type 'Effect<unknown, unknown, never>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
12
- Type 'StorageService' is not assignable to type 'never'.
13
- ../paywalls-js/src/superwall.ts(1046,38): error TS2551: Property 'activeSubscriptions' does not exist on type 'CustomerInfo'. Did you mean 'subscriptions'?
14
- ../paywalls-js/src/superwall.ts(1050,11): error TS2375: Type '{ publicApiKey: string; aliasId: string; appUserId: string; vendorId: string; deviceId: string; bundleId: string | undefined; appVersion: string | undefined; isSandbox: boolean; isFirstAppOpen: boolean; ... 6 more ...; activeProducts: any; }' is not assignable to type 'DeviceAttributesInput' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
15
- Types of property 'bundleId' are incompatible.
16
- Type 'string | undefined' is not assignable to type 'string'.
17
- Type 'undefined' is not assignable to type 'string'.
18
- ../paywalls-js/src/superwall.ts(1208,9): error TS2379: Argument of type 'Effect<void, never, EventBus>' is not assignable to parameter of type 'Effect<unknown, unknown, never>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
19
- Type 'EventBus' is not assignable to type 'never'.
20
- ../paywalls-js/src/superwall.ts(1608,15): error TS2379: Argument of type 'Effect<void, never, EventBus>' is not assignable to parameter of type 'Effect<unknown, unknown, never>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
21
- Type 'EventBus' is not assignable to type 'never'.
22
- ../paywalls-js/src/superwall.ts(1722,17): error TS2379: Argument of type 'Effect<void, never, EventBus>' is not assignable to parameter of type 'Effect<unknown, unknown, never>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
23
- Type 'EventBus' is not assignable to type 'never'.
24
- ../paywalls-js/src/superwall.ts(1737,17): error TS2379: Argument of type 'Effect<void, never, EventBus>' is not assignable to parameter of type 'Effect<unknown, unknown, never>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
25
- Type 'EventBus' is not assignable to type 'never'.
26
- ../paywalls-js/src/superwall.ts(1949,11): error TS2379: Argument of type 'Effect<void, never, EventBus>' is not assignable to parameter of type 'Effect<unknown, unknown, never>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
27
- Type 'EventBus' is not assignable to type 'never'.
28
- ../paywalls-js/src/superwall.ts(1969,13): error TS2379: Argument of type 'Effect<void, never, EventBus>' is not assignable to parameter of type 'Effect<unknown, unknown, never>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
29
- Type 'EventBus' is not assignable to type 'never'.
30
- ../paywalls-js/src/superwall.ts(2050,11): error TS2379: Argument of type 'Effect<void, never, EventBus>' is not assignable to parameter of type 'Effect<unknown, unknown, never>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
31
- Type 'EventBus' is not assignable to type 'never'.
32
- ../paywalls-js/src/superwall.ts(2112,9): error TS2379: Argument of type 'Effect<void, never, EventBus>' is not assignable to parameter of type 'Effect<unknown, unknown, never>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
33
- Type 'EventBus' is not assignable to type 'never'.
34
- ../paywalls-js/src/superwall.ts(2303,9): error TS2379: Argument of type 'Effect<void, never, Logger>' is not assignable to parameter of type 'Effect<unknown, unknown, never>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
35
- Type 'Logger' is not assignable to type 'never'.
36
- ../paywalls-js/src/superwall.ts(2317,9): error TS2379: Argument of type 'Effect<void, never, EventBus>' is not assignable to parameter of type 'Effect<unknown, unknown, never>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
37
- Type 'EventBus' is not assignable to type 'never'.
38
- ../paywalls-js/src/superwall.ts(2392,9): error TS2352: Conversion of type 'Effect<void, never, NetworkService | ConfigService | AssignmentService>' to type 'Effect<void, unknown, never>' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
39
- Type 'NetworkService | ConfigService | AssignmentService' is not comparable to type 'never'.
40
- Type 'AssignmentService' is not comparable to type 'never'.
41
2
  src/hooks.test.tsx(417,26): error TS2345: Argument of type '{ readonly value: string; subscribe: (run: () => void) => () => void; }' is not assignable to parameter of type 'Readable<string>'.
42
3
  Types of property 'subscribe' are incompatible.
43
4
  Type '(run: () => void) => () => void' is not assignable to type '(run: (value: string) => void) => () => void'.
44
5
  Types of parameters 'run' and 'run' are incompatible.
45
6
  Target signature provides too few arguments. Expected 1 or more, but got 0.
46
7
  src/hooks.ts(185,11): error TS2367: This comparison appears to be unintentional because the types '"error" | "presented" | "skipped"' and '"entitled"' have no overlap.
8
+ src/SuperwallPaywall.tsx(42,17): error TS2379: Argument of type '{ placement: string; params: PlacementParams | undefined; feature: () => void; handler: { onPresent: (info: PaywallInfo) => void | undefined; onDismiss: (info: PaywallInfo, result: PaywallResult) => void | undefined; onSkip: (reason: PaywallSkippedReason) => void | undefined; onError: (error: Error) => void | undefi...' is not assignable to parameter of type 'RegisterPlacementArgs' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
9
+ Types of property 'params' are incompatible.
10
+ Type 'PlacementParams | undefined' is not assignable to type 'PlacementParams'.
11
+ Type 'undefined' is not assignable to type 'PlacementParams'.
package/README.md CHANGED
@@ -23,9 +23,29 @@ export function Root() {
23
23
  }
24
24
  ```
25
25
 
26
- `SuperwallProvider` takes the same config as `createSuperwall`
27
- (`apiKey`, `storage`, `delegate`, `identity`, `options`).
26
+ `SuperwallProvider` accepts the following props:
28
27
 
28
+ | Prop | Type | Description | Example |
29
+ |-----------|---------------------|------------------------------------------------------------------------------------------------------|---------------------------------------------|
30
+ | `apiKey` | `string` | **Required.** Your Superwall public key. | `"pk_your_public_key"` |
31
+ | `storage` | `StorageAdapter?` | Optional. Provide a storage layer to customize persistence behavior (defaults to localStorage). | `myCustomStorage` |
32
+ | `delegate`| `SuperwallDelegate?`| Optional. Receives paywall and subscription events (like callbacks for onPresent, onDismiss, etc). | `myDelegate` |
33
+ | `identity`| `{ appUserId?, aliasId?, vendorId? }?` | Optional. Seed identity on configure, e.g. from cookies on SSR hydration. | `{ appUserId: 'abc123' }` |
34
+ | `options` | `object?` | Optional. Additional options for advanced configuration (see the paywalls-js docs for details). | `{ networkEnvironment: "release" }` |
35
+
36
+ Most apps will only need to provide `apiKey`, but you can pass the optional extras as needed.
37
+
38
+ ```tsx
39
+ <SuperwallProvider
40
+ apiKey="pk_your_public_key"
41
+ storage={myCustomStorage}
42
+ delegate={myDelegate}
43
+ identity={{ appUserId: "123" }}
44
+ options={{ networkEnvironment: "release" }}
45
+ >
46
+ <App />
47
+ </SuperwallProvider>
48
+ ```
29
49
  ## Placements
30
50
 
31
51
  ```tsx
@@ -76,6 +96,25 @@ function GoPro() {
76
96
  - The placement has no audience match / holdout — feature runs without showing a paywall
77
97
  - The user completes a purchase or restore through the paywall
78
98
 
99
+ ## SuperwallPaywall component
100
+
101
+ Declarative alternative to `usePlacement`. Calls `register()` on mount and
102
+ renders `children` when the user is entitled — i.e. the feature block fires.
103
+
104
+ ```tsx
105
+ import { SuperwallPaywall } from "@superwall/paywalls-react";
106
+
107
+ function App() {
108
+ return (
109
+ <SuperwallPaywall placement="campaign_trigger" loading={<LoadingSpinner />}>
110
+ <ProContent />
111
+ </SuperwallPaywall>
112
+ );
113
+ }
114
+ ```
115
+
116
+ `loading` renders while the paywall is loading and is swapped out the moment it presents. `children` render once the user is entitled. Pass `inline` to mount the paywall iframe inside the component instead of as a full-viewport overlay. Optional handler props (`onPresent`, `onDismiss`, `onSkip`, `onError`) work the same as in `usePlacement`.
117
+
79
118
  ## Subscription status & user
80
119
 
81
120
  ```tsx
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "@superwall/paywalls-react",
3
- "version": "0.1.5",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
6
9
  "exports": {
7
10
  ".": {
8
11
  "types": "./src/index.ts",
@@ -17,10 +20,10 @@
17
20
  },
18
21
  "peerDependencies": {
19
22
  "react": "^19.0.0",
20
- "@superwall/paywalls-js": "^0.1.3"
23
+ "@superwall/paywalls-js": "^0.2.0"
21
24
  },
22
25
  "dependencies": {
23
- "@superwall/paywalls-js": "^0.1.3"
26
+ "@superwall/paywalls-js": "^0.2.0"
24
27
  },
25
28
  "devDependencies": {
26
29
  "@happy-dom/global-registrator": "^20.0.0",
@@ -0,0 +1,94 @@
1
+ import { type ReactNode, useEffect, useMemo, useRef, useState } from "react";
2
+ import type { PlacementParams } from "@superwall/paywalls-js";
3
+ import { createBrowserPresenter } from "@superwall/paywalls-js/browser";
4
+ import type { PaywallPresentationHandlerHooks } from "./hooks.ts";
5
+ import { useSuperwall } from "./hooks.ts";
6
+
7
+ export interface SuperwallPaywallProps extends PaywallPresentationHandlerHooks {
8
+ placement: string;
9
+ params?: PlacementParams;
10
+ /** Rendered when the user is entitled — i.e. the feature block fires. */
11
+ children?: ReactNode;
12
+ /** Rendered while the paywall is loading. Swapped out the moment the paywall presents. */
13
+ loading?: ReactNode;
14
+ /**
15
+ * When true the paywall iframe is mounted inside this component instead of
16
+ * as a full-viewport overlay. Default: false.
17
+ */
18
+ inline?: boolean;
19
+ }
20
+
21
+ /**
22
+ * Declarative feature gate. Calls `register()` on mount and renders
23
+ * `children` when the user is entitled (already subscribed, purchased
24
+ * through the paywall, or the placement has no audience match).
25
+ *
26
+ * ```tsx
27
+ * <SuperwallPaywall placement="campaign_trigger" loading={<Spinner />}>
28
+ * <ProContent />
29
+ * </SuperwallPaywall>
30
+ * ```
31
+ */
32
+ export function SuperwallPaywall({
33
+ placement,
34
+ params,
35
+ children,
36
+ loading = null,
37
+ inline = false,
38
+ onPresent,
39
+ onDismiss,
40
+ onSkip,
41
+ onError,
42
+ }: SuperwallPaywallProps) {
43
+ const sw = useSuperwall();
44
+ const [unlocked, setUnlocked] = useState(false);
45
+ const [presenting, setPresenting] = useState(false);
46
+ const containerRef = useRef<HTMLDivElement>(null);
47
+
48
+ const handlersRef = useRef({ onPresent, onDismiss, onSkip, onError });
49
+ handlersRef.current = { onPresent, onDismiss, onSkip, onError };
50
+
51
+ const presenter = useMemo(
52
+ () =>
53
+ inline
54
+ ? createBrowserPresenter({ container: () => containerRef.current ?? document.body, inline: true })
55
+ : undefined,
56
+ [inline],
57
+ );
58
+
59
+ useEffect(() => {
60
+ let cancelled = false;
61
+ sw.register({
62
+ placement,
63
+ params,
64
+ feature: () => { if (!cancelled) setUnlocked(true); },
65
+ ...(presenter && { presenter }),
66
+ handler: {
67
+ onPresent: (info) => { if (!cancelled) setPresenting(true); handlersRef.current.onPresent?.(info); },
68
+ onDismiss: (info, result) => { handlersRef.current.onDismiss?.(info, result); },
69
+ onSkip: (reason) => { handlersRef.current.onSkip?.(reason); },
70
+ onError: (error) => { handlersRef.current.onError?.(error); },
71
+ },
72
+ }).catch(() => {});
73
+ return () => { cancelled = true; };
74
+ // eslint-disable-next-line react-hooks/exhaustive-deps
75
+ }, [placement, params, presenter]);
76
+
77
+ if (unlocked) return <>{children}</>;
78
+
79
+ // Container always stays in the DOM so the presenter can append the iframe
80
+ // before onPresent fires. We swap loading ↔ iframe via display:none.
81
+ return (
82
+ <div style={{ position: "relative", width: "100%", height: "100%" }}>
83
+ <div
84
+ ref={containerRef}
85
+ style={{ display: presenting ? "block" : "none", width: "100%", height: "100%" }}
86
+ />
87
+ {!presenting && (
88
+ <div style={{ position: "absolute", inset: 0 }}>
89
+ {loading}
90
+ </div>
91
+ )}
92
+ </div>
93
+ );
94
+ }
package/src/index.ts CHANGED
@@ -26,6 +26,11 @@ export {
26
26
  type PaywallPresentationHandlerHooks,
27
27
  } from "./hooks.ts";
28
28
 
29
+ export {
30
+ SuperwallPaywall,
31
+ type SuperwallPaywallProps,
32
+ } from "./SuperwallPaywall.tsx";
33
+
29
34
  // Re-export everything public from paywalls-js so React consumers don't
30
35
  // need to depend on both packages directly. Tree-shakeable per ESM rules.
31
36
  export * from "@superwall/paywalls-js";