@getuserfeedback/react 0.9.6 → 0.11.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
@@ -1,68 +1,42 @@
1
1
  # @getuserfeedback/react
2
2
 
3
- In-product surveys for React apps, from [getuserfeedback.com](https://getuserfeedback.com). Ask one short question at the right moment, and read every answer.
3
+ Add in-product surveys, forms, and messages to React applications with
4
+ [getuserfeedback.com](https://getuserfeedback.com).
4
5
 
5
- > Plain JavaScript or another framework? Use [@getuserfeedback/sdk](https://www.npmjs.com/package/@getuserfeedback/sdk).
6
+ > Using plain JavaScript or another browser framework? Use
7
+ > [@getuserfeedback/sdk](https://www.npmjs.com/package/@getuserfeedback/sdk).
6
8
  >
7
- > Building a React Native app? Use [@getuserfeedback/react-native](https://www.npmjs.com/package/@getuserfeedback/react-native).
9
+ > Building a React Native app? Use
10
+ > [@getuserfeedback/react-native](https://www.npmjs.com/package/@getuserfeedback/react-native).
8
11
 
9
- ## Install
12
+ ## Get started
13
+
14
+ Install the SDK:
10
15
 
11
16
  ```bash
12
17
  npm install @getuserfeedback/react
13
18
  ```
14
19
 
15
- Requires `react >= 18`.
20
+ Requires React 18 or later.
16
21
 
17
- ## For AI agents
18
-
19
- Installing this for someone? Start with our MCP server, not with this page. Connect `https://mcp.getuserfeedback.com` (listed in the MCP registry as `com.getuserfeedback/mcp`) and read its get-started resource — `getuserfeedback://docs/get-started`. It walks the whole path in order: workspace, API key (the MCP hands it to you), this package's install, the first survey, and which steps need a human.
20
-
21
- ## Get started
22
-
23
- Grab your Public API key from the dashboard — Settings → Widget — and mount the provider near the root of your app:
22
+ Mount the provider near the root of your app using the Public API key from
23
+ [Widget settings](https://getuserfeedback.com/app/_/settings/widget):
24
24
 
25
25
  ```tsx
26
26
  import { GetUserFeedbackProvider } from "@getuserfeedback/react";
27
27
 
28
28
  export function App() {
29
- return (
30
- <GetUserFeedbackProvider clientOptions={{ apiKey: "YOUR_API_KEY" }}>
31
- <YourApp />
32
- </GetUserFeedbackProvider>
33
- );
34
- }
35
- ```
36
-
37
- If your app has signed-in users, also identify them. It lets surveys target signed-in users, and each answer arrives attributed to the person instead of anonymous. Call identify from an effect keyed on your auth state — resetting only when a signed-in user signs out, so anonymous visitors keep their identity — and render the component anywhere inside the provider:
38
-
39
- ```tsx
40
- import { useEffect, useRef } from "react";
41
- import { useGetUserFeedback } from "@getuserfeedback/react";
42
-
43
- function IdentifyUser({ user }: { user: { id: string; email: string } | null }) {
44
- const client = useGetUserFeedback();
45
- const wasIdentified = useRef(false);
46
- useEffect(() => {
47
- if (user) {
48
- client.identify(user.id, { email: user.email });
49
- wasIdentified.current = true;
50
- } else if (wasIdentified.current) {
51
- wasIdentified.current = false;
52
- client.reset();
53
- }
54
- }, [user, client]);
55
- return null;
29
+ return (
30
+ <GetUserFeedbackProvider clientOptions={{ apiKey: "YOUR_API_KEY" }}>
31
+ <YourApp />
32
+ </GetUserFeedbackProvider>
33
+ );
56
34
  }
57
35
  ```
58
36
 
59
- That's it. The widget is running, and surveys you publish in the dashboard show up based on the targeting you set there — nothing shows until you publish something.
60
-
61
- - Full guide: [getuserfeedback.com/docs/get-started/react-sdk](https://getuserfeedback.com/docs/get-started/react-sdk)
62
- - API reference: [getuserfeedback.com/docs/reference/react-sdk-reference](https://getuserfeedback.com/docs/reference/react-sdk-reference)
63
-
64
- ## Links
37
+ That is enough to receive flows published for automatic Widget delivery.
65
38
 
66
- - Docs: [getuserfeedback.com/docs](https://getuserfeedback.com/docs)
67
- - Package versions (release history): [npm versions for `@getuserfeedback/react`](https://www.npmjs.com/package/@getuserfeedback/react?activeTab=versions)
68
- - Report issues / support: [hello@getuserfeedback.com](mailto:hello@getuserfeedback.com)
39
+ - [React SDK guide](https://getuserfeedback.com/docs/get-started/react-sdk)
40
+ - [React SDK reference](https://getuserfeedback.com/docs/reference/react-sdk-reference)
41
+ - [Package versions](https://www.npmjs.com/package/@getuserfeedback/react?activeTab=versions)
42
+ - [Support](mailto:hello@getuserfeedback.com)
@@ -0,0 +1,6 @@
1
+ "use client";
2
+ import{createClient as L}from"@getuserfeedback/sdk";import{createActionRegistry as x}from"@getuserfeedback/sdk/internal/action-registry";import{createContext as E,useCallback as u,useContext as b,useEffect as P,useMemo as R,useRef as p,useState as S,useSyncExternalStore as D}from"react";import{jsx as j}from"react/jsx-runtime";var g={isOpen:!1,isLoading:!1,shouldRenderContainer:!1},T=(e)=>({isOpen:e.isOpen,isLoading:e.isLoading}),O=(e)=>typeof e.width==="number"&&typeof e.height==="number",M=(e,n)=>e.isOpen===n.isOpen&&e.isLoading===n.isLoading&&O(e)===O(n),I={isOpen:!1,isLoading:!1,width:void 0,height:void 0};function G(e){let n=p(e.getFlowState());return u(()=>{let o=e.getFlowState(),a=n.current;if(M(a,o))return a;return n.current=o,o},[e])}function U(e,n,o){let a=G(e),t=p(null),i=p(null),r=u(()=>{let s=a();if(t.current===s){let c=i.current;if(c!==null)return c}let l=n(s);return t.current=s,i.current=l,l},[a,n]);return D((s)=>e.subscribeFlowState(()=>{s()},{emitInitial:!1}),r,o)}var h=E(null),m=new WeakMap,v=(e)=>{try{return JSON.stringify(x(e).listRegistrationIdentities())}catch{return null}};function V({children:e,clientOptions:n}){let o=p(v(n.actions)),a=v(n.actions);if(a!==null&&o.current!==null&&a!==o.current)throw Error("GetUserFeedbackProvider clientOptions.actions definitions cannot change after mount. Keep each custom key and version fixed for the provider lifetime; handler functions may change.");let t=L(n),i=p(null),r=U(t,T,()=>g),s=u((d,f)=>{if(i.current!==d||m.get(t)!==d)return;t.setDefaultContainerPolicy({kind:"hostContainer",host:f,sharing:"perFlowRun"})},[t]),l=u((d,f)=>{let C=m.get(t);if(C!==void 0&&C!==d)throw Error("Only one useFlowContainer consumer can be mounted for a getuserfeedback client");return m.set(t,d),i.current=d,t.setDefaultContainerPolicy({kind:"hostContainer",host:f,sharing:"perFlowRun"}),()=>{if(i.current!==d||m.get(t)!==d)return;i.current=null,m.delete(t),t.setDefaultContainerPolicy({kind:"floating"})}},[t]),c=R(()=>{if(!r.isOpen&&!r.isLoading)return g;return{isOpen:r.isOpen,isLoading:r.isLoading,shouldRenderContainer:!0}},[r]),w=R(()=>({client:t,apiKey:n.apiKey,setDefaultFlowContainer:s,registerDefaultFlowContainerConsumer:l,defaultFlowContainerState:c}),[t,n.apiKey,c,l,s]);return j(h.Provider,{value:w,children:e})}var H=(e)=>{let{flowRun:n,openFlow:o,prerenderFlow:a,prefetchOnMount:t=!1,hideCloseButton:i}=e,r=e.mode==="container",s=p(null),l=U(n,(F)=>F,()=>I),c=u((F)=>o({container:r?s.current??null:void 0,hideCloseButton:i,metadata:F?.metadata}),[i,o,r]),w=u(()=>n.close(),[n]),d=u(()=>n.prefetch(),[n]),f=u((F)=>F?c():w(),[w,c]),C=u((F)=>{if(!r)return;s.current=F,n.setContainer(F)},[n,r]),y=O(l),k=r&&(l.isOpen||l.isLoading&&y);return P(()=>{if(!t)return;d().catch(()=>{})},[d,t]),{isOpen:l.isOpen,isLoading:l.isLoading,shouldRenderContainer:k,setOpen:f,open:c,close:w,prefetch:d,prerender:()=>a({container:r?s.current??null:void 0,hideCloseButton:i}),containerRef:C}};function B(e){let n=e.container??"default";if(p(n).current!==n)throw Error("useFlow container mode cannot change while mounted; remount the hook to change it");let a=n==="custom"?"container":"default",t=H({flowRun:e.flowRun,mode:a,openFlow:e.openFlow,prerenderFlow:e.prerenderFlow,prefetchOnMount:e.prefetchOnMount,hideCloseButton:e.hideCloseButton});if(a==="container")return{container:"custom",isOpen:t.isOpen,isLoading:t.isLoading,shouldRenderContainer:t.shouldRenderContainer,open:t.open,close:t.close,prefetch:t.prefetch,setOpen:t.setOpen,prerender:t.prerender,containerRef:t.containerRef};return{container:"default",isOpen:t.isOpen,isLoading:t.isLoading,open:t.open,close:t.close,prefetch:t.prefetch,prerender:t.prerender}}function _(e){let n=b(h);if(!n)throw Error("useFlow must be used within a GetUserFeedbackProvider");let o=R(()=>n.client.flow(e.flowId),[n.client,e.flowId]),a=u(({container:i,hideCloseButton:r,metadata:s})=>o.open(i===void 0?{hideCloseButton:r,metadata:s}:{container:i,hideCloseButton:r,metadata:s}),[o]),t=u(({hideCloseButton:i})=>o.prerender({hideCloseButton:i}),[o]);return B({flowRun:o,openFlow:a,prerenderFlow:t,container:e.container,prefetchOnMount:e.prefetchOnMount,hideCloseButton:e.hideCloseButton})}function W(){let e=b(h);if(!e)throw Error("useFlowContainer must be used within a GetUserFeedbackProvider");let{client:n,defaultFlowContainerState:o,registerDefaultFlowContainerConsumer:a,setDefaultFlowContainer:t}=e,i=p({}),r=p(null);P(()=>a(i.current,r.current),[a]);let s=u((c)=>{r.current=c,t(i.current,c)},[t]),l=u(()=>n.close(),[n]);return{isOpen:o.isOpen,isLoading:o.isLoading,shouldRenderContainer:o.shouldRenderContainer,close:l,containerRef:s}}function q(){let e=b(h);if(!e)throw Error("useFeedback must be used within a GetUserFeedbackProvider");let[n,o]=S(0),[a,t]=S(0),i=u(async(s)=>{o((l)=>l+1);try{return await e.client.feedback.fetch(s)}finally{o((l)=>l-1)}},[e.client]),r=u(async(s)=>{t((l)=>l+1);try{return await e.client.feedback.submit(s)}finally{t((l)=>l-1)}},[e.client]);return{fetch:i,isFetching:n>0,isSubmitting:a>0,submit:r}}function J(){let e=b(h);if(!e)throw Error("useGetUserFeedback must be used within a GetUserFeedbackProvider");return e.client}
3
+ export{h as a,V as b,B as c,_ as d,W as e,q as f,J as g};
4
+
5
+ //# debugId=3F0C5DDA586FBA5164756E2164756E21
6
+ //# sourceMappingURL=chunk-a3b04qn2.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/client.tsx"],
4
+ "sourcesContent": [
5
+ "\"use client\";\n\nimport {\n\ttype Client,\n\ttype ClientOptions,\n\tcreateClient,\n\ttype FeedbackInput,\n\ttype FetchFeedbackInput,\n\ttype FetchFeedbackResult,\n\ttype FlowRun,\n\ttype FlowState,\n\ttype OpenFlowOptions as SdkOpenFlowOptions,\n\ttype SubmitFeedbackResult,\n} from \"@getuserfeedback/sdk\";\nimport { createActionRegistry } from \"@getuserfeedback/sdk/internal/action-registry\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport {\n\tcreateContext,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n\tuseSyncExternalStore,\n} from \"react\";\n\n/**\n * Return value for the experimental `useFeedback()` hook.\n *\n * @experimental\n */\nexport interface UseFeedbackReturn {\n\t/** Fetch feedback matching each selector for the JWT-authenticated user. */\n\tfetch: (input: FetchFeedbackInput) => Promise<FetchFeedbackResult>;\n\t/** True while one or more fetches from this hook are pending. */\n\tisFetching: boolean;\n\t/** True while one or more submissions from this hook are pending. */\n\tisSubmitting: boolean;\n\t/** Submit feedback about the current app or a specific target. */\n\tsubmit: (input: FeedbackInput) => Promise<SubmitFeedbackResult>;\n}\n\n/**\n * Options for useFlow().\n */\nexport interface UseFlowOptions {\n\t/** The flow/survey ID to control. */\n\tflowId: string;\n\t/** Prefetch the flow resources on mount so it opens faster. Default `false`. */\n\tprefetchOnMount?: boolean;\n\t/**\n\t * Where the flow mounts: `\"default\"` (floating container) or `\"custom\"` (your container via containerRef).\n\t * Default `\"default\"`. Remount the hook to change this mode.\n\t */\n\tcontainer?: \"default\" | \"custom\";\n\t/** When true, the view does not show a close button. */\n\thideCloseButton?: boolean;\n}\n\ntype UseFlowPresentationOptions = Pick<\n\tUseFlowOptions,\n\t\"container\" | \"hideCloseButton\" | \"prefetchOnMount\"\n>;\n\n/**\n * Per-open options for useFlow(). These apply to the specific response created\n * by that open action and do not affect prerendering.\n */\nexport interface UseFlowOpenOptions {\n\t/** Optional response metadata to preserve with the eventual submission. */\n\tmetadata?: SdkOpenFlowOptions[\"metadata\"];\n}\n\n/**\n * Return value for useFlow() when container is `\"default\"`: state and callbacks for the floating flow.\n */\nexport interface UseFlowReturn {\n\treadonly container: \"default\";\n\t/** True when the flow is visible. */\n\tisOpen: boolean;\n\t/** True after open is requested while the flow is not visible yet. */\n\tisLoading: boolean;\n\t/** Open the flow. */\n\topen: (options?: UseFlowOpenOptions) => Promise<void>;\n\t/** Close the flow. */\n\tclose: () => Promise<void>;\n\t/** Prefetches the flow resources without opening it. */\n\tprefetch: () => Promise<void>;\n\t/** Prerendering warms up the flow for instant display later. */\n\tprerender: () => Promise<void>;\n}\n\n/**\n * Return value for useFlow() when container is `\"custom\"`: state and callbacks for host-managed container flows.\n */\nexport interface UseCustomFlowReturn {\n\treadonly container: \"custom\";\n\t/** True when the flow is visible. */\n\tisOpen: boolean;\n\t/** True after open is requested while the flow is not visible yet. */\n\tisLoading: boolean;\n\t/** True when your host UI should render the custom container element. */\n\tshouldRenderContainer: boolean;\n\t/** Open the flow in the custom container. */\n\topen: (options?: UseFlowOpenOptions) => Promise<void>;\n\t/** Close the flow. */\n\tclose: () => Promise<void>;\n\t/** Prefetches the flow resources without opening it. */\n\tprefetch: () => Promise<void>;\n\t/**\n\t * @deprecated Use `open()` or `close()` instead. Kept for compatibility.\n\t */\n\tsetOpen: (next: boolean) => Promise<void>;\n\t/** Prerendering warms up the flow for instant display later. */\n\tprerender: () => Promise<void>;\n\t/** Ref callback: attach this to the container element where the flow should render. */\n\tcontainerRef: (element: HTMLDivElement | null) => void;\n}\n\n/**\n * Return value for useFlowContainer(): container ref and aggregate flow state\n * for flows using the default presentation in the same logical client\n * (including targeting-engine opens). Mount exactly one consumer per logical\n * client.\n */\nexport interface UseFlowContainerReturn {\n\t/** True when any flow is visible. */\n\tisOpen: boolean;\n\t/** True after any flow open is requested while the flow is not visible yet. */\n\tisLoading: boolean;\n\t/** True when your host UI should render the provider-wide flow container. */\n\tshouldRenderContainer: boolean;\n\t/** Close all open flows owned by this logical client. */\n\tclose: () => Promise<void>;\n\t/** Ref callback for the provider-wide flow container element. */\n\tcontainerRef: (element: HTMLDivElement | null) => void;\n}\n\ntype InstanceFlowRenderState = {\n\tisOpen: boolean;\n\tisLoading: boolean;\n};\n\ntype DefaultFlowContainerState = {\n\tisOpen: boolean;\n\tisLoading: boolean;\n\tshouldRenderContainer: boolean;\n};\n\nconst DEFAULT_FLOW_CONTAINER_STATE: DefaultFlowContainerState = {\n\tisOpen: false,\n\tisLoading: false,\n\tshouldRenderContainer: false,\n};\n\nconst toInstanceFlowRenderState = (\n\tstate: FlowState,\n): InstanceFlowRenderState => ({\n\tisOpen: state.isOpen,\n\tisLoading: state.isLoading,\n});\n\nconst hasPreparedFlowState = (state: FlowState): boolean =>\n\ttypeof state.width === \"number\" && typeof state.height === \"number\";\n\nconst isSameFlowLifecycleState = (\n\ta: Pick<FlowState, \"isOpen\" | \"isLoading\" | \"width\" | \"height\">,\n\tb: Pick<FlowState, \"isOpen\" | \"isLoading\" | \"width\" | \"height\">,\n): boolean =>\n\ta.isOpen === b.isOpen &&\n\ta.isLoading === b.isLoading &&\n\thasPreparedFlowState(a) === hasPreparedFlowState(b);\n\ntype FlowStateStore = {\n\tgetFlowState: () => FlowState;\n\tsubscribeFlowState: (\n\t\tlistener: (state: FlowState) => void,\n\t\toptions?: { emitInitial?: boolean },\n\t) => () => void;\n};\n\nconst FALLBACK_FLOW_STATE: FlowState = {\n\tisOpen: false,\n\tisLoading: false,\n\twidth: undefined,\n\theight: undefined,\n};\n\nfunction useStableFlowStateSnapshot(store: FlowStateStore): () => FlowState {\n\tconst snapshotRef = useRef<FlowState>(store.getFlowState());\n\n\treturn useCallback((): FlowState => {\n\t\tconst next = store.getFlowState();\n\t\tconst previous = snapshotRef.current;\n\t\tif (isSameFlowLifecycleState(previous, next)) {\n\t\t\treturn previous;\n\t\t}\n\t\tsnapshotRef.current = next;\n\t\treturn next;\n\t}, [store]);\n}\n\nfunction useFlowStateStoreValue<TState>(\n\tstore: FlowStateStore,\n\tproject: (state: FlowState) => TState,\n\tgetServerSnapshot: () => TState,\n): TState {\n\tconst getFlowStateSnapshot = useStableFlowStateSnapshot(store);\n\tconst lastSourceSnapshotRef = useRef<FlowState | null>(null);\n\tconst lastProjectedSnapshotRef = useRef<TState | null>(null);\n\tconst getProjectedSnapshot = useCallback((): TState => {\n\t\tconst sourceSnapshot = getFlowStateSnapshot();\n\t\tif (lastSourceSnapshotRef.current === sourceSnapshot) {\n\t\t\tconst cachedProjectedSnapshot = lastProjectedSnapshotRef.current;\n\t\t\tif (cachedProjectedSnapshot !== null) {\n\t\t\t\treturn cachedProjectedSnapshot;\n\t\t\t}\n\t\t}\n\t\tconst projectedSnapshot = project(sourceSnapshot);\n\t\tlastSourceSnapshotRef.current = sourceSnapshot;\n\t\tlastProjectedSnapshotRef.current = projectedSnapshot;\n\t\treturn projectedSnapshot;\n\t}, [getFlowStateSnapshot, project]);\n\n\treturn useSyncExternalStore<TState>(\n\t\t(onStoreChange) =>\n\t\t\tstore.subscribeFlowState(\n\t\t\t\t() => {\n\t\t\t\t\tonStoreChange();\n\t\t\t\t},\n\t\t\t\t{ emitInitial: false },\n\t\t\t),\n\t\tgetProjectedSnapshot,\n\t\tgetServerSnapshot,\n\t);\n}\n\ntype GetUserFeedbackContextValue = {\n\tclient: Client;\n\tapiKey: string;\n\tsetDefaultFlowContainer: (owner: object, element: HTMLElement | null) => void;\n\tregisterDefaultFlowContainerConsumer: (\n\t\towner: object,\n\t\telement: HTMLElement | null,\n\t) => () => void;\n\tdefaultFlowContainerState: DefaultFlowContainerState;\n};\n\nexport const GetUserFeedbackContext =\n\tcreateContext<GetUserFeedbackContextValue | null>(null);\n\nconst flowContainerOwnerByClient = new WeakMap<Client, object>();\n\nexport interface GetUserFeedbackProviderProps {\n\t/** Application subtree that can use getuserfeedback hooks. */\n\tchildren: ReactNode;\n\t/**\n\t * Core SDK client options used to create/reuse the underlying client.\n\t * Action definitions must remain fixed for the provider's mounted\n\t * lifetime; handlers may change while their custom key and version stay\n\t * the same.\n\t */\n\tclientOptions: ClientOptions;\n}\n\nconst toActionDefinitionsKey = (\n\tactions: ClientOptions[\"actions\"],\n): string | null => {\n\ttry {\n\t\treturn JSON.stringify(\n\t\t\tcreateActionRegistry(actions).listRegistrationIdentities(),\n\t\t);\n\t} catch {\n\t\treturn null;\n\t}\n};\n\n/**\n * Provider for getuserfeedback React hooks.\n * Wrap your app (or a subtree) so `useFlow`, `useFlowContainer`, and\n * `useGetUserFeedback` can access a client created from `clientOptions`.\n *\n * If your app uses `useFlowContainer()`, flows using the default presentation\n * in this subtree (including targeting-engine opens) target that container.\n * If the container ref is not mounted yet, loader keeps flows parked until it is.\n * Mount exactly one `useFlowContainer()` consumer per logical client. Providers\n * with the same API key and targeting context reuse that client.\n *\n * @example Basic usage\n * ```tsx\n * function App() {\n * return (\n * <GetUserFeedbackProvider clientOptions={{ apiKey: \"YOUR_API_KEY\" }}>\n * <Routes />\n * </GetUserFeedbackProvider>\n * );\n * }\n * ```\n *\n * @example Display *any* flow in your own dialog (a shadcn/ui dialog in this example):\n * ```tsx\n * function AppFlowContainer() {\n * const { close, containerRef, shouldRenderContainer } = useFlowContainer();\n *\n * return (\n * <Dialog\n * open={shouldRenderContainer}\n * onOpenChange={(open) => {\n * if (!open) {\n * void close().catch((error) =>\n * console.error(\"Unable to close feedback\", error),\n * );\n * }\n * }}\n * >\n * <DialogContent>\n * <div ref={containerRef} style={{ width: \"100%\" }} />\n * </DialogContent>\n * </Dialog>\n * );\n * }\n *\n * function App() {\n * return (\n * <GetUserFeedbackProvider clientOptions={{ apiKey: \"YOUR_API_KEY\" }}>\n * <AppRoutes />\n * <AppFlowContainer /> // Targeted flows display in your dialog.\n * </GetUserFeedbackProvider>\n * );\n * }\n * ```\n */\nexport function GetUserFeedbackProvider({\n\tchildren,\n\tclientOptions,\n}: GetUserFeedbackProviderProps): ReactElement {\n\tconst initialActionDefinitionsKeyRef = useRef(\n\t\ttoActionDefinitionsKey(clientOptions.actions),\n\t);\n\tconst actionDefinitionsKey = toActionDefinitionsKey(clientOptions.actions);\n\tif (\n\t\tactionDefinitionsKey !== null &&\n\t\tinitialActionDefinitionsKeyRef.current !== null &&\n\t\tactionDefinitionsKey !== initialActionDefinitionsKeyRef.current\n\t) {\n\t\tthrow new Error(\n\t\t\t\"GetUserFeedbackProvider clientOptions.actions definitions cannot change after mount. Keep each custom key and version fixed for the provider lifetime; handler functions may change.\",\n\t\t);\n\t}\n\tconst client = createClient(clientOptions);\n\tconst defaultFlowContainerOwnerRef = useRef<object | null>(null);\n\tconst instanceFlowState = useFlowStateStoreValue<InstanceFlowRenderState>(\n\t\tclient,\n\t\ttoInstanceFlowRenderState,\n\t\t() => DEFAULT_FLOW_CONTAINER_STATE,\n\t);\n\n\tconst setDefaultFlowContainer = useCallback(\n\t\t(owner: object, element: HTMLElement | null) => {\n\t\t\tif (\n\t\t\t\tdefaultFlowContainerOwnerRef.current !== owner ||\n\t\t\t\tflowContainerOwnerByClient.get(client) !== owner\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tclient.setDefaultContainerPolicy({\n\t\t\t\tkind: \"hostContainer\",\n\t\t\t\thost: element,\n\t\t\t\tsharing: \"perFlowRun\",\n\t\t\t});\n\t\t},\n\t\t[client],\n\t);\n\n\tconst registerDefaultFlowContainerConsumer = useCallback(\n\t\t(owner: object, element: HTMLElement | null) => {\n\t\t\tconst currentOwner = flowContainerOwnerByClient.get(client);\n\t\t\tif (currentOwner !== undefined && currentOwner !== owner) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Only one useFlowContainer consumer can be mounted for a getuserfeedback client\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tflowContainerOwnerByClient.set(client, owner);\n\t\t\tdefaultFlowContainerOwnerRef.current = owner;\n\t\t\tclient.setDefaultContainerPolicy({\n\t\t\t\tkind: \"hostContainer\",\n\t\t\t\thost: element,\n\t\t\t\tsharing: \"perFlowRun\",\n\t\t\t});\n\n\t\t\treturn () => {\n\t\t\t\tif (\n\t\t\t\t\tdefaultFlowContainerOwnerRef.current !== owner ||\n\t\t\t\t\tflowContainerOwnerByClient.get(client) !== owner\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tdefaultFlowContainerOwnerRef.current = null;\n\t\t\t\tflowContainerOwnerByClient.delete(client);\n\t\t\t\tclient.setDefaultContainerPolicy({ kind: \"floating\" });\n\t\t\t};\n\t\t},\n\t\t[client],\n\t);\n\n\tconst defaultFlowContainerState = useMemo<DefaultFlowContainerState>(() => {\n\t\tif (!instanceFlowState.isOpen && !instanceFlowState.isLoading) {\n\t\t\treturn DEFAULT_FLOW_CONTAINER_STATE;\n\t\t}\n\t\treturn {\n\t\t\tisOpen: instanceFlowState.isOpen,\n\t\t\tisLoading: instanceFlowState.isLoading,\n\t\t\tshouldRenderContainer: true,\n\t\t};\n\t}, [instanceFlowState]);\n\n\tconst contextValue = useMemo(\n\t\t() => ({\n\t\t\tclient,\n\t\t\tapiKey: clientOptions.apiKey,\n\t\t\tsetDefaultFlowContainer,\n\t\t\tregisterDefaultFlowContainerConsumer,\n\t\t\tdefaultFlowContainerState,\n\t\t}),\n\t\t[\n\t\t\tclient,\n\t\t\tclientOptions.apiKey,\n\t\t\tdefaultFlowContainerState,\n\t\t\tregisterDefaultFlowContainerConsumer,\n\t\t\tsetDefaultFlowContainer,\n\t\t],\n\t);\n\n\treturn (\n\t\t<GetUserFeedbackContext.Provider value={contextValue}>\n\t\t\t{children}\n\t\t</GetUserFeedbackContext.Provider>\n\t);\n}\n\ntype FlowControllerRun = Pick<\n\tFlowRun,\n\t\"setContainer\" | \"getFlowState\" | \"subscribeFlowState\" | \"prefetch\" | \"close\"\n>;\n\ntype FlowControllerOpenInput = {\n\tcontainer: HTMLDivElement | null | undefined;\n\tmetadata?: UseFlowOpenOptions[\"metadata\"];\n\thideCloseButton?: boolean;\n};\n\nexport type UseFlowControllerOptions = {\n\tflowRun: FlowControllerRun;\n\tmode: \"default\" | \"container\";\n\topenFlow: (input: FlowControllerOpenInput) => Promise<void>;\n\tprerenderFlow: (input: {\n\t\tcontainer: HTMLDivElement | null | undefined;\n\t\thideCloseButton?: boolean;\n\t}) => Promise<void>;\n\tprefetchOnMount?: boolean;\n\thideCloseButton?: boolean;\n};\n\ntype UseFlowControllerReturn = {\n\tisOpen: boolean;\n\tisLoading: boolean;\n\tshouldRenderContainer: boolean;\n\tsetOpen: (next: boolean) => Promise<void>;\n\topen: (options?: UseFlowOpenOptions) => Promise<void>;\n\tclose: () => Promise<void>;\n\tprefetch: () => Promise<void>;\n\tprerender: () => Promise<void>;\n\tcontainerRef: (element: HTMLDivElement | null) => void;\n};\n\ntype UseFlowRunOptions = UseFlowPresentationOptions & {\n\tflowRun: FlowControllerRun;\n\topenFlow: UseFlowControllerOptions[\"openFlow\"];\n\tprerenderFlow: UseFlowControllerOptions[\"prerenderFlow\"];\n};\n\nconst useFlowController = (\n\toptions: UseFlowControllerOptions,\n): UseFlowControllerReturn => {\n\tconst {\n\t\tflowRun,\n\t\topenFlow,\n\t\tprerenderFlow,\n\t\tprefetchOnMount = false,\n\t\thideCloseButton,\n\t} = options;\n\tconst requiresContainer = options.mode === \"container\";\n\tconst customContainerRef = useRef<HTMLDivElement | null>(null);\n\n\t/** Flow state from loader events; dimensions are used only for prepared-view lifecycle. */\n\tconst flowState = useFlowStateStoreValue<FlowState>(\n\t\tflowRun,\n\t\t(state) => state,\n\t\t() => FALLBACK_FLOW_STATE,\n\t);\n\n\tconst open = useCallback(\n\t\t(openOptions?: UseFlowOpenOptions): Promise<void> =>\n\t\t\topenFlow({\n\t\t\t\tcontainer: requiresContainer\n\t\t\t\t\t? (customContainerRef.current ?? null)\n\t\t\t\t\t: undefined,\n\t\t\t\thideCloseButton,\n\t\t\t\tmetadata: openOptions?.metadata,\n\t\t\t}),\n\t\t[hideCloseButton, openFlow, requiresContainer],\n\t);\n\n\tconst close = useCallback((): Promise<void> => flowRun.close(), [flowRun]);\n\tconst prefetch = useCallback(\n\t\t(): Promise<void> => flowRun.prefetch(),\n\t\t[flowRun],\n\t);\n\n\tconst setOpen = useCallback(\n\t\t(next: boolean): Promise<void> => (next ? open() : close()),\n\t\t[close, open],\n\t);\n\n\tconst containerRef = useCallback(\n\t\t(element: HTMLDivElement | null): void => {\n\t\t\tif (!requiresContainer) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcustomContainerRef.current = element;\n\t\t\tflowRun.setContainer(element);\n\t\t},\n\t\t[flowRun, requiresContainer],\n\t);\n\n\tconst hasPreparedCustomView = hasPreparedFlowState(flowState);\n\tconst shouldRenderContainer =\n\t\trequiresContainer &&\n\t\t(flowState.isOpen || (flowState.isLoading && hasPreparedCustomView));\n\n\tuseEffect(() => {\n\t\tif (!prefetchOnMount) {\n\t\t\treturn;\n\t\t}\n\t\tvoid prefetch().catch(() => {});\n\t}, [prefetch, prefetchOnMount]);\n\n\treturn {\n\t\tisOpen: flowState.isOpen,\n\t\tisLoading: flowState.isLoading,\n\t\tshouldRenderContainer,\n\t\tsetOpen,\n\t\topen,\n\t\tclose,\n\t\tprefetch,\n\t\tprerender: (): Promise<void> =>\n\t\t\tprerenderFlow({\n\t\t\t\tcontainer: requiresContainer\n\t\t\t\t\t? (customContainerRef.current ?? null)\n\t\t\t\t\t: undefined,\n\t\t\t\thideCloseButton,\n\t\t\t}),\n\t\tcontainerRef,\n\t};\n};\n\nexport function useFlowRun(\n\toptions: UseFlowRunOptions & { container?: \"default\" },\n): UseFlowReturn;\nexport function useFlowRun(\n\toptions: UseFlowRunOptions & { container: \"custom\" },\n): UseCustomFlowReturn;\nexport function useFlowRun(\n\toptions: UseFlowRunOptions,\n): UseFlowReturn | UseCustomFlowReturn;\nexport function useFlowRun(\n\toptions: UseFlowRunOptions,\n): UseFlowReturn | UseCustomFlowReturn {\n\tconst container = options.container ?? \"default\";\n\tconst initialContainerRef = useRef(container);\n\tif (initialContainerRef.current !== container) {\n\t\tthrow new Error(\n\t\t\t\"useFlow container mode cannot change while mounted; remount the hook to change it\",\n\t\t);\n\t}\n\tconst mode = container === \"custom\" ? \"container\" : \"default\";\n\tconst controller = useFlowController({\n\t\tflowRun: options.flowRun,\n\t\tmode,\n\t\topenFlow: options.openFlow,\n\t\tprerenderFlow: options.prerenderFlow,\n\t\tprefetchOnMount: options.prefetchOnMount,\n\t\thideCloseButton: options.hideCloseButton,\n\t});\n\n\tif (mode === \"container\") {\n\t\treturn {\n\t\t\tcontainer: \"custom\",\n\t\t\tisOpen: controller.isOpen,\n\t\t\tisLoading: controller.isLoading,\n\t\t\tshouldRenderContainer: controller.shouldRenderContainer,\n\t\t\topen: controller.open,\n\t\t\tclose: controller.close,\n\t\t\tprefetch: controller.prefetch,\n\t\t\tsetOpen: controller.setOpen,\n\t\t\tprerender: controller.prerender,\n\t\t\tcontainerRef: controller.containerRef,\n\t\t};\n\t}\n\n\treturn {\n\t\tcontainer: \"default\",\n\t\tisOpen: controller.isOpen,\n\t\tisLoading: controller.isLoading,\n\t\topen: controller.open,\n\t\tclose: controller.close,\n\t\tprefetch: controller.prefetch,\n\t\tprerender: controller.prerender,\n\t};\n}\n\n/**\n * @name useFlow\n * @description Open a flow in the default container or your own container.\n * @example Default container\n * ```tsx\n * const { open, isLoading } = useFlow({ flowId: \"sur_123\" });\n * await open({\n * metadata: {\n * tags: {\n * journey_stage: \"onboarding\",\n * },\n * },\n * });\n * ```\n * @example Custom container\n * ```tsx\n * const { containerRef, shouldRenderContainer, open } = useFlow({ flowId: \"sur_123\", container: \"custom\" });\n * ```\n * @see https://getuserfeedback.com/docs/guides/advanced/containers\n */\nexport function useFlow(\n\toptions: UseFlowOptions & { container?: \"default\" },\n): UseFlowReturn;\nexport function useFlow(\n\toptions: UseFlowOptions & { container: \"custom\" },\n): UseCustomFlowReturn;\nexport function useFlow(\n\toptions: UseFlowOptions,\n): UseFlowReturn | UseCustomFlowReturn {\n\tconst ctx = useContext(GetUserFeedbackContext);\n\tif (!ctx) {\n\t\tthrow new Error(\"useFlow must be used within a GetUserFeedbackProvider\");\n\t}\n\tconst flowRun = useMemo(\n\t\t() => ctx.client.flow(options.flowId),\n\t\t[ctx.client, options.flowId],\n\t);\n\tconst openFlow = useCallback(\n\t\t({ container, hideCloseButton, metadata }: FlowControllerOpenInput) =>\n\t\t\tflowRun.open(\n\t\t\t\tcontainer === undefined\n\t\t\t\t\t? { hideCloseButton, metadata }\n\t\t\t\t\t: { container, hideCloseButton, metadata },\n\t\t\t),\n\t\t[flowRun],\n\t);\n\tconst prerenderFlow = useCallback(\n\t\t({ hideCloseButton }: { hideCloseButton?: boolean }) =>\n\t\t\tflowRun.prerender({ hideCloseButton }),\n\t\t[flowRun],\n\t);\n\treturn useFlowRun({\n\t\tflowRun,\n\t\topenFlow,\n\t\tprerenderFlow,\n\t\tcontainer: options.container,\n\t\tprefetchOnMount: options.prefetchOnMount,\n\t\thideCloseButton: options.hideCloseButton,\n\t});\n}\n\n/**\n * @name useFlowContainer\n * @description Register and control the single default container for this provider subtree. Mount exactly one consumer per logical client.\n * @example Display any flow in your own dialog\n * ```tsx\n * function AppFlowContainer() {\n * const { close, containerRef, shouldRenderContainer } = useFlowContainer();\n * return (\n * <Dialog\n * open={shouldRenderContainer}\n * onOpenChange={(open) => {\n * if (!open) {\n * void close().catch((error) =>\n * console.error(\"Unable to close feedback\", error),\n * );\n * }\n * }}\n * >\n * <DialogContent>\n * <div ref={containerRef} style={{ width: \"100%\" }} />\n * </DialogContent>\n * </Dialog>\n * );\n * }\n *\n * function App() {\n * return (\n * <GetUserFeedbackProvider clientOptions={{ apiKey: \"YOUR_API_KEY\" }}>\n * <AppRoutes />\n * <AppFlowContainer />\n * </GetUserFeedbackProvider>\n * );\n * }\n * ```\n * @see https://getuserfeedback.com/docs/guides/advanced/containers\n */\nexport function useFlowContainer(): UseFlowContainerReturn {\n\tconst ctx = useContext(GetUserFeedbackContext);\n\tif (!ctx) {\n\t\tthrow new Error(\n\t\t\t\"useFlowContainer must be used within a GetUserFeedbackProvider\",\n\t\t);\n\t}\n\n\tconst {\n\t\tclient,\n\t\tdefaultFlowContainerState,\n\t\tregisterDefaultFlowContainerConsumer,\n\t\tsetDefaultFlowContainer,\n\t} = ctx;\n\tconst ownerRef = useRef<object>({});\n\tconst containerElementRef = useRef<HTMLDivElement | null>(null);\n\n\tuseEffect(\n\t\t() =>\n\t\t\tregisterDefaultFlowContainerConsumer(\n\t\t\t\townerRef.current,\n\t\t\t\tcontainerElementRef.current,\n\t\t\t),\n\t\t[registerDefaultFlowContainerConsumer],\n\t);\n\n\tconst containerRef = useCallback(\n\t\t(element: HTMLDivElement | null): void => {\n\t\t\tcontainerElementRef.current = element;\n\t\t\tsetDefaultFlowContainer(ownerRef.current, element);\n\t\t},\n\t\t[setDefaultFlowContainer],\n\t);\n\n\tconst close = useCallback((): Promise<void> => client.close(), [client]);\n\n\treturn {\n\t\tisOpen: defaultFlowContainerState.isOpen,\n\t\tisLoading: defaultFlowContainerState.isLoading,\n\t\tshouldRenderContainer: defaultFlowContainerState.shouldRenderContainer,\n\t\tclose,\n\t\tcontainerRef,\n\t};\n}\n\n/**\n * Experimental hook for submitting feedback or explicitly fetching the\n * JWT-authenticated user's feedback.\n *\n * Neither operation runs automatically. Each promise returns the corresponding\n * SDK result and rejects when the operation fails.\n *\n * @experimental\n */\nexport function useFeedback(): UseFeedbackReturn {\n\tconst ctx = useContext(GetUserFeedbackContext);\n\tif (!ctx) {\n\t\tthrow new Error(\n\t\t\t\"useFeedback must be used within a GetUserFeedbackProvider\",\n\t\t);\n\t}\n\n\tconst [pendingFetchCount, setPendingFetchCount] = useState(0);\n\tconst [pendingSubmissionCount, setPendingSubmissionCount] = useState(0);\n\tconst fetch = useCallback(\n\t\tasync (input: FetchFeedbackInput): Promise<FetchFeedbackResult> => {\n\t\t\tsetPendingFetchCount((count) => count + 1);\n\t\t\ttry {\n\t\t\t\treturn await ctx.client.feedback.fetch(input);\n\t\t\t} finally {\n\t\t\t\tsetPendingFetchCount((count) => count - 1);\n\t\t\t}\n\t\t},\n\t\t[ctx.client],\n\t);\n\tconst submit = useCallback(\n\t\tasync (input: FeedbackInput): Promise<SubmitFeedbackResult> => {\n\t\t\tsetPendingSubmissionCount((count) => count + 1);\n\t\t\ttry {\n\t\t\t\treturn await ctx.client.feedback.submit(input);\n\t\t\t} finally {\n\t\t\t\tsetPendingSubmissionCount((count) => count - 1);\n\t\t\t}\n\t\t},\n\t\t[ctx.client],\n\t);\n\n\treturn {\n\t\tfetch,\n\t\tisFetching: pendingFetchCount > 0,\n\t\tisSubmitting: pendingSubmissionCount > 0,\n\t\tsubmit,\n\t};\n}\n\n/**\n * Hook for accessing the getuserfeedback client instance.\n *\n * @see https://getuserfeedback.com/docs/reference/react-sdk-reference\n * @see https://getuserfeedback.com/docs/reference/events\n *\n * @example Basic usage\n * ```tsx\n * const client = useGetUserFeedback();\n *\n * async function handleLogin() {\n * await client.identify(\"user-123\", { email: \"user@example.com\" });\n * }\n *\n * async function handleCheckoutStarted() {\n * await client.track(\"Checkout Started\", { plan: \"pro\" });\n * }\n *\n * async function handleLogout() {\n * await client.reset();\n * }\n * ```\n *\n * @example Override color scheme\n * ```tsx\n * const client = useGetUserFeedback();\n * await client.configure({ colorScheme: \"dark\" });\n * ```\n */\nexport function useGetUserFeedback(): Client {\n\tconst ctx = useContext(GetUserFeedbackContext);\n\tif (!ctx) {\n\t\tthrow new Error(\n\t\t\t\"useGetUserFeedback must be used within a GetUserFeedbackProvider\",\n\t\t);\n\t}\n\treturn ctx.client;\n}\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "3F0C5DDA586FBA5164756E2164756E21",
9
+ "names": []
10
+ }
package/dist/index.d.ts CHANGED
@@ -1,7 +1,12 @@
1
- import { ReactNode, ReactElement } from 'react';
2
1
  import { ClientOptions, OpenFlowOptions, FetchFeedbackInput, FetchFeedbackResult, FeedbackInput, SubmitFeedbackResult, Client } from '@getuserfeedback/sdk';
2
+ export { ActionsConfig, LinksConfig } from '@getuserfeedback/sdk';
3
+ import { ReactNode, ReactElement } from 'react';
3
4
 
4
- /** Return value for useFeedback(). */
5
+ /**
6
+ * Return value for the experimental `useFeedback()` hook.
7
+ *
8
+ * @experimental
9
+ */
5
10
  interface UseFeedbackReturn {
6
11
  /** Fetch feedback matching each selector for the JWT-authenticated user. */
7
12
  fetch: (input: FetchFeedbackInput) => Promise<FetchFeedbackResult>;
@@ -49,6 +54,8 @@ interface UseFlowReturn {
49
54
  open: (options?: UseFlowOpenOptions) => Promise<void>;
50
55
  /** Close the flow. */
51
56
  close: () => Promise<void>;
57
+ /** Prefetches the flow resources without opening it. */
58
+ prefetch: () => Promise<void>;
52
59
  /** Prerendering warms up the flow for instant display later. */
53
60
  prerender: () => Promise<void>;
54
61
  }
@@ -65,7 +72,13 @@ interface UseCustomFlowReturn {
65
72
  shouldRenderContainer: boolean;
66
73
  /** Open the flow in the custom container. */
67
74
  open: (options?: UseFlowOpenOptions) => Promise<void>;
68
- /** Open the flow when `true`, close when `false`. */
75
+ /** Close the flow. */
76
+ close: () => Promise<void>;
77
+ /** Prefetches the flow resources without opening it. */
78
+ prefetch: () => Promise<void>;
79
+ /**
80
+ * @deprecated Use `open()` or `close()` instead. Kept for compatibility.
81
+ */
69
82
  setOpen: (next: boolean) => Promise<void>;
70
83
  /** Prerendering warms up the flow for instant display later. */
71
84
  prerender: () => Promise<void>;
@@ -103,9 +116,8 @@ interface GetUserFeedbackProviderProps {
103
116
  }
104
117
  /**
105
118
  * Provider for getuserfeedback React hooks.
106
- * Wrap your app (or a subtree) so `useFeedback`, `useFlow`,
107
- * `useFlowContainer`, and `useGetUserFeedback` can access a client
108
- * created from `clientOptions`.
119
+ * Wrap your app (or a subtree) so `useFlow`, `useFlowContainer`, and
120
+ * `useGetUserFeedback` can access a client created from `clientOptions`.
109
121
  *
110
122
  * If your app uses `useFlowContainer()`, flows using the default presentation
111
123
  * in this subtree (including targeting-engine opens) target that container.
@@ -130,7 +142,16 @@ interface GetUserFeedbackProviderProps {
130
142
  * const { close, containerRef, shouldRenderContainer } = useFlowContainer();
131
143
  *
132
144
  * return (
133
- * <Dialog open={shouldRenderContainer} onOpenChange={(open) => { if (!open) void close(); }}>
145
+ * <Dialog
146
+ * open={shouldRenderContainer}
147
+ * onOpenChange={(open) => {
148
+ * if (!open) {
149
+ * void close().catch((error) =>
150
+ * console.error("Unable to close feedback", error),
151
+ * );
152
+ * }
153
+ * }}
154
+ * >
134
155
  * <DialogContent>
135
156
  * <div ref={containerRef} style={{ width: "100%" }} />
136
157
  * </DialogContent>
@@ -151,8 +172,8 @@ interface GetUserFeedbackProviderProps {
151
172
  declare function GetUserFeedbackProvider({ children, clientOptions, }: GetUserFeedbackProviderProps): ReactElement;
152
173
  /**
153
174
  * @name useFlow
154
- * @description Open a Widget survey in the default floating container or your own container.
155
- * @example Default (floating) container
175
+ * @description Open a flow in the default container or your own container.
176
+ * @example Default container
156
177
  * ```tsx
157
178
  * const { open, isLoading } = useFlow({ flowId: "sur_123" });
158
179
  * await open({
@@ -167,9 +188,7 @@ declare function GetUserFeedbackProvider({ children, clientOptions, }: GetUserFe
167
188
  * ```tsx
168
189
  * const { containerRef, shouldRenderContainer, open } = useFlow({ flowId: "sur_123", container: "custom" });
169
190
  * ```
170
- * @see docs/custom-wrapper.md — integration levels 1 and 2, the default floating
171
- * container and the per-flow custom container, cited by path so the internal
172
- * set stays reachable. Level 3 is {@link useFlowContainer}.
191
+ * @see https://getuserfeedback.com/docs/guides/advanced/containers
173
192
  */
174
193
  declare function useFlow(options: UseFlowOptions & {
175
194
  container?: "default";
@@ -185,7 +204,16 @@ declare function useFlow(options: UseFlowOptions & {
185
204
  * function AppFlowContainer() {
186
205
  * const { close, containerRef, shouldRenderContainer } = useFlowContainer();
187
206
  * return (
188
- * <Dialog open={shouldRenderContainer} onOpenChange={(open) => { if (!open) void close(); }}>
207
+ * <Dialog
208
+ * open={shouldRenderContainer}
209
+ * onOpenChange={(open) => {
210
+ * if (!open) {
211
+ * void close().catch((error) =>
212
+ * console.error("Unable to close feedback", error),
213
+ * );
214
+ * }
215
+ * }}
216
+ * >
189
217
  * <DialogContent>
190
218
  * <div ref={containerRef} style={{ width: "100%" }} />
191
219
  * </DialogContent>
@@ -202,14 +230,17 @@ declare function useFlow(options: UseFlowOptions & {
202
230
  * );
203
231
  * }
204
232
  * ```
205
- * @see docs/specs/2026-08-28-sdk-flow-container-contract.md
233
+ * @see https://getuserfeedback.com/docs/guides/advanced/containers
206
234
  */
207
235
  declare function useFlowContainer(): UseFlowContainerReturn;
208
236
  /**
209
- * Submit feedback or explicitly fetch the JWT-authenticated user's feedback.
237
+ * Experimental hook for submitting feedback or explicitly fetching the
238
+ * JWT-authenticated user's feedback.
210
239
  *
211
240
  * Neither operation runs automatically. Each promise returns the corresponding
212
241
  * SDK result and rejects when the operation fails.
242
+ *
243
+ * @experimental
213
244
  */
214
245
  declare function useFeedback(): UseFeedbackReturn;
215
246
  /**
@@ -222,14 +253,17 @@ declare function useFeedback(): UseFeedbackReturn;
222
253
  * ```tsx
223
254
  * const client = useGetUserFeedback();
224
255
  *
225
- * // on login
226
- * client.identify('user-123', { email: 'user@example.com' });
256
+ * async function handleLogin() {
257
+ * await client.identify("user-123", { email: "user@example.com" });
258
+ * }
227
259
  *
228
- * // track a product event
229
- * client.track("Checkout Started", { plan: "pro" });
260
+ * async function handleCheckoutStarted() {
261
+ * await client.track("Checkout Started", { plan: "pro" });
262
+ * }
230
263
  *
231
- * // on logout
232
- * client.reset();
264
+ * async function handleLogout() {
265
+ * await client.reset();
266
+ * }
233
267
  * ```
234
268
  *
235
269
  * @example Override color scheme
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import{b as t,d as r,e as _,f as s,g as n}from"./chunk-thzce5rj.js";var e="0.9.6".trim(),o=e.length>0?e:"0.0.0-local";export{t as GetUserFeedbackProvider,o as REACT_SDK_VERSION,s as useFeedback,r as useFlow,_ as useFlowContainer,n as useGetUserFeedback};
2
+ import{b as t,d as r,e as s,f as n,g as _}from"./chunk-a3b04qn2.js";var e="0.11.0".trim(),o=e.length>0?e:"0.0.0-local";export{t as GetUserFeedbackProvider,o as REACT_SDK_VERSION,n as useFeedback,r as useFlow,s as useFlowContainer,_ as useGetUserFeedback};
3
3
 
4
- //# debugId=BF76C7ECBC40875264756E2164756E21
4
+ //# debugId=F9DD5B92FDB8C0E864756E2164756E21
5
5
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -4,7 +4,7 @@
4
4
  "sourcesContent": [
5
5
  "declare const __GX_REACT_SDK_VERSION__: string | undefined;\n\nconst reactSdkVersion =\n\ttypeof __GX_REACT_SDK_VERSION__ === \"string\"\n\t\t? __GX_REACT_SDK_VERSION__.trim()\n\t\t: \"\";\n\n// Build scripts inject __GX_REACT_SDK_VERSION__ for published artifacts.\n// Source-linked workspace usage may not inject defines, so keep a safe fallback.\nexport const REACT_SDK_VERSION =\n\treactSdkVersion.length > 0 ? reactSdkVersion : \"0.0.0-local\";\n"
6
6
  ],
7
- "mappings": ";oEAEA,IAAM,EAEF,QAAyB,KAAK,EAKrB,EACZ,EAAgB,OAAS,EAAI,EAAkB",
8
- "debugId": "BF76C7ECBC40875264756E2164756E21",
7
+ "mappings": ";oEAEA,IAAM,EAEF,SAAyB,KAAK,EAKrB,EACZ,EAAgB,OAAS,EAAI,EAAkB",
8
+ "debugId": "F9DD5B92FDB8C0E864756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -23,6 +23,8 @@ interface UseFlowReturn {
23
23
  open: (options?: UseFlowOpenOptions) => Promise<void>;
24
24
  /** Close the flow. */
25
25
  close: () => Promise<void>;
26
+ /** Prefetches the flow resources without opening it. */
27
+ prefetch: () => Promise<void>;
26
28
  /** Prerendering warms up the flow for instant display later. */
27
29
  prerender: () => Promise<void>;
28
30
  }
@@ -39,7 +41,13 @@ interface UseCustomFlowReturn {
39
41
  shouldRenderContainer: boolean;
40
42
  /** Open the flow in the custom container. */
41
43
  open: (options?: UseFlowOpenOptions) => Promise<void>;
42
- /** Open the flow when `true`, close when `false`. */
44
+ /** Close the flow. */
45
+ close: () => Promise<void>;
46
+ /** Prefetches the flow resources without opening it. */
47
+ prefetch: () => Promise<void>;
48
+ /**
49
+ * @deprecated Use `open()` or `close()` instead. Kept for compatibility.
50
+ */
43
51
  setOpen: (next: boolean) => Promise<void>;
44
52
  /** Prerendering warms up the flow for instant display later. */
45
53
  prerender: () => Promise<void>;
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import{a as s,c as i}from"../chunk-thzce5rj.js";import{createInlineFlow as F}from"@getuserfeedback/sdk/internal/inline-flow";import{useCallback as l,useContext as p,useRef as f,useState as a}from"react";function R(t){let n=p(s);if(!n)throw Error("useFlow must be used within a GetUserFeedbackProvider");if(f(n.client).current!==n.client)throw Error("useFlow must be remounted when the GetUserFeedbackProvider client changes");let[e]=a(()=>F(n.client,t.flow)),u=l(({container:o,hideCloseButton:r,metadata:c})=>{if(o!==void 0)e.setContainer(o);return e.open({hideCloseButton:r,metadata:c})},[e]),w=l(({container:o,hideCloseButton:r})=>{if(o!==void 0)e.setContainer(o);return e.prerender({hideCloseButton:r})},[e]);return i({flowRun:e,openFlow:u,prerenderFlow:w,container:t.container,prefetchOnMount:t.prefetchOnMount,hideCloseButton:t.hideCloseButton})}export{R as useFlow};
2
+ import{a as s,c as i}from"../chunk-a3b04qn2.js";import{createInlineFlow as F}from"@getuserfeedback/sdk/internal/inline-flow";import{useCallback as l,useContext as p,useRef as f,useState as a}from"react";function R(t){let n=p(s);if(!n)throw Error("useFlow must be used within a GetUserFeedbackProvider");if(f(n.client).current!==n.client)throw Error("useFlow must be remounted when the GetUserFeedbackProvider client changes");let[e]=a(()=>F(n.client,t.flow)),u=l(({container:o,hideCloseButton:r,metadata:c})=>{if(o!==void 0)e.setContainer(o);return e.open({hideCloseButton:r,metadata:c})},[e]),w=l(({container:o,hideCloseButton:r})=>{if(o!==void 0)e.setContainer(o);return e.prerender({hideCloseButton:r})},[e]);return i({flowRun:e,openFlow:u,prerenderFlow:w,container:t.container,prefetchOnMount:t.prefetchOnMount,hideCloseButton:t.hideCloseButton})}export{R as useFlow};
3
3
 
4
4
  //# debugId=49A3C1D11CF83FD564756E2164756E21
5
5
  //# sourceMappingURL=inline-flow.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getuserfeedback/react",
3
- "version": "0.9.6",
3
+ "version": "0.11.0",
4
4
  "description": "getuserfeedback React SDK",
5
5
  "keywords": [
6
6
  "getuserfeedback",
@@ -45,14 +45,15 @@
45
45
  "lint": "biome check ."
46
46
  },
47
47
  "dependencies": {
48
- "@getuserfeedback/sdk": "^0.18.0"
48
+ "@getuserfeedback/sdk": "^0.19.0"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "react": ">=18.0.0"
52
52
  },
53
53
  "devDependencies": {
54
+ "@typescript/typescript6": "^6.0.2",
54
55
  "rollup": "^4.57.1",
55
- "rollup-plugin-dts": "^6.3.0",
56
+ "rollup-plugin-dts": "^6.5.1",
56
57
  "react-dom": "*"
57
58
  }
58
59
  }
@@ -1,6 +0,0 @@
1
- "use client";
2
- import{createClient as P}from"@getuserfeedback/sdk";import{createContext as L,useCallback as u,useContext as C,useEffect as U,useMemo as R,useRef as p,useState as S,useSyncExternalStore as x}from"react";import{jsx as B}from"react/jsx-runtime";var g={isOpen:!1,isLoading:!1,shouldRenderContainer:!1},E=(e)=>({isOpen:e.isOpen,isLoading:e.isLoading}),O=(e)=>typeof e.width==="number"&&typeof e.height==="number",T=(e,t)=>e.isOpen===t.isOpen&&e.isLoading===t.isLoading&&O(e)===O(t),D={isOpen:!1,isLoading:!1,width:void 0,height:void 0};function M(e){let t=p(e.getFlowState());return u(()=>{let o=e.getFlowState(),a=t.current;if(T(a,o))return a;return t.current=o,o},[e])}function v(e,t,o){let a=M(e),n=p(null),s=p(null),r=u(()=>{let i=a();if(n.current===i){let c=s.current;if(c!==null)return c}let l=t(i);return n.current=i,s.current=l,l},[a,t]);return x((i)=>e.subscribeFlowState(()=>{i()},{emitInitial:!1}),r,o)}var h=L(null),m=new WeakMap,I=(e,t)=>e<t?-1:e>t?1:0,y=(e)=>{if(e!==void 0&&!Array.isArray(e))return null;let t=[],o=new Set,a=!1;for(let n of e??[]){if(typeof n!=="object"||n===null)return null;let s=Reflect.get(n,"kind");if(s==="open-url"){if(a||typeof Reflect.get(n,"handler")!=="function")return null;a=!0,t.push("open-url");continue}if(s!=="custom")return null;let r=Reflect.get(n,"key"),i=Reflect.get(n,"version");if(typeof r!=="string"||r.trim().length===0||!Number.isSafeInteger(i)||i<=0||typeof Reflect.get(n,"handler")!=="function")return null;let l=`custom:${JSON.stringify([r.trim(),i])}`;if(o.has(l))return null;o.add(l),t.push(l)}return JSON.stringify(t.sort(I))};function K({children:e,clientOptions:t}){let o=p(y(t.actions)),a=y(t.actions);if(a!==null&&o.current!==null&&a!==o.current)throw Error("GetUserFeedbackProvider clientOptions.actions definitions cannot change after mount. Keep each custom key and version fixed for the provider lifetime; handler functions may change.");let n=P(t),s=p(null),r=v(n,E,()=>g),i=u((d,w)=>{if(s.current!==d||m.get(n)!==d)return;n.setDefaultContainerPolicy({kind:"hostContainer",host:w,sharing:"perFlowRun"})},[n]),l=u((d,w)=>{let b=m.get(n);if(b!==void 0&&b!==d)throw Error("Only one useFlowContainer consumer can be mounted for a getuserfeedback client");return m.set(n,d),s.current=d,n.setDefaultContainerPolicy({kind:"hostContainer",host:w,sharing:"perFlowRun"}),()=>{if(s.current!==d||m.get(n)!==d)return;s.current=null,m.delete(n),n.setDefaultContainerPolicy({kind:"floating"})}},[n]),c=R(()=>{if(!r.isOpen&&!r.isLoading)return g;return{isOpen:r.isOpen,isLoading:r.isLoading,shouldRenderContainer:!0}},[r]),f=R(()=>({client:n,apiKey:t.apiKey,setDefaultFlowContainer:i,registerDefaultFlowContainerConsumer:l,defaultFlowContainerState:c}),[n,t.apiKey,c,l,i]);return B(h.Provider,{value:f,children:e})}var G=(e)=>{let{flowRun:t,openFlow:o,prerenderFlow:a,prefetchOnMount:n=!1,hideCloseButton:s}=e,r=e.mode==="container",i=p(null),l=v(t,(F)=>F,()=>D),c=u((F)=>o({container:r?i.current??null:void 0,hideCloseButton:s,metadata:F?.metadata}),[s,o,r]),f=u(()=>t.close(),[t]),d=u((F)=>F?c():f(),[f,c]),w=u((F)=>{if(!r)return;i.current=F,t.setContainer(F)},[t,r]),b=O(l),k=r&&(l.isOpen||l.isLoading&&b);return U(()=>{if(!n)return;t.prefetch()},[t,n]),{isOpen:l.isOpen,isLoading:l.isLoading,shouldRenderContainer:k,setOpen:d,open:c,close:f,prerender:()=>a({container:r?i.current??null:void 0,hideCloseButton:s}),containerRef:w}};function H(e){let t=e.container??"default";if(p(t).current!==t)throw Error("useFlow container mode cannot change while mounted; remount the hook to change it");let a=t==="custom"?"container":"default",n=G({flowRun:e.flowRun,mode:a,openFlow:e.openFlow,prerenderFlow:e.prerenderFlow,prefetchOnMount:e.prefetchOnMount,hideCloseButton:e.hideCloseButton});if(a==="container")return{container:"custom",isOpen:n.isOpen,isLoading:n.isLoading,shouldRenderContainer:n.shouldRenderContainer,open:n.open,setOpen:n.setOpen,prerender:n.prerender,containerRef:n.containerRef};return{container:"default",isOpen:n.isOpen,isLoading:n.isLoading,open:n.open,close:n.close,prerender:n.prerender}}function N(e){let t=C(h);if(!t)throw Error("useFlow must be used within a GetUserFeedbackProvider");let o=R(()=>t.client.flow(e.flowId),[t.client,e.flowId]),a=u(({container:s,hideCloseButton:r,metadata:i})=>o.open(s===void 0?{hideCloseButton:r,metadata:i}:{container:s,hideCloseButton:r,metadata:i}),[o]),n=u(({hideCloseButton:s})=>o.prerender({hideCloseButton:s}),[o]);return H({flowRun:o,openFlow:a,prerenderFlow:n,container:e.container,prefetchOnMount:e.prefetchOnMount,hideCloseButton:e.hideCloseButton})}function V(){let e=C(h);if(!e)throw Error("useFlowContainer must be used within a GetUserFeedbackProvider");let{client:t,defaultFlowContainerState:o,registerDefaultFlowContainerConsumer:a,setDefaultFlowContainer:n}=e,s=p({}),r=p(null);U(()=>a(s.current,r.current),[a]);let i=u((c)=>{r.current=c,n(s.current,c)},[n]),l=u(()=>t.close(),[t]);return{isOpen:o.isOpen,isLoading:o.isLoading,shouldRenderContainer:o.shouldRenderContainer,close:l,containerRef:i}}function _(){let e=C(h);if(!e)throw Error("useFeedback must be used within a GetUserFeedbackProvider");let[t,o]=S(0),[a,n]=S(0),s=u(async(i)=>{o((l)=>l+1);try{return await e.client.feedback.fetch(i)}finally{o((l)=>l-1)}},[e.client]),r=u(async(i)=>{n((l)=>l+1);try{return await e.client.feedback.submit(i)}finally{n((l)=>l-1)}},[e.client]);return{fetch:s,isFetching:t>0,isSubmitting:a>0,submit:r}}function W(){let e=C(h);if(!e)throw Error("useGetUserFeedback must be used within a GetUserFeedbackProvider");return e.client}
3
- export{h as a,K as b,H as c,N as d,V as e,_ as f,W as g};
4
-
5
- //# debugId=86193C13A9FBB95364756E2164756E21
6
- //# sourceMappingURL=chunk-thzce5rj.js.map
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/client.tsx"],
4
- "sourcesContent": [
5
- "\"use client\";\n\nimport {\n\ttype Client,\n\ttype ClientOptions,\n\tcreateClient,\n\ttype FeedbackInput,\n\ttype FetchFeedbackInput,\n\ttype FetchFeedbackResult,\n\ttype FlowRun,\n\ttype FlowState,\n\ttype OpenFlowOptions as SdkOpenFlowOptions,\n\ttype SubmitFeedbackResult,\n} from \"@getuserfeedback/sdk\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport {\n\tcreateContext,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n\tuseSyncExternalStore,\n} from \"react\";\n\n/** Return value for useFeedback(). */\nexport interface UseFeedbackReturn {\n\t/** Fetch feedback matching each selector for the JWT-authenticated user. */\n\tfetch: (input: FetchFeedbackInput) => Promise<FetchFeedbackResult>;\n\t/** True while one or more fetches from this hook are pending. */\n\tisFetching: boolean;\n\t/** True while one or more submissions from this hook are pending. */\n\tisSubmitting: boolean;\n\t/** Submit feedback about the current app or a specific target. */\n\tsubmit: (input: FeedbackInput) => Promise<SubmitFeedbackResult>;\n}\n\n/**\n * Options for useFlow().\n */\nexport interface UseFlowOptions {\n\t/** The flow/survey ID to control. */\n\tflowId: string;\n\t/** Prefetch the flow resources on mount so it opens faster. Default `false`. */\n\tprefetchOnMount?: boolean;\n\t/**\n\t * Where the flow mounts: `\"default\"` (floating container) or `\"custom\"` (your container via containerRef).\n\t * Default `\"default\"`. Remount the hook to change this mode.\n\t */\n\tcontainer?: \"default\" | \"custom\";\n\t/** When true, the view does not show a close button. */\n\thideCloseButton?: boolean;\n}\n\ntype UseFlowPresentationOptions = Pick<\n\tUseFlowOptions,\n\t\"container\" | \"hideCloseButton\" | \"prefetchOnMount\"\n>;\n\n/**\n * Per-open options for useFlow(). These apply to the specific response created\n * by that open action and do not affect prerendering.\n */\nexport interface UseFlowOpenOptions {\n\t/** Optional response metadata to preserve with the eventual submission. */\n\tmetadata?: SdkOpenFlowOptions[\"metadata\"];\n}\n\n/**\n * Return value for useFlow() when container is `\"default\"`: state and callbacks for the floating flow.\n */\nexport interface UseFlowReturn {\n\treadonly container: \"default\";\n\t/** True when the flow is visible. */\n\tisOpen: boolean;\n\t/** True after open is requested while the flow is not visible yet. */\n\tisLoading: boolean;\n\t/** Open the flow. */\n\topen: (options?: UseFlowOpenOptions) => Promise<void>;\n\t/** Close the flow. */\n\tclose: () => Promise<void>;\n\t/** Prerendering warms up the flow for instant display later. */\n\tprerender: () => Promise<void>;\n}\n\n/**\n * Return value for useFlow() when container is `\"custom\"`: state and callbacks for host-managed container flows.\n */\nexport interface UseCustomFlowReturn {\n\treadonly container: \"custom\";\n\t/** True when the flow is visible. */\n\tisOpen: boolean;\n\t/** True after open is requested while the flow is not visible yet. */\n\tisLoading: boolean;\n\t/** True when your host UI should render the custom container element. */\n\tshouldRenderContainer: boolean;\n\t/** Open the flow in the custom container. */\n\topen: (options?: UseFlowOpenOptions) => Promise<void>;\n\t/** Open the flow when `true`, close when `false`. */\n\tsetOpen: (next: boolean) => Promise<void>;\n\t/** Prerendering warms up the flow for instant display later. */\n\tprerender: () => Promise<void>;\n\t/** Ref callback: attach this to the container element where the flow should render. */\n\tcontainerRef: (element: HTMLDivElement | null) => void;\n}\n\n/**\n * Return value for useFlowContainer(): container ref and aggregate flow state\n * for flows using the default presentation in the same logical client\n * (including targeting-engine opens). Mount exactly one consumer per logical\n * client.\n */\nexport interface UseFlowContainerReturn {\n\t/** True when any flow is visible. */\n\tisOpen: boolean;\n\t/** True after any flow open is requested while the flow is not visible yet. */\n\tisLoading: boolean;\n\t/** True when your host UI should render the provider-wide flow container. */\n\tshouldRenderContainer: boolean;\n\t/** Close all open flows owned by this logical client. */\n\tclose: () => Promise<void>;\n\t/** Ref callback for the provider-wide flow container element. */\n\tcontainerRef: (element: HTMLDivElement | null) => void;\n}\n\ntype InstanceFlowRenderState = {\n\tisOpen: boolean;\n\tisLoading: boolean;\n};\n\ntype DefaultFlowContainerState = {\n\tisOpen: boolean;\n\tisLoading: boolean;\n\tshouldRenderContainer: boolean;\n};\n\nconst DEFAULT_FLOW_CONTAINER_STATE: DefaultFlowContainerState = {\n\tisOpen: false,\n\tisLoading: false,\n\tshouldRenderContainer: false,\n};\n\nconst toInstanceFlowRenderState = (\n\tstate: FlowState,\n): InstanceFlowRenderState => ({\n\tisOpen: state.isOpen,\n\tisLoading: state.isLoading,\n});\n\nconst hasPreparedFlowState = (state: FlowState): boolean =>\n\ttypeof state.width === \"number\" && typeof state.height === \"number\";\n\nconst isSameFlowLifecycleState = (\n\ta: Pick<FlowState, \"isOpen\" | \"isLoading\" | \"width\" | \"height\">,\n\tb: Pick<FlowState, \"isOpen\" | \"isLoading\" | \"width\" | \"height\">,\n): boolean =>\n\ta.isOpen === b.isOpen &&\n\ta.isLoading === b.isLoading &&\n\thasPreparedFlowState(a) === hasPreparedFlowState(b);\n\ntype FlowStateStore = {\n\tgetFlowState: () => FlowState;\n\tsubscribeFlowState: (\n\t\tlistener: (state: FlowState) => void,\n\t\toptions?: { emitInitial?: boolean },\n\t) => () => void;\n};\n\nconst FALLBACK_FLOW_STATE: FlowState = {\n\tisOpen: false,\n\tisLoading: false,\n\twidth: undefined,\n\theight: undefined,\n};\n\nfunction useStableFlowStateSnapshot(store: FlowStateStore): () => FlowState {\n\tconst snapshotRef = useRef<FlowState>(store.getFlowState());\n\n\treturn useCallback((): FlowState => {\n\t\tconst next = store.getFlowState();\n\t\tconst previous = snapshotRef.current;\n\t\tif (isSameFlowLifecycleState(previous, next)) {\n\t\t\treturn previous;\n\t\t}\n\t\tsnapshotRef.current = next;\n\t\treturn next;\n\t}, [store]);\n}\n\nfunction useFlowStateStoreValue<TState>(\n\tstore: FlowStateStore,\n\tproject: (state: FlowState) => TState,\n\tgetServerSnapshot: () => TState,\n): TState {\n\tconst getFlowStateSnapshot = useStableFlowStateSnapshot(store);\n\tconst lastSourceSnapshotRef = useRef<FlowState | null>(null);\n\tconst lastProjectedSnapshotRef = useRef<TState | null>(null);\n\tconst getProjectedSnapshot = useCallback((): TState => {\n\t\tconst sourceSnapshot = getFlowStateSnapshot();\n\t\tif (lastSourceSnapshotRef.current === sourceSnapshot) {\n\t\t\tconst cachedProjectedSnapshot = lastProjectedSnapshotRef.current;\n\t\t\tif (cachedProjectedSnapshot !== null) {\n\t\t\t\treturn cachedProjectedSnapshot;\n\t\t\t}\n\t\t}\n\t\tconst projectedSnapshot = project(sourceSnapshot);\n\t\tlastSourceSnapshotRef.current = sourceSnapshot;\n\t\tlastProjectedSnapshotRef.current = projectedSnapshot;\n\t\treturn projectedSnapshot;\n\t}, [getFlowStateSnapshot, project]);\n\n\treturn useSyncExternalStore<TState>(\n\t\t(onStoreChange) =>\n\t\t\tstore.subscribeFlowState(\n\t\t\t\t() => {\n\t\t\t\t\tonStoreChange();\n\t\t\t\t},\n\t\t\t\t{ emitInitial: false },\n\t\t\t),\n\t\tgetProjectedSnapshot,\n\t\tgetServerSnapshot,\n\t);\n}\n\ntype GetUserFeedbackContextValue = {\n\tclient: Client;\n\tapiKey: string;\n\tsetDefaultFlowContainer: (owner: object, element: HTMLElement | null) => void;\n\tregisterDefaultFlowContainerConsumer: (\n\t\towner: object,\n\t\telement: HTMLElement | null,\n\t) => () => void;\n\tdefaultFlowContainerState: DefaultFlowContainerState;\n};\n\nexport const GetUserFeedbackContext =\n\tcreateContext<GetUserFeedbackContextValue | null>(null);\n\nconst flowContainerOwnerByClient = new WeakMap<Client, object>();\n\nexport interface GetUserFeedbackProviderProps {\n\t/** Application subtree that can use getuserfeedback hooks. */\n\tchildren: ReactNode;\n\t/**\n\t * Core SDK client options used to create/reuse the underlying client.\n\t * Action definitions must remain fixed for the provider's mounted\n\t * lifetime; handlers may change while their custom key and version stay\n\t * the same.\n\t */\n\tclientOptions: ClientOptions;\n}\n\nconst compareText = (left: string, right: string): number =>\n\tleft < right ? -1 : left > right ? 1 : 0;\n\nconst toActionDefinitionsKey = (\n\tactions: ClientOptions[\"actions\"],\n): string | null => {\n\tif (actions !== undefined && !Array.isArray(actions)) {\n\t\treturn null;\n\t}\n\tconst identities: string[] = [];\n\tconst customIdentities = new Set<string>();\n\tlet hasOpenUrl = false;\n\tfor (const registration of actions ?? []) {\n\t\tif (typeof registration !== \"object\" || registration === null) {\n\t\t\treturn null;\n\t\t}\n\t\tconst kind = Reflect.get(registration, \"kind\");\n\t\tif (kind === \"open-url\") {\n\t\t\tif (\n\t\t\t\thasOpenUrl ||\n\t\t\t\ttypeof Reflect.get(registration, \"handler\") !== \"function\"\n\t\t\t) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\thasOpenUrl = true;\n\t\t\tidentities.push(\"open-url\");\n\t\t\tcontinue;\n\t\t}\n\t\tif (kind !== \"custom\") {\n\t\t\treturn null;\n\t\t}\n\t\tconst key = Reflect.get(registration, \"key\");\n\t\tconst version = Reflect.get(registration, \"version\");\n\t\tif (\n\t\t\ttypeof key !== \"string\" ||\n\t\t\tkey.trim().length === 0 ||\n\t\t\t!Number.isSafeInteger(version) ||\n\t\t\tversion <= 0 ||\n\t\t\ttypeof Reflect.get(registration, \"handler\") !== \"function\"\n\t\t) {\n\t\t\treturn null;\n\t\t}\n\t\tconst identity = `custom:${JSON.stringify([key.trim(), version])}`;\n\t\tif (customIdentities.has(identity)) return null;\n\t\tcustomIdentities.add(identity);\n\t\tidentities.push(identity);\n\t}\n\treturn JSON.stringify(identities.sort(compareText));\n};\n\n/**\n * Provider for getuserfeedback React hooks.\n * Wrap your app (or a subtree) so `useFeedback`, `useFlow`,\n * `useFlowContainer`, and `useGetUserFeedback` can access a client\n * created from `clientOptions`.\n *\n * If your app uses `useFlowContainer()`, flows using the default presentation\n * in this subtree (including targeting-engine opens) target that container.\n * If the container ref is not mounted yet, loader keeps flows parked until it is.\n * Mount exactly one `useFlowContainer()` consumer per logical client. Providers\n * with the same API key and targeting context reuse that client.\n *\n * @example Basic usage\n * ```tsx\n * function App() {\n * return (\n * <GetUserFeedbackProvider clientOptions={{ apiKey: \"YOUR_API_KEY\" }}>\n * <Routes />\n * </GetUserFeedbackProvider>\n * );\n * }\n * ```\n *\n * @example Display *any* flow in your own dialog (a shadcn/ui dialog in this example):\n * ```tsx\n * function AppFlowContainer() {\n * const { close, containerRef, shouldRenderContainer } = useFlowContainer();\n *\n * return (\n * <Dialog open={shouldRenderContainer} onOpenChange={(open) => { if (!open) void close(); }}>\n * <DialogContent>\n * <div ref={containerRef} style={{ width: \"100%\" }} />\n * </DialogContent>\n * </Dialog>\n * );\n * }\n *\n * function App() {\n * return (\n * <GetUserFeedbackProvider clientOptions={{ apiKey: \"YOUR_API_KEY\" }}>\n * <AppRoutes />\n * <AppFlowContainer /> // Targeted flows display in your dialog.\n * </GetUserFeedbackProvider>\n * );\n * }\n * ```\n */\nexport function GetUserFeedbackProvider({\n\tchildren,\n\tclientOptions,\n}: GetUserFeedbackProviderProps): ReactElement {\n\tconst initialActionDefinitionsKeyRef = useRef(\n\t\ttoActionDefinitionsKey(clientOptions.actions),\n\t);\n\tconst actionDefinitionsKey = toActionDefinitionsKey(clientOptions.actions);\n\tif (\n\t\tactionDefinitionsKey !== null &&\n\t\tinitialActionDefinitionsKeyRef.current !== null &&\n\t\tactionDefinitionsKey !== initialActionDefinitionsKeyRef.current\n\t) {\n\t\tthrow new Error(\n\t\t\t\"GetUserFeedbackProvider clientOptions.actions definitions cannot change after mount. Keep each custom key and version fixed for the provider lifetime; handler functions may change.\",\n\t\t);\n\t}\n\tconst client = createClient(clientOptions);\n\tconst defaultFlowContainerOwnerRef = useRef<object | null>(null);\n\tconst instanceFlowState = useFlowStateStoreValue<InstanceFlowRenderState>(\n\t\tclient,\n\t\ttoInstanceFlowRenderState,\n\t\t() => DEFAULT_FLOW_CONTAINER_STATE,\n\t);\n\n\tconst setDefaultFlowContainer = useCallback(\n\t\t(owner: object, element: HTMLElement | null) => {\n\t\t\tif (\n\t\t\t\tdefaultFlowContainerOwnerRef.current !== owner ||\n\t\t\t\tflowContainerOwnerByClient.get(client) !== owner\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tclient.setDefaultContainerPolicy({\n\t\t\t\tkind: \"hostContainer\",\n\t\t\t\thost: element,\n\t\t\t\tsharing: \"perFlowRun\",\n\t\t\t});\n\t\t},\n\t\t[client],\n\t);\n\n\tconst registerDefaultFlowContainerConsumer = useCallback(\n\t\t(owner: object, element: HTMLElement | null) => {\n\t\t\tconst currentOwner = flowContainerOwnerByClient.get(client);\n\t\t\tif (currentOwner !== undefined && currentOwner !== owner) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Only one useFlowContainer consumer can be mounted for a getuserfeedback client\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tflowContainerOwnerByClient.set(client, owner);\n\t\t\tdefaultFlowContainerOwnerRef.current = owner;\n\t\t\tclient.setDefaultContainerPolicy({\n\t\t\t\tkind: \"hostContainer\",\n\t\t\t\thost: element,\n\t\t\t\tsharing: \"perFlowRun\",\n\t\t\t});\n\n\t\t\treturn () => {\n\t\t\t\tif (\n\t\t\t\t\tdefaultFlowContainerOwnerRef.current !== owner ||\n\t\t\t\t\tflowContainerOwnerByClient.get(client) !== owner\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tdefaultFlowContainerOwnerRef.current = null;\n\t\t\t\tflowContainerOwnerByClient.delete(client);\n\t\t\t\tclient.setDefaultContainerPolicy({ kind: \"floating\" });\n\t\t\t};\n\t\t},\n\t\t[client],\n\t);\n\n\tconst defaultFlowContainerState = useMemo<DefaultFlowContainerState>(() => {\n\t\tif (!instanceFlowState.isOpen && !instanceFlowState.isLoading) {\n\t\t\treturn DEFAULT_FLOW_CONTAINER_STATE;\n\t\t}\n\t\treturn {\n\t\t\tisOpen: instanceFlowState.isOpen,\n\t\t\tisLoading: instanceFlowState.isLoading,\n\t\t\tshouldRenderContainer: true,\n\t\t};\n\t}, [instanceFlowState]);\n\n\tconst contextValue = useMemo(\n\t\t() => ({\n\t\t\tclient,\n\t\t\tapiKey: clientOptions.apiKey,\n\t\t\tsetDefaultFlowContainer,\n\t\t\tregisterDefaultFlowContainerConsumer,\n\t\t\tdefaultFlowContainerState,\n\t\t}),\n\t\t[\n\t\t\tclient,\n\t\t\tclientOptions.apiKey,\n\t\t\tdefaultFlowContainerState,\n\t\t\tregisterDefaultFlowContainerConsumer,\n\t\t\tsetDefaultFlowContainer,\n\t\t],\n\t);\n\n\treturn (\n\t\t<GetUserFeedbackContext.Provider value={contextValue}>\n\t\t\t{children}\n\t\t</GetUserFeedbackContext.Provider>\n\t);\n}\n\ntype FlowControllerRun = Pick<\n\tFlowRun,\n\t\"setContainer\" | \"getFlowState\" | \"subscribeFlowState\" | \"prefetch\" | \"close\"\n>;\n\ntype FlowControllerOpenInput = {\n\tcontainer: HTMLDivElement | null | undefined;\n\tmetadata?: UseFlowOpenOptions[\"metadata\"];\n\thideCloseButton?: boolean;\n};\n\nexport type UseFlowControllerOptions = {\n\tflowRun: FlowControllerRun;\n\tmode: \"default\" | \"container\";\n\topenFlow: (input: FlowControllerOpenInput) => Promise<void>;\n\tprerenderFlow: (input: {\n\t\tcontainer: HTMLDivElement | null | undefined;\n\t\thideCloseButton?: boolean;\n\t}) => Promise<void>;\n\tprefetchOnMount?: boolean;\n\thideCloseButton?: boolean;\n};\n\ntype UseFlowControllerReturn = {\n\tisOpen: boolean;\n\tisLoading: boolean;\n\tshouldRenderContainer: boolean;\n\tsetOpen: (next: boolean) => Promise<void>;\n\topen: (options?: UseFlowOpenOptions) => Promise<void>;\n\tclose: () => Promise<void>;\n\tprerender: () => Promise<void>;\n\tcontainerRef: (element: HTMLDivElement | null) => void;\n};\n\ntype UseFlowRunOptions = UseFlowPresentationOptions & {\n\tflowRun: FlowControllerRun;\n\topenFlow: UseFlowControllerOptions[\"openFlow\"];\n\tprerenderFlow: UseFlowControllerOptions[\"prerenderFlow\"];\n};\n\nconst useFlowController = (\n\toptions: UseFlowControllerOptions,\n): UseFlowControllerReturn => {\n\tconst {\n\t\tflowRun,\n\t\topenFlow,\n\t\tprerenderFlow,\n\t\tprefetchOnMount = false,\n\t\thideCloseButton,\n\t} = options;\n\tconst requiresContainer = options.mode === \"container\";\n\tconst customContainerRef = useRef<HTMLDivElement | null>(null);\n\n\t/** Flow state from loader events; dimensions are used only for prepared-view lifecycle. */\n\tconst flowState = useFlowStateStoreValue<FlowState>(\n\t\tflowRun,\n\t\t(state) => state,\n\t\t() => FALLBACK_FLOW_STATE,\n\t);\n\n\tconst open = useCallback(\n\t\t(openOptions?: UseFlowOpenOptions): Promise<void> =>\n\t\t\topenFlow({\n\t\t\t\tcontainer: requiresContainer\n\t\t\t\t\t? (customContainerRef.current ?? null)\n\t\t\t\t\t: undefined,\n\t\t\t\thideCloseButton,\n\t\t\t\tmetadata: openOptions?.metadata,\n\t\t\t}),\n\t\t[hideCloseButton, openFlow, requiresContainer],\n\t);\n\n\tconst close = useCallback((): Promise<void> => flowRun.close(), [flowRun]);\n\n\tconst setOpen = useCallback(\n\t\t(next: boolean): Promise<void> => (next ? open() : close()),\n\t\t[close, open],\n\t);\n\n\tconst containerRef = useCallback(\n\t\t(element: HTMLDivElement | null): void => {\n\t\t\tif (!requiresContainer) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcustomContainerRef.current = element;\n\t\t\tflowRun.setContainer(element);\n\t\t},\n\t\t[flowRun, requiresContainer],\n\t);\n\n\tconst hasPreparedCustomView = hasPreparedFlowState(flowState);\n\tconst shouldRenderContainer =\n\t\trequiresContainer &&\n\t\t(flowState.isOpen || (flowState.isLoading && hasPreparedCustomView));\n\n\tuseEffect(() => {\n\t\tif (!prefetchOnMount) {\n\t\t\treturn;\n\t\t}\n\t\tflowRun.prefetch();\n\t}, [flowRun, prefetchOnMount]);\n\n\treturn {\n\t\tisOpen: flowState.isOpen,\n\t\tisLoading: flowState.isLoading,\n\t\tshouldRenderContainer,\n\t\tsetOpen,\n\t\topen,\n\t\tclose,\n\t\tprerender: (): Promise<void> =>\n\t\t\tprerenderFlow({\n\t\t\t\tcontainer: requiresContainer\n\t\t\t\t\t? (customContainerRef.current ?? null)\n\t\t\t\t\t: undefined,\n\t\t\t\thideCloseButton,\n\t\t\t}),\n\t\tcontainerRef,\n\t};\n};\n\nexport function useFlowRun(\n\toptions: UseFlowRunOptions & { container?: \"default\" },\n): UseFlowReturn;\nexport function useFlowRun(\n\toptions: UseFlowRunOptions & { container: \"custom\" },\n): UseCustomFlowReturn;\nexport function useFlowRun(\n\toptions: UseFlowRunOptions,\n): UseFlowReturn | UseCustomFlowReturn;\nexport function useFlowRun(\n\toptions: UseFlowRunOptions,\n): UseFlowReturn | UseCustomFlowReturn {\n\tconst container = options.container ?? \"default\";\n\tconst initialContainerRef = useRef(container);\n\tif (initialContainerRef.current !== container) {\n\t\tthrow new Error(\n\t\t\t\"useFlow container mode cannot change while mounted; remount the hook to change it\",\n\t\t);\n\t}\n\tconst mode = container === \"custom\" ? \"container\" : \"default\";\n\tconst controller = useFlowController({\n\t\tflowRun: options.flowRun,\n\t\tmode,\n\t\topenFlow: options.openFlow,\n\t\tprerenderFlow: options.prerenderFlow,\n\t\tprefetchOnMount: options.prefetchOnMount,\n\t\thideCloseButton: options.hideCloseButton,\n\t});\n\n\tif (mode === \"container\") {\n\t\treturn {\n\t\t\tcontainer: \"custom\",\n\t\t\tisOpen: controller.isOpen,\n\t\t\tisLoading: controller.isLoading,\n\t\t\tshouldRenderContainer: controller.shouldRenderContainer,\n\t\t\topen: controller.open,\n\t\t\tsetOpen: controller.setOpen,\n\t\t\tprerender: controller.prerender,\n\t\t\tcontainerRef: controller.containerRef,\n\t\t};\n\t}\n\n\treturn {\n\t\tcontainer: \"default\",\n\t\tisOpen: controller.isOpen,\n\t\tisLoading: controller.isLoading,\n\t\topen: controller.open,\n\t\tclose: controller.close,\n\t\tprerender: controller.prerender,\n\t};\n}\n\n/**\n * @name useFlow\n * @description Open a Widget survey in the default floating container or your own container.\n * @example Default (floating) container\n * ```tsx\n * const { open, isLoading } = useFlow({ flowId: \"sur_123\" });\n * await open({\n * metadata: {\n * tags: {\n * journey_stage: \"onboarding\",\n * },\n * },\n * });\n * ```\n * @example Custom container\n * ```tsx\n * const { containerRef, shouldRenderContainer, open } = useFlow({ flowId: \"sur_123\", container: \"custom\" });\n * ```\n * @see docs/custom-wrapper.md — integration levels 1 and 2, the default floating\n * container and the per-flow custom container, cited by path so the internal\n * set stays reachable. Level 3 is {@link useFlowContainer}.\n */\nexport function useFlow(\n\toptions: UseFlowOptions & { container?: \"default\" },\n): UseFlowReturn;\nexport function useFlow(\n\toptions: UseFlowOptions & { container: \"custom\" },\n): UseCustomFlowReturn;\nexport function useFlow(\n\toptions: UseFlowOptions,\n): UseFlowReturn | UseCustomFlowReturn {\n\tconst ctx = useContext(GetUserFeedbackContext);\n\tif (!ctx) {\n\t\tthrow new Error(\"useFlow must be used within a GetUserFeedbackProvider\");\n\t}\n\tconst flowRun = useMemo(\n\t\t() => ctx.client.flow(options.flowId),\n\t\t[ctx.client, options.flowId],\n\t);\n\tconst openFlow = useCallback(\n\t\t({ container, hideCloseButton, metadata }: FlowControllerOpenInput) =>\n\t\t\tflowRun.open(\n\t\t\t\tcontainer === undefined\n\t\t\t\t\t? { hideCloseButton, metadata }\n\t\t\t\t\t: { container, hideCloseButton, metadata },\n\t\t\t),\n\t\t[flowRun],\n\t);\n\tconst prerenderFlow = useCallback(\n\t\t({ hideCloseButton }: { hideCloseButton?: boolean }) =>\n\t\t\tflowRun.prerender({ hideCloseButton }),\n\t\t[flowRun],\n\t);\n\treturn useFlowRun({\n\t\tflowRun,\n\t\topenFlow,\n\t\tprerenderFlow,\n\t\tcontainer: options.container,\n\t\tprefetchOnMount: options.prefetchOnMount,\n\t\thideCloseButton: options.hideCloseButton,\n\t});\n}\n\n/**\n * @name useFlowContainer\n * @description Register and control the single default container for this provider subtree. Mount exactly one consumer per logical client.\n * @example Display any flow in your own dialog\n * ```tsx\n * function AppFlowContainer() {\n * const { close, containerRef, shouldRenderContainer } = useFlowContainer();\n * return (\n * <Dialog open={shouldRenderContainer} onOpenChange={(open) => { if (!open) void close(); }}>\n * <DialogContent>\n * <div ref={containerRef} style={{ width: \"100%\" }} />\n * </DialogContent>\n * </Dialog>\n * );\n * }\n *\n * function App() {\n * return (\n * <GetUserFeedbackProvider clientOptions={{ apiKey: \"YOUR_API_KEY\" }}>\n * <AppRoutes />\n * <AppFlowContainer />\n * </GetUserFeedbackProvider>\n * );\n * }\n * ```\n * @see docs/specs/2026-08-28-sdk-flow-container-contract.md\n */\nexport function useFlowContainer(): UseFlowContainerReturn {\n\tconst ctx = useContext(GetUserFeedbackContext);\n\tif (!ctx) {\n\t\tthrow new Error(\n\t\t\t\"useFlowContainer must be used within a GetUserFeedbackProvider\",\n\t\t);\n\t}\n\n\tconst {\n\t\tclient,\n\t\tdefaultFlowContainerState,\n\t\tregisterDefaultFlowContainerConsumer,\n\t\tsetDefaultFlowContainer,\n\t} = ctx;\n\tconst ownerRef = useRef<object>({});\n\tconst containerElementRef = useRef<HTMLDivElement | null>(null);\n\n\tuseEffect(\n\t\t() =>\n\t\t\tregisterDefaultFlowContainerConsumer(\n\t\t\t\townerRef.current,\n\t\t\t\tcontainerElementRef.current,\n\t\t\t),\n\t\t[registerDefaultFlowContainerConsumer],\n\t);\n\n\tconst containerRef = useCallback(\n\t\t(element: HTMLDivElement | null): void => {\n\t\t\tcontainerElementRef.current = element;\n\t\t\tsetDefaultFlowContainer(ownerRef.current, element);\n\t\t},\n\t\t[setDefaultFlowContainer],\n\t);\n\n\tconst close = useCallback((): Promise<void> => client.close(), [client]);\n\n\treturn {\n\t\tisOpen: defaultFlowContainerState.isOpen,\n\t\tisLoading: defaultFlowContainerState.isLoading,\n\t\tshouldRenderContainer: defaultFlowContainerState.shouldRenderContainer,\n\t\tclose,\n\t\tcontainerRef,\n\t};\n}\n\n/**\n * Submit feedback or explicitly fetch the JWT-authenticated user's feedback.\n *\n * Neither operation runs automatically. Each promise returns the corresponding\n * SDK result and rejects when the operation fails.\n */\nexport function useFeedback(): UseFeedbackReturn {\n\tconst ctx = useContext(GetUserFeedbackContext);\n\tif (!ctx) {\n\t\tthrow new Error(\n\t\t\t\"useFeedback must be used within a GetUserFeedbackProvider\",\n\t\t);\n\t}\n\n\tconst [pendingFetchCount, setPendingFetchCount] = useState(0);\n\tconst [pendingSubmissionCount, setPendingSubmissionCount] = useState(0);\n\tconst fetch = useCallback(\n\t\tasync (input: FetchFeedbackInput): Promise<FetchFeedbackResult> => {\n\t\t\tsetPendingFetchCount((count) => count + 1);\n\t\t\ttry {\n\t\t\t\treturn await ctx.client.feedback.fetch(input);\n\t\t\t} finally {\n\t\t\t\tsetPendingFetchCount((count) => count - 1);\n\t\t\t}\n\t\t},\n\t\t[ctx.client],\n\t);\n\tconst submit = useCallback(\n\t\tasync (input: FeedbackInput): Promise<SubmitFeedbackResult> => {\n\t\t\tsetPendingSubmissionCount((count) => count + 1);\n\t\t\ttry {\n\t\t\t\treturn await ctx.client.feedback.submit(input);\n\t\t\t} finally {\n\t\t\t\tsetPendingSubmissionCount((count) => count - 1);\n\t\t\t}\n\t\t},\n\t\t[ctx.client],\n\t);\n\n\treturn {\n\t\tfetch,\n\t\tisFetching: pendingFetchCount > 0,\n\t\tisSubmitting: pendingSubmissionCount > 0,\n\t\tsubmit,\n\t};\n}\n\n/**\n * Hook for accessing the getuserfeedback client instance.\n *\n * @see https://getuserfeedback.com/docs/reference/react-sdk-reference\n * @see https://getuserfeedback.com/docs/reference/events\n *\n * @example Basic usage\n * ```tsx\n * const client = useGetUserFeedback();\n *\n * // on login\n * client.identify('user-123', { email: 'user@example.com' });\n *\n * // track a product event\n * client.track(\"Checkout Started\", { plan: \"pro\" });\n *\n * // on logout\n * client.reset();\n * ```\n *\n * @example Override color scheme\n * ```tsx\n * const client = useGetUserFeedback();\n * await client.configure({ colorScheme: \"dark\" });\n * ```\n */\nexport function useGetUserFeedback(): Client {\n\tconst ctx = useContext(GetUserFeedbackContext);\n\tif (!ctx) {\n\t\tthrow new Error(\n\t\t\t\"useGetUserFeedback must be used within a GetUserFeedbackProvider\",\n\t\t);\n\t}\n\treturn ctx.client;\n}\n"
6
- ],
7
- "mappings": "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",
8
- "debugId": "86193C13A9FBB95364756E2164756E21",
9
- "names": []
10
- }