@lockerverse/react 0.2.64 → 0.2.65

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
@@ -17,7 +17,10 @@ npm install @stripe/react-stripe-js @stripe/stripe-js
17
17
  ## Use
18
18
 
19
19
  ```tsx
20
- import { LockerversePayment } from "@lockerverse/react/payment";
20
+ import {
21
+ LockerversePayment,
22
+ type LockerversePaymentSelectionItem,
23
+ } from "@lockerverse/react/payment";
21
24
  import "@lockerverse/react/payment.css";
22
25
 
23
26
  export function Checkout() {
@@ -41,6 +44,70 @@ export function Checkout() {
41
44
 
42
45
  The original `@lockerverse/react` and `@lockerverse/react/styles.css` payment imports remain supported.
43
46
 
47
+ ## Custom Product UI
48
+
49
+ Use `useLockerverseWidget` to build custom Product presentation from the live
50
+ Lockerverse catalog. This entry point does not import the payment UI or Stripe.
51
+
52
+ ```tsx
53
+ import { LockerversePayment } from "@lockerverse/react/payment";
54
+ import "@lockerverse/react/payment.css";
55
+ import { useLockerverseWidget } from "@lockerverse/react/widget";
56
+ import { useState } from "react";
57
+
58
+ const widgetOptions = {
59
+ communitySlug: "auburn",
60
+ widgetSlug: "tailgate-party",
61
+ };
62
+
63
+ export function CustomProductCheckout() {
64
+ const { error, loading, products, refresh, widget } =
65
+ useLockerverseWidget(widgetOptions);
66
+ const [selection, setSelection] =
67
+ useState<LockerversePaymentSelectionItem | null>(null);
68
+
69
+ if (loading) {
70
+ return <p>Loading {widget?.name ?? "checkout"}...</p>;
71
+ }
72
+ if (error) {
73
+ return <button onClick={refresh}>Try again</button>;
74
+ }
75
+ if (selection) {
76
+ return (
77
+ <LockerversePayment
78
+ {...widgetOptions}
79
+ selection={[selection]}
80
+ />
81
+ );
82
+ }
83
+
84
+ return products
85
+ .filter((product) => product.pricingMode === "fixed")
86
+ .map((product) => (
87
+ <button
88
+ key={product.id}
89
+ onClick={() =>
90
+ setSelection(
91
+ product.paymentOption === "one-time"
92
+ ? { productSlug: product.slug, quantity: 1 }
93
+ : { productSlug: product.slug }
94
+ )
95
+ }
96
+ >
97
+ {product.name}
98
+ </button>
99
+ ));
100
+ }
101
+ ```
102
+
103
+ The hook returns immutable catalog data together with `status`, `loading`,
104
+ `error`, and `refresh`. The host owns presentation and selection state. Pass the
105
+ selected Product slugs to `LockerversePayment`; Lockerverse remains
106
+ authoritative for availability, pricing, and payment.
107
+
108
+ This small example shows fixed-price Products. For a custom-price Product, ask
109
+ for the amount in the host UI and pass `amountCents` with `productSlug`.
110
+
44
111
  For a monthly or annual Product, omit quantity. The component shows the
45
112
  cadence and configures Stripe Elements for a subscription:
46
113
 
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { a as LockerversePaymentRecovery, c as LockerversePaymentTheme, i as LockerversePaymentProps, l as LockerversePaymentUncertain, n as LockerverseDonateLauncherProps, o as LockerversePaymentSelectionItem, r as LockerversePaymentBranding, s as LockerversePaymentStyle, t as LockerverseDonateLauncherPosition, u as LockerverseStripeLoader } from "./types.js";
2
2
  import { t as LockerverseDonateLauncher } from "./lockerverse-donate-launcher.js";
3
3
  import { t as LockerversePayment } from "./lockerverse-payment.js";
4
- export { LockerverseDonateLauncher, type LockerverseDonateLauncherPosition, type LockerverseDonateLauncherProps, LockerversePayment, type LockerversePaymentBranding, type LockerversePaymentProps, type LockerversePaymentRecovery, type LockerversePaymentSelectionItem, type LockerversePaymentStyle, type LockerversePaymentTheme, type LockerversePaymentUncertain, type LockerverseStripeLoader };
4
+ import { n as UseLockerverseWidgetResult, r as useLockerverseWidget, t as LockerverseWidgetStatus } from "./use-lockerverse-widget.js";
5
+ export { LockerverseDonateLauncher, type LockerverseDonateLauncherPosition, type LockerverseDonateLauncherProps, LockerversePayment, type LockerversePaymentBranding, type LockerversePaymentProps, type LockerversePaymentRecovery, type LockerversePaymentSelectionItem, type LockerversePaymentStyle, type LockerversePaymentTheme, type LockerversePaymentUncertain, type LockerverseStripeLoader, type LockerverseWidgetStatus, type UseLockerverseWidgetResult, useLockerverseWidget };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{t as e}from"./lockerverse-payment.js";import{t}from"./lockerverse-donate-launcher.js";export{t as LockerverseDonateLauncher,e as LockerversePayment};
1
+ import{t as e}from"./lockerverse-payment.js";import{t}from"./lockerverse-donate-launcher.js";import{t as n}from"./use-lockerverse-widget.js";export{t as LockerverseDonateLauncher,e as LockerversePayment,n as useLockerverseWidget};
@@ -0,0 +1,17 @@
1
+ import { CreateLockerverseWidgetOptions, LockerverseCatalog } from "@lockerverse/sdk/checkout";
2
+ //#region src/use-lockerverse-widget.d.ts
3
+ type LockerverseWidgetStatus = "error" | "loading" | "ready";
4
+ type UseLockerverseWidgetResult = {
5
+ catalog: LockerverseCatalog | null;
6
+ community: LockerverseCatalog["community"] | null;
7
+ error: Error | null;
8
+ loading: boolean;
9
+ products: LockerverseCatalog["products"];
10
+ refresh: () => void;
11
+ status: LockerverseWidgetStatus;
12
+ widget: LockerverseCatalog["widget"] | null;
13
+ };
14
+ declare function useLockerverseWidget({ apiBaseUrl, communitySlug, environment, fetch, onError, requestTimeoutMs, sentryDsn, widgetSlug }: CreateLockerverseWidgetOptions): UseLockerverseWidgetResult;
15
+ //#endregion
16
+ export { UseLockerverseWidgetResult as n, useLockerverseWidget as r, LockerverseWidgetStatus as t };
17
+ //# sourceMappingURL=use-lockerverse-widget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-lockerverse-widget.d.ts","names":[],"sources":["../src/use-lockerverse-widget.ts"],"mappings":";;KASY;KAEA;EACV,SAAS;EACT,WAAW;EACX,OAAO;EACP;EACA,UAAU;EACV;EACA,QAAQ;EACR,QAAQ;;iBAoBM,uBACd,YACA,eACA,aACA,OACA,SACA,kBACA,WACA,cACC,iCAAiC"}
@@ -0,0 +1,2 @@
1
+ import{createLockerverseCheckoutClient as e}from"@lockerverse/sdk/checkout";import{useCallback as t,useEffect as n,useMemo as r,useRef as i,useState as a}from"react";const o=Object.freeze([]);function s(e){return e instanceof Error?e:Error(`Unable to load the Lockerverse widget.`)}function c({apiBaseUrl:c,communitySlug:l,environment:u,fetch:d,onError:f,requestTimeoutMs:p,sentryDsn:m,widgetSlug:h}){let g=r(()=>({...c===void 0?{}:{apiBaseUrl:c},communitySlug:l,...u===void 0?{}:{environment:u},...d===void 0?{}:{fetch:d},...p===void 0?{}:{requestTimeoutMs:p},...m===void 0?{}:{sentryDsn:m},widgetSlug:h}),[c,l,u,d,p,m,h]),[_,v]=a(0),[y,b]=a({catalog:null,configuration:null,error:null,status:`loading`}),x=i(f);x.current=f,n(()=>{let t=!0;b({catalog:null,configuration:g,error:null,status:`loading`});async function n(){try{let n=await e({...g,onError:e=>x.current?.(e)}).load();t&&b({catalog:n,configuration:g,error:null,status:`ready`})}catch(e){t&&b({catalog:null,configuration:g,error:s(e),status:`error`})}}return n(),()=>{t=!1}},[g,_]);let S=t(()=>{b({catalog:null,configuration:g,error:null,status:`loading`}),v(e=>e+1)},[g]),C=y.configuration===g?y:null,w=C?.catalog??null,T=C?.status??`loading`;return{catalog:w,community:w?.community??null,error:C?.error??null,loading:T===`loading`,products:w?.products??o,refresh:S,status:T,widget:w?.widget??null}}export{c as t};
2
+ //# sourceMappingURL=use-lockerverse-widget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-lockerverse-widget.js","names":[],"sources":["../src/use-lockerverse-widget.ts"],"sourcesContent":["import type {\n CreateLockerverseWidgetOptions,\n LockerverseCatalog,\n} from \"@lockerverse/sdk/checkout\";\nimport { createLockerverseCheckoutClient } from \"@lockerverse/sdk/checkout\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\ntype WidgetConfiguration = Omit<CreateLockerverseWidgetOptions, \"onError\">;\n\nexport type LockerverseWidgetStatus = \"error\" | \"loading\" | \"ready\";\n\nexport type UseLockerverseWidgetResult = {\n catalog: LockerverseCatalog | null;\n community: LockerverseCatalog[\"community\"] | null;\n error: Error | null;\n loading: boolean;\n products: LockerverseCatalog[\"products\"];\n refresh: () => void;\n status: LockerverseWidgetStatus;\n widget: LockerverseCatalog[\"widget\"] | null;\n};\n\ntype WidgetLoadState = {\n catalog: LockerverseCatalog | null;\n configuration: WidgetConfiguration | null;\n error: Error | null;\n status: LockerverseWidgetStatus;\n};\n\nconst EMPTY_PRODUCTS = Object.freeze(\n []\n) as unknown as LockerverseCatalog[\"products\"];\n\nfunction toError(error: unknown) {\n return error instanceof Error\n ? error\n : new Error(\"Unable to load the Lockerverse widget.\");\n}\n\nexport function useLockerverseWidget({\n apiBaseUrl,\n communitySlug,\n environment,\n fetch,\n onError,\n requestTimeoutMs,\n sentryDsn,\n widgetSlug,\n}: CreateLockerverseWidgetOptions): UseLockerverseWidgetResult {\n const configuration = useMemo<WidgetConfiguration>(\n () => ({\n ...(apiBaseUrl === undefined ? {} : { apiBaseUrl }),\n communitySlug,\n ...(environment === undefined ? {} : { environment }),\n ...(fetch === undefined ? {} : { fetch }),\n ...(requestTimeoutMs === undefined ? {} : { requestTimeoutMs }),\n ...(sentryDsn === undefined ? {} : { sentryDsn }),\n widgetSlug,\n }),\n [\n apiBaseUrl,\n communitySlug,\n environment,\n fetch,\n requestTimeoutMs,\n sentryDsn,\n widgetSlug,\n ]\n );\n const [revision, setRevision] = useState(0);\n const [state, setState] = useState<WidgetLoadState>({\n catalog: null,\n configuration: null,\n error: null,\n status: \"loading\",\n });\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n\n useEffect(() => {\n let active = true;\n setState({\n catalog: null,\n configuration,\n error: null,\n status: \"loading\",\n });\n\n async function loadWidget() {\n try {\n const client = createLockerverseCheckoutClient({\n ...configuration,\n onError: (error) => onErrorRef.current?.(error),\n });\n const catalog = await client.load();\n if (active) {\n setState({\n catalog,\n configuration,\n error: null,\n status: \"ready\",\n });\n }\n } catch (error) {\n if (active) {\n setState({\n catalog: null,\n configuration,\n error: toError(error),\n status: \"error\",\n });\n }\n }\n }\n\n loadWidget();\n return () => {\n active = false;\n };\n }, [configuration, revision]);\n\n const refresh = useCallback(() => {\n setState({\n catalog: null,\n configuration,\n error: null,\n status: \"loading\",\n });\n setRevision((value) => value + 1);\n }, [configuration]);\n const current = state.configuration === configuration ? state : null;\n const catalog = current?.catalog ?? null;\n const status = current?.status ?? \"loading\";\n\n return {\n catalog,\n community: catalog?.community ?? null,\n error: current?.error ?? null,\n loading: status === \"loading\",\n products: catalog?.products ?? EMPTY_PRODUCTS,\n refresh,\n status,\n widget: catalog?.widget ?? null,\n };\n}\n"],"mappings":"sKA6BA,MAAM,EAAiB,OAAO,OAC5B,CAAC,CACH,EAEA,SAAS,EAAQ,EAAgB,CAC/B,OAAO,aAAiB,MACpB,EACI,MAAM,wCAAwC,CACxD,CAEA,SAAgB,EAAqB,CACnC,aACA,gBACA,cACA,QACA,UACA,mBACA,YACA,cAC6D,CAC7D,IAAM,EAAgB,OACb,CACL,GAAI,IAAe,IAAA,GAAY,CAAC,EAAI,CAAE,YAAW,EACjD,gBACA,GAAI,IAAgB,IAAA,GAAY,CAAC,EAAI,CAAE,aAAY,EACnD,GAAI,IAAU,IAAA,GAAY,CAAC,EAAI,CAAE,OAAM,EACvC,GAAI,IAAqB,IAAA,GAAY,CAAC,EAAI,CAAE,kBAAiB,EAC7D,GAAI,IAAc,IAAA,GAAY,CAAC,EAAI,CAAE,WAAU,EAC/C,YACF,GACA,CACE,EACA,EACA,EACA,EACA,EACA,EACA,CACF,CACF,EACM,CAAC,EAAU,GAAe,EAAS,CAAC,EACpC,CAAC,EAAO,GAAY,EAA0B,CAClD,QAAS,KACT,cAAe,KACf,MAAO,KACP,OAAQ,SACV,CAAC,EACK,EAAa,EAAO,CAAO,EACjC,EAAW,QAAU,EAErB,MAAgB,CACd,IAAI,EAAS,GACb,EAAS,CACP,QAAS,KACT,gBACA,MAAO,KACP,OAAQ,SACV,CAAC,EAED,eAAe,GAAa,CAC1B,GAAI,CAKF,IAAM,EAAU,MAJD,EAAgC,CAC7C,GAAG,EACH,QAAU,GAAU,EAAW,UAAU,CAAK,CAChD,CAC2B,CAAC,CAAC,KAAK,EAC9B,GACF,EAAS,CACP,UACA,gBACA,MAAO,KACP,OAAQ,OACV,CAAC,CAEL,OAAS,EAAO,CACV,GACF,EAAS,CACP,QAAS,KACT,gBACA,MAAO,EAAQ,CAAK,EACpB,OAAQ,OACV,CAAC,CAEL,CACF,CAGA,OADA,EAAW,MACE,CACX,EAAS,EACX,CACF,EAAG,CAAC,EAAe,CAAQ,CAAC,EAE5B,IAAM,EAAU,MAAkB,CAChC,EAAS,CACP,QAAS,KACT,gBACA,MAAO,KACP,OAAQ,SACV,CAAC,EACD,EAAa,GAAU,EAAQ,CAAC,CAClC,EAAG,CAAC,CAAa,CAAC,EACZ,EAAU,EAAM,gBAAkB,EAAgB,EAAQ,KAC1D,EAAU,GAAS,SAAW,KAC9B,EAAS,GAAS,QAAU,UAElC,MAAO,CACL,UACA,UAAW,GAAS,WAAa,KACjC,MAAO,GAAS,OAAS,KACzB,QAAS,IAAW,UACpB,SAAU,GAAS,UAAY,EAC/B,UACA,SACA,OAAQ,GAAS,QAAU,IAC7B,CACF"}
@@ -0,0 +1,2 @@
1
+ import { n as UseLockerverseWidgetResult, r as useLockerverseWidget, t as LockerverseWidgetStatus } from "./use-lockerverse-widget.js";
2
+ export { type LockerverseWidgetStatus, type UseLockerverseWidgetResult, useLockerverseWidget };
package/dist/widget.js ADDED
@@ -0,0 +1 @@
1
+ import{t as e}from"./use-lockerverse-widget.js";export{e as useLockerverseWidget};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lockerverse/react",
3
- "version": "0.2.64",
3
+ "version": "0.2.65",
4
4
  "description": "Tree-shakable React payment and signup UI for Lockerverse",
5
5
  "repository": {
6
6
  "type": "git",
@@ -33,6 +33,11 @@
33
33
  "import": "./dist/signup.js",
34
34
  "default": "./dist/signup.js"
35
35
  },
36
+ "./widget": {
37
+ "types": "./dist/widget.d.ts",
38
+ "import": "./dist/widget.js",
39
+ "default": "./dist/widget.js"
40
+ },
36
41
  "./styles.css": {
37
42
  "types": "./dist/styles.d.ts",
38
43
  "default": "./dist/styles.css"
@@ -55,7 +60,7 @@
55
60
  "dependencies": {
56
61
  "@base-ui/react": "1.6.0",
57
62
  "valibot": "1.4.2",
58
- "@lockerverse/sdk": "0.2.64"
63
+ "@lockerverse/sdk": "0.2.65"
59
64
  },
60
65
  "devDependencies": {
61
66
  "@size-limit/file": "13.0.3",
@@ -125,6 +130,14 @@
125
130
  "dist/contact-validation.js"
126
131
  ]
127
132
  },
133
+ {
134
+ "name": "React widget data",
135
+ "limit": "2 kB",
136
+ "path": [
137
+ "dist/widget.js",
138
+ "dist/use-lockerverse-widget.js"
139
+ ]
140
+ },
128
141
  {
129
142
  "name": "React signup styles",
130
143
  "limit": "4 kB",