@getuserfeedback/react 0.11.12 → 0.12.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/dist/chunk-d1zm9cbm.js +6 -0
- package/dist/chunk-d1zm9cbm.js.map +10 -0
- package/dist/index.d.ts +7 -7
- package/dist/index.js +2 -2
- package/dist/index.js.map +2 -2
- package/dist/internal/inline-flow.d.ts +3 -3
- package/dist/internal/inline-flow.js +1 -1
- package/package.json +4 -5
- package/dist/chunk-tqj5rwar.js +0 -6
- package/dist/chunk-tqj5rwar.js.map +0 -10
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import{createClient as A}from"@getuserfeedback/sdk";import{createActionRegistry as K}from"@getuserfeedback/sdk/internal/action-registry";import{createReactContainerOwner as T,registerReactContainer as v}from"@getuserfeedback/sdk/internal/react-container";import{createContext as N,useCallback as C,useContext as U,useEffect as M,useMemo as P,useRef as R,useState as k,useSyncExternalStore as V}from"react";import{jsx as z}from"react/jsx-runtime";var D={isOpen:!1,isLoading:!1,shouldRenderContainer:!1},_=(s)=>({isOpen:s.isOpen,isLoading:s.isLoading}),L=(s)=>typeof s.width==="number"&&typeof s.height==="number",W=(s,u)=>s.isOpen===u.isOpen&&s.isLoading===u.isLoading&&L(s)===L(u),j={isOpen:!1,isLoading:!1,width:void 0,height:void 0};function q(s){let u=R(s.getFlowState());return C(()=>{let c=s.getFlowState(),w=u.current;if(W(w,c))return w;return u.current=c,c},[s])}function I(s,u,c){let w=q(s),a=R(null),d=R(null),p=C(()=>{let F=w();if(a.current===F){let m=d.current;if(m!==null)return m}let f=u(F);return a.current=F,d.current=f,f},[w,u]);return V((F)=>s.subscribeFlowState(()=>{F()},{emitInitial:!1}),p,c)}var e=N(null),S=new WeakMap,E=(s)=>{try{return JSON.stringify(K(s).listRegistrationIdentities())}catch{return null}};function n({children:s,clientOptions:u}){let c=R(E(u.actions)),w=E(u.actions);if(w!==null&&c.current!==null&&w!==c.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 a=A(u),d=R(null),p=I(a,_,()=>D),F=C((h,O)=>{if(d.current!==h||S.get(a)!==h)return;v(a,h,O),a.setDefaultContainerPolicy({kind:"hostContainer",host:O,sharing:"perFlowRun"})},[a]),f=C((h,O)=>{let g=S.get(a);if(g!==void 0&&g!==h)throw Error("Only one useFlowContainer consumer can be mounted for a getuserfeedback client");return S.set(a,h),d.current=h,v(a,h,O),a.setDefaultContainerPolicy({kind:"hostContainer",host:O,sharing:"perFlowRun"}),()=>{if(d.current!==h||S.get(a)!==h)return;d.current=null,S.delete(a),v(a,h,null),a.setDefaultContainerPolicy({kind:"floating"})}},[a]),m=P(()=>{if(!p.isOpen&&!p.isLoading)return D;return{isOpen:p.isOpen,isLoading:p.isLoading,shouldRenderContainer:!0}},[p]),y=P(()=>({client:a,apiKey:u.apiKey,setDefaultFlowContainer:F,registerDefaultFlowContainerConsumer:f,defaultFlowContainerState:m}),[a,u.apiKey,m,f,F]);return z(e.Provider,{value:y,children:s})}var J=(s)=>{let{flowRun:u,openFlow:c,prerenderFlow:w,prefetchOnMount:a=!1,hideCloseButton:d}=s,p=s.mode==="container",F=R(null),f=I(u,(b)=>b,()=>j),m=C((b)=>c({container:p?F.current??null:void 0,hideCloseButton:d,metadata:b?.metadata}),[d,c,p]),y=C(()=>w({container:p?F.current??null:void 0,hideCloseButton:d}),[d,w,p]),h=C(()=>u.close(),[u]),O=C(()=>u.prefetch(),[u]),g=C((b)=>b?m():h(),[h,m]),x=P(()=>T(),[u]),G=C((b)=>{if(!p)return;F.current=b,v(u,x,b),u.setContainer(b)},[u,p,x]),H=L(f),B=p&&(f.isOpen||f.isLoading&&H);return M(()=>{if(!a)return;O().catch(()=>{})},[O,a]),{isOpen:f.isOpen,isLoading:f.isLoading,shouldRenderContainer:B,setOpen:g,open:m,close:h,prefetch:O,prerender:y,containerRef:G}};function t(s){let u=s.container??"default";if(R(u).current!==u)throw Error("useFlow container mode cannot change while mounted; remount the hook to change it");let w=u==="custom"?"container":"default",a=J({flowRun:s.flowRun,mode:w,openFlow:s.openFlow,prerenderFlow:s.prerenderFlow,prefetchOnMount:s.prefetchOnMount,hideCloseButton:s.hideCloseButton});if(w==="container")return{container:"custom",isOpen:a.isOpen,isLoading:a.isLoading,shouldRenderContainer:a.shouldRenderContainer,open:a.open,close:a.close,prefetch:a.prefetch,setOpen:a.setOpen,prerender:a.prerender,containerRef:a.containerRef};return{container:"default",isOpen:a.isOpen,isLoading:a.isLoading,open:a.open,close:a.close,prefetch:a.prefetch,prerender:a.prerender}}function o(s){let u=U(e);if(!u)throw Error("useFlow must be used within a GetUserFeedbackProvider");let c=P(()=>u.client.flow(s.flowId),[u.client,s.flowId]),w=C(({container:d,hideCloseButton:p,metadata:F})=>c.open(d===void 0?{hideCloseButton:p,metadata:F}:{container:d,hideCloseButton:p,metadata:F}),[c]),a=C(({hideCloseButton:d})=>c.prerender({hideCloseButton:d}),[c]);return t({flowRun:c,openFlow:w,prerenderFlow:a,container:s.container,prefetchOnMount:s.prefetchOnMount,hideCloseButton:s.hideCloseButton})}function r(){let s=U(e);if(!s)throw Error("useFlowContainer must be used within a GetUserFeedbackProvider");let{client:u,defaultFlowContainerState:c,registerDefaultFlowContainerConsumer:w,setDefaultFlowContainer:a}=s,[d]=k(T),p=R(null);M(()=>w(d,p.current),[w,d]);let F=C((m)=>{p.current=m,a(d,m)},[a,d]),f=C(()=>u.close(),[u]);return{isOpen:c.isOpen,isLoading:c.isLoading,shouldRenderContainer:c.shouldRenderContainer,close:f,containerRef:F}}function i(){let s=U(e);if(!s)throw Error("useFeedback must be used within a GetUserFeedbackProvider");let[u,c]=k(0),[w,a]=k(0),d=C(async(F)=>{c((f)=>f+1);try{return await s.client.feedback.fetch(F)}finally{c((f)=>f-1)}},[s.client]),p=C(async(F)=>{a((f)=>f+1);try{return await s.client.feedback.submit(F)}finally{a((f)=>f-1)}},[s.client]);return{fetch:d,isFetching:u>0,isSubmitting:w>0,submit:p}}function l(){let s=U(e);if(!s)throw Error("useGetUserFeedback must be used within a GetUserFeedbackProvider");return s.client}
|
|
3
|
+
export{e,n,t,o,r,i,l};
|
|
4
|
+
|
|
5
|
+
//# debugId=3D049BDEE69B43CB64756E2164756E21
|
|
6
|
+
//# sourceMappingURL=chunk-d1zm9cbm.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 {\n\tcreateReactContainerOwner,\n\tregisterReactContainer,\n} from \"@getuserfeedback/sdk/internal/react-container\";\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 while the flow interaction is open. */\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 interaction; its last presentation remains until the container ref detaches or a new flow is presented. */\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/** Attach to your container. Detaching releases the last presentation; a mounted container retains it after close. */\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 while any flow interaction is open. */\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 interactions owned by this logical client; the last presentation remains until ref detach or replacement. */\n\tclose: () => Promise<void>;\n\t/** Attach to the provider-wide container. Detaching releases its last presentation after close. */\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 DefaultFlowContainerOwner = string;\n\ntype GetUserFeedbackContextValue = {\n\tclient: Client;\n\tapiKey: string;\n\tsetDefaultFlowContainer: (\n\t\towner: DefaultFlowContainerOwner,\n\t\telement: HTMLElement | null,\n\t) => void;\n\tregisterDefaultFlowContainerConsumer: (\n\t\towner: DefaultFlowContainerOwner,\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<\n\tClient,\n\tDefaultFlowContainerOwner\n>();\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 share one root 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<DefaultFlowContainerOwner | null>(\n\t\tnull,\n\t);\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: DefaultFlowContainerOwner, 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\tregisterReactContainer(client, owner, element);\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: DefaultFlowContainerOwner, 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\tregisterReactContainer(client, owner, element);\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\tregisterReactContainer(client, owner, null);\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 prerender = useCallback(\n\t\t(): 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\t[hideCloseButton, prerenderFlow, 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 reactContainerOwner = useMemo(\n\t\t() => createReactContainerOwner(),\n\t\t[flowRun],\n\t);\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\tregisterReactContainer(flowRun, reactContainerOwner, element);\n\t\t\tflowRun.setContainer(element);\n\t\t},\n\t\t[flowRun, requiresContainer, reactContainerOwner],\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,\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 [owner] = useState<DefaultFlowContainerOwner>(\n\t\tcreateReactContainerOwner,\n\t);\n\tconst containerElementRef = useRef<HTMLDivElement | null>(null);\n\n\tuseEffect(\n\t\t() =>\n\t\t\tregisterDefaultFlowContainerConsumer(owner, containerElementRef.current),\n\t\t[registerDefaultFlowContainerConsumer, owner],\n\t);\n\n\tconst containerRef = useCallback(\n\t\t(element: HTMLDivElement | null): void => {\n\t\t\tcontainerElementRef.current = element;\n\t\t\tsetDefaultFlowContainer(owner, element);\n\t\t},\n\t\t[setDefaultFlowContainer, owner],\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": "3D049BDEE69B43CB64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -64,7 +64,7 @@ interface UseFlowReturn {
|
|
|
64
64
|
*/
|
|
65
65
|
interface UseCustomFlowReturn {
|
|
66
66
|
readonly container: "custom";
|
|
67
|
-
/** True
|
|
67
|
+
/** True while the flow interaction is open. */
|
|
68
68
|
isOpen: boolean;
|
|
69
69
|
/** True after open is requested while the flow is not visible yet. */
|
|
70
70
|
isLoading: boolean;
|
|
@@ -72,7 +72,7 @@ interface UseCustomFlowReturn {
|
|
|
72
72
|
shouldRenderContainer: boolean;
|
|
73
73
|
/** Open the flow in the custom container. */
|
|
74
74
|
open: (options?: UseFlowOpenOptions) => Promise<void>;
|
|
75
|
-
/** Close the flow. */
|
|
75
|
+
/** Close the interaction; its last presentation remains until the container ref detaches or a new flow is presented. */
|
|
76
76
|
close: () => Promise<void>;
|
|
77
77
|
/** Prefetches the flow resources without opening it. */
|
|
78
78
|
prefetch: () => Promise<void>;
|
|
@@ -82,7 +82,7 @@ interface UseCustomFlowReturn {
|
|
|
82
82
|
setOpen: (next: boolean) => Promise<void>;
|
|
83
83
|
/** Prerendering warms up the flow for instant display later. */
|
|
84
84
|
prerender: () => Promise<void>;
|
|
85
|
-
/**
|
|
85
|
+
/** Attach to your container. Detaching releases the last presentation; a mounted container retains it after close. */
|
|
86
86
|
containerRef: (element: HTMLDivElement | null) => void;
|
|
87
87
|
}
|
|
88
88
|
/**
|
|
@@ -92,15 +92,15 @@ interface UseCustomFlowReturn {
|
|
|
92
92
|
* client.
|
|
93
93
|
*/
|
|
94
94
|
interface UseFlowContainerReturn {
|
|
95
|
-
/** True
|
|
95
|
+
/** True while any flow interaction is open. */
|
|
96
96
|
isOpen: boolean;
|
|
97
97
|
/** True after any flow open is requested while the flow is not visible yet. */
|
|
98
98
|
isLoading: boolean;
|
|
99
99
|
/** True when your host UI should render the provider-wide flow container. */
|
|
100
100
|
shouldRenderContainer: boolean;
|
|
101
|
-
/** Close all
|
|
101
|
+
/** Close all interactions owned by this logical client; the last presentation remains until ref detach or replacement. */
|
|
102
102
|
close: () => Promise<void>;
|
|
103
|
-
/**
|
|
103
|
+
/** Attach to the provider-wide container. Detaching releases its last presentation after close. */
|
|
104
104
|
containerRef: (element: HTMLDivElement | null) => void;
|
|
105
105
|
}
|
|
106
106
|
interface GetUserFeedbackProviderProps {
|
|
@@ -123,7 +123,7 @@ interface GetUserFeedbackProviderProps {
|
|
|
123
123
|
* in this subtree (including targeting-engine opens) target that container.
|
|
124
124
|
* If the container ref is not mounted yet, loader keeps flows parked until it is.
|
|
125
125
|
* Mount exactly one `useFlowContainer()` consumer per logical client. Providers
|
|
126
|
-
* with the same API key
|
|
126
|
+
* with the same API key share one root client.
|
|
127
127
|
*
|
|
128
128
|
* @example Basic usage
|
|
129
129
|
* ```tsx
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import{n,o,r,i,l}from"./chunk-
|
|
2
|
+
import{n,o,r,i,l}from"./chunk-d1zm9cbm.js";var e="0.12.0".trim(),t=e.length>0?e:"0.0.0-local";export{n as GetUserFeedbackProvider,t as REACT_SDK_VERSION,i as useFeedback,o as useFlow,r as useFlowContainer,l as useGetUserFeedback};
|
|
3
3
|
|
|
4
|
-
//# debugId=
|
|
4
|
+
//# debugId=8CE6ABE4A22C05D264756E2164756E21
|
|
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": ";2CAEA,IAAM,EAEF,
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": ";2CAEA,IAAM,EAEF,SAAyB,KAAK,EAKrB,EACZ,EAAgB,OAAS,EAAI,EAAkB",
|
|
8
|
+
"debugId": "8CE6ABE4A22C05D264756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -33,7 +33,7 @@ interface UseFlowReturn {
|
|
|
33
33
|
*/
|
|
34
34
|
interface UseCustomFlowReturn {
|
|
35
35
|
readonly container: "custom";
|
|
36
|
-
/** True
|
|
36
|
+
/** True while the flow interaction is open. */
|
|
37
37
|
isOpen: boolean;
|
|
38
38
|
/** True after open is requested while the flow is not visible yet. */
|
|
39
39
|
isLoading: boolean;
|
|
@@ -41,7 +41,7 @@ interface UseCustomFlowReturn {
|
|
|
41
41
|
shouldRenderContainer: boolean;
|
|
42
42
|
/** Open the flow in the custom container. */
|
|
43
43
|
open: (options?: UseFlowOpenOptions) => Promise<void>;
|
|
44
|
-
/** Close the flow. */
|
|
44
|
+
/** Close the interaction; its last presentation remains until the container ref detaches or a new flow is presented. */
|
|
45
45
|
close: () => Promise<void>;
|
|
46
46
|
/** Prefetches the flow resources without opening it. */
|
|
47
47
|
prefetch: () => Promise<void>;
|
|
@@ -51,7 +51,7 @@ interface UseCustomFlowReturn {
|
|
|
51
51
|
setOpen: (next: boolean) => Promise<void>;
|
|
52
52
|
/** Prerendering warms up the flow for instant display later. */
|
|
53
53
|
prerender: () => Promise<void>;
|
|
54
|
-
/**
|
|
54
|
+
/** Attach to your container. Detaching releases the last presentation; a mounted container retains it after close. */
|
|
55
55
|
containerRef: (element: HTMLDivElement | null) => void;
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import{e,t}from"../chunk-
|
|
2
|
+
import{e,t}from"../chunk-d1zm9cbm.js";import{createInlineFlow as F}from"@getuserfeedback/sdk/internal/inline-flow";import{useCallback as i,useContext as p,useRef as f,useState as a}from"react";function R(r){let l=p(e);if(!l)throw Error("useFlow must be used within a GetUserFeedbackProvider");if(f(l.client).current!==l.client)throw Error("useFlow must be remounted when the GetUserFeedbackProvider client changes");let[o]=a(()=>F(l.client,r.flow)),u=i(({container:n,hideCloseButton:s,metadata:c})=>{if(n!==void 0)o.setContainer(n);return o.open({hideCloseButton:s,metadata:c})},[o]),w=i(({container:n,hideCloseButton:s})=>{if(n!==void 0)o.setContainer(n);return o.prerender({hideCloseButton:s})},[o]);return t({flowRun:o,openFlow:u,prerenderFlow:w,container:r.container,prefetchOnMount:r.prefetchOnMount,hideCloseButton:r.hideCloseButton})}export{R as useFlow};
|
|
3
3
|
|
|
4
4
|
//# debugId=9E8904514086000D64756E2164756E21
|
|
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.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "getuserfeedback React SDK",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"getuserfeedback",
|
|
@@ -40,12 +40,11 @@
|
|
|
40
40
|
"publish:npm": "node ../../scripts/publish-package.cjs . --expect-dependency @getuserfeedback/sdk:../sdk/package.json",
|
|
41
41
|
"build": "bun ../../scripts/clean-build-output.ts dist tsconfig.tsbuildinfo && bun run scripts/build.ts && bun x rollup -c rollup.dts.config.mjs && bun run scripts/verify-internal-build.ts",
|
|
42
42
|
"typecheck": "tsc -p tsconfig.json --noEmit --composite false --incremental false",
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"lint": "biome check ."
|
|
43
|
+
"lint": "oxlint --threads=2 -c ../../oxlint.config.ts . && GOMAXPROCS=2 GOMEMLIMIT=1GiB oxlint --threads=2 -c ../../oxlint-types.config.ts .",
|
|
44
|
+
"lint:syntax": "oxlint --threads=2 -c ../../oxlint.config.ts ."
|
|
46
45
|
},
|
|
47
46
|
"dependencies": {
|
|
48
|
-
"@getuserfeedback/sdk": "^0.
|
|
47
|
+
"@getuserfeedback/sdk": "^0.20.0"
|
|
49
48
|
},
|
|
50
49
|
"peerDependencies": {
|
|
51
50
|
"react": ">=18.0.0"
|
package/dist/chunk-tqj5rwar.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import{createClient as I}from"@getuserfeedback/sdk";import{createActionRegistry as G}from"@getuserfeedback/sdk/internal/action-registry";import{createContext as H,useCallback as m,useContext as P,useEffect as D,useMemo as U,useRef as O,useState as k,useSyncExternalStore as B}from"react";import{jsx as W}from"react/jsx-runtime";var L={isOpen:!1,isLoading:!1,shouldRenderContainer:!1},A=(s)=>({isOpen:s.isOpen,isLoading:s.isLoading}),y=(s)=>typeof s.width==="number"&&typeof s.height==="number",K=(s,u)=>s.isOpen===u.isOpen&&s.isLoading===u.isLoading&&y(s)===y(u),N={isOpen:!1,isLoading:!1,width:void 0,height:void 0};function V(s){let u=O(s.getFlowState());return m(()=>{let c=s.getFlowState(),f=u.current;if(K(f,c))return f;return u.current=c,c},[s])}function E(s,u,c){let f=V(s),a=O(null),p=O(null),d=m(()=>{let w=f();if(a.current===w){let h=p.current;if(h!==null)return h}let F=u(w);return a.current=w,p.current=F,F},[f,u]);return B((w)=>s.subscribeFlowState(()=>{w()},{emitInitial:!1}),d,c)}var e=H(null),g=new WeakMap,x=(s)=>{try{return JSON.stringify(G(s).listRegistrationIdentities())}catch{return null}};function n({children:s,clientOptions:u}){let c=O(x(u.actions)),f=x(u.actions);if(f!==null&&c.current!==null&&f!==c.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 a=I(u),p=O(null),d=E(a,A,()=>L),w=m((C,S)=>{if(p.current!==C||g.get(a)!==C)return;a.setDefaultContainerPolicy({kind:"hostContainer",host:S,sharing:"perFlowRun"})},[a]),F=m((C,S)=>{let v=g.get(a);if(v!==void 0&&v!==C)throw Error("Only one useFlowContainer consumer can be mounted for a getuserfeedback client");return g.set(a,C),p.current=C,a.setDefaultContainerPolicy({kind:"hostContainer",host:S,sharing:"perFlowRun"}),()=>{if(p.current!==C||g.get(a)!==C)return;p.current=null,g.delete(a),a.setDefaultContainerPolicy({kind:"floating"})}},[a]),h=U(()=>{if(!d.isOpen&&!d.isLoading)return L;return{isOpen:d.isOpen,isLoading:d.isLoading,shouldRenderContainer:!0}},[d]),R=U(()=>({client:a,apiKey:u.apiKey,setDefaultFlowContainer:w,registerDefaultFlowContainerConsumer:F,defaultFlowContainerState:h}),[a,u.apiKey,h,F,w]);return W(e.Provider,{value:R,children:s})}var _=(s)=>{let{flowRun:u,openFlow:c,prerenderFlow:f,prefetchOnMount:a=!1,hideCloseButton:p}=s,d=s.mode==="container",w=O(null),F=E(u,(b)=>b,()=>N),h=m((b)=>c({container:d?w.current??null:void 0,hideCloseButton:p,metadata:b?.metadata}),[p,c,d]),R=m(()=>u.close(),[u]),C=m(()=>u.prefetch(),[u]),S=m((b)=>b?h():R(),[R,h]),v=m((b)=>{if(!d)return;w.current=b,u.setContainer(b)},[u,d]),T=y(F),M=d&&(F.isOpen||F.isLoading&&T);return D(()=>{if(!a)return;C().catch(()=>{})},[C,a]),{isOpen:F.isOpen,isLoading:F.isLoading,shouldRenderContainer:M,setOpen:S,open:h,close:R,prefetch:C,prerender:()=>f({container:d?w.current??null:void 0,hideCloseButton:p}),containerRef:v}};function t(s){let u=s.container??"default";if(O(u).current!==u)throw Error("useFlow container mode cannot change while mounted; remount the hook to change it");let f=u==="custom"?"container":"default",a=_({flowRun:s.flowRun,mode:f,openFlow:s.openFlow,prerenderFlow:s.prerenderFlow,prefetchOnMount:s.prefetchOnMount,hideCloseButton:s.hideCloseButton});if(f==="container")return{container:"custom",isOpen:a.isOpen,isLoading:a.isLoading,shouldRenderContainer:a.shouldRenderContainer,open:a.open,close:a.close,prefetch:a.prefetch,setOpen:a.setOpen,prerender:a.prerender,containerRef:a.containerRef};return{container:"default",isOpen:a.isOpen,isLoading:a.isLoading,open:a.open,close:a.close,prefetch:a.prefetch,prerender:a.prerender}}function o(s){let u=P(e);if(!u)throw Error("useFlow must be used within a GetUserFeedbackProvider");let c=U(()=>u.client.flow(s.flowId),[u.client,s.flowId]),f=m(({container:p,hideCloseButton:d,metadata:w})=>c.open(p===void 0?{hideCloseButton:d,metadata:w}:{container:p,hideCloseButton:d,metadata:w}),[c]),a=m(({hideCloseButton:p})=>c.prerender({hideCloseButton:p}),[c]);return t({flowRun:c,openFlow:f,prerenderFlow:a,container:s.container,prefetchOnMount:s.prefetchOnMount,hideCloseButton:s.hideCloseButton})}function r(){let s=P(e);if(!s)throw Error("useFlowContainer must be used within a GetUserFeedbackProvider");let{client:u,defaultFlowContainerState:c,registerDefaultFlowContainerConsumer:f,setDefaultFlowContainer:a}=s,p=O(Symbol("getuserfeedback React flow container owner")),d=O(null);D(()=>f(p.current,d.current),[f]);let w=m((h)=>{d.current=h,a(p.current,h)},[a]),F=m(()=>u.close(),[u]);return{isOpen:c.isOpen,isLoading:c.isLoading,shouldRenderContainer:c.shouldRenderContainer,close:F,containerRef:w}}function i(){let s=P(e);if(!s)throw Error("useFeedback must be used within a GetUserFeedbackProvider");let[u,c]=k(0),[f,a]=k(0),p=m(async(w)=>{c((F)=>F+1);try{return await s.client.feedback.fetch(w)}finally{c((F)=>F-1)}},[s.client]),d=m(async(w)=>{a((F)=>F+1);try{return await s.client.feedback.submit(w)}finally{a((F)=>F-1)}},[s.client]);return{fetch:p,isFetching:u>0,isSubmitting:f>0,submit:d}}function l(){let s=P(e);if(!s)throw Error("useGetUserFeedback must be used within a GetUserFeedbackProvider");return s.client}
|
|
3
|
-
export{e,n,t,o,r,i,l};
|
|
4
|
-
|
|
5
|
-
//# debugId=84E9BFB8871DE49A64756E2164756E21
|
|
6
|
-
//# sourceMappingURL=chunk-tqj5rwar.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 { 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 DefaultFlowContainerOwner = symbol;\n\ntype GetUserFeedbackContextValue = {\n\tclient: Client;\n\tapiKey: string;\n\tsetDefaultFlowContainer: (\n\t\towner: DefaultFlowContainerOwner,\n\t\telement: HTMLElement | null,\n\t) => void;\n\tregisterDefaultFlowContainerConsumer: (\n\t\towner: DefaultFlowContainerOwner,\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<\n\tClient,\n\tDefaultFlowContainerOwner\n>();\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<DefaultFlowContainerOwner | null>(\n\t\tnull,\n\t);\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: DefaultFlowContainerOwner, 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: DefaultFlowContainerOwner, 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<DefaultFlowContainerOwner>(\n\t\tSymbol(\"getuserfeedback React flow container owner\"),\n\t);\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": "84E9BFB8871DE49A64756E2164756E21",
|
|
9
|
-
"names": []
|
|
10
|
-
}
|