@medplum/react-hooks 2.2.7 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- "use strict";var M=Object.defineProperty;var P=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var N=(t,e)=>{for(var n in e)M(t,n,{get:e[n],enumerable:!0})},I=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of S(e))!b.call(t,o)&&o!==n&&M(t,o,{get:()=>e[o],enumerable:!(r=P(e,o))||r.enumerable});return t};var F=t=>I(M({},"__esModule",{value:!0}),t);var U={};N(U,{MedplumProvider:()=>L,reactContext:()=>l,useMedplum:()=>p,useMedplumContext:()=>R,useMedplumNavigate:()=>z,useMedplumProfile:()=>Q,useResource:()=>A,useSearch:()=>B,useSearchOne:()=>w,useSearchResources:()=>J});module.exports=F(U);var s=require("react");var m=require("react"),l=(0,m.createContext)(void 0);function R(){return(0,m.useContext)(l)}function p(){return R().medplum}function z(){return R().navigate}function Q(){return R().profile}var C=require("react/jsx-runtime");function L(t){let e=t.medplum,n=t.navigate??k,[r,o]=(0,s.useState)({profile:e.getProfile(),loading:!e.isInitialized});(0,s.useEffect)(()=>{e&&(e.isInitialized||(o(u=>({...u,loading:!0})),e.getInitPromise().then(()=>o(u=>({...u,loading:!1}))).catch(console.error)))},[e,e.isInitialized]),(0,s.useEffect)(()=>{function u(){o({...r,profile:e.getProfile()})}return e.addEventListener("change",u),()=>e.removeEventListener("change",u)},[e,r]);let i=(0,s.useMemo)(()=>({...r,medplum:e,navigate:n}),[r,e,n]);return(0,C.jsx)(l.Provider,{value:i,children:t.children})}function k(t){window.location.assign(t)}var c=require("@medplum/core"),d=require("react");function A(t,e){let n=p(),[r,o]=(0,d.useState)(K(n,t)),i=(0,d.useCallback)(u=>{(0,c.deepEquals)(u,r)||o(u)},[r,o]);return(0,d.useEffect)(()=>{i(K(n,t))},[n,t,i]),(0,d.useEffect)(()=>{let u=!0;return(0,c.isReference)(t)&&n.readReference(t).then(f=>{u&&i(f)}).catch(f=>{u&&(i(void 0),e&&e((0,c.normalizeOperationOutcome)(f)))}),()=>u=!1},[n,r,t,i,e]),r}function K(t,e){if(e){if((0,c.isResource)(e))return e;if((0,c.isReference)(e))return t.getCachedReference(e)}}var x=require("@medplum/core"),a=require("react");function B(t,e){return T("search",t,e)}function w(t,e){return T("searchOne",t,e)}function J(t,e){return T("searchResources",t,e)}function T(t,e,n){let r=p(),[o,i]=(0,a.useState)(),[u,f]=(0,a.useState)(!1),[v,g]=(0,a.useState)(),[E,y]=(0,a.useState)();return(0,a.useEffect)(()=>{let O=r.fhirSearchUrl(e,n).toString();O!==o&&(i(O),r[t](e,n).then(h=>{f(!1),g(h),y(x.allOk)}).catch(h=>{f(!1),g(void 0),y((0,x.normalizeOperationOutcome)(h))}))},[r,t,e,n,o,g]),[v,u,E]}
1
+ "use strict";var M=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var N=(t,e)=>{for(var n in e)M(t,n,{get:e[n],enumerable:!0})},I=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of S(e))!b.call(t,o)&&o!==n&&M(t,o,{get:()=>e[o],enumerable:!(r=E(e,o))||r.enumerable});return t};var F=t=>I(M({},"__esModule",{value:!0}),t);var U={};N(U,{MedplumProvider:()=>L,reactContext:()=>l,useMedplum:()=>p,useMedplumContext:()=>R,useMedplumNavigate:()=>z,useMedplumProfile:()=>Q,useResource:()=>A,useSearch:()=>B,useSearchOne:()=>w,useSearchResources:()=>J});module.exports=F(U);var s=require("react");var m=require("react"),l=(0,m.createContext)(void 0);function R(){return(0,m.useContext)(l)}function p(){return R().medplum}function z(){return R().navigate}function Q(){return R().profile}var C=require("react/jsx-runtime");function L(t){let e=t.medplum,n=t.navigate??k,[r,o]=(0,s.useState)({profile:e.getProfile(),loading:!e.isInitialized});(0,s.useEffect)(()=>{e&&(e.isInitialized||(o(i=>({...i,loading:!0})),e.getInitPromise().then(()=>o(i=>({...i,loading:!1}))).catch(console.error)))},[e,e.isInitialized]),(0,s.useEffect)(()=>{function i(){o({...r,profile:e.getProfile()})}return e.addEventListener("change",i),()=>e.removeEventListener("change",i)},[e,r]);let u=(0,s.useMemo)(()=>({...r,medplum:e,navigate:n}),[r,e,n]);return(0,C.jsx)(l.Provider,{value:u,children:t.children})}function k(t){window.location.assign(t)}var c=require("@medplum/core"),d=require("react");function A(t,e){let n=p(),[r,o]=(0,d.useState)(K(n,t)),u=(0,d.useCallback)(i=>{(0,c.deepEquals)(i,r)||o(i)},[r,o]);return(0,d.useEffect)(()=>{u(K(n,t))},[n,t,u]),(0,d.useEffect)(()=>{let i=!0;return(0,c.isReference)(t)&&n.readReference(t).then(f=>{i&&u(f)}).catch(f=>{i&&(u(void 0),e&&e((0,c.normalizeOperationOutcome)(f)))}),()=>i=!1},[n,r,t,u,e]),r}function K(t,e){if(e){if((0,c.isResource)(e))return e;if((0,c.isReference)(e))return t.getCachedReference(e)}}var x=require("@medplum/core"),a=require("react");function B(t,e){return T("search",t,e)}function w(t,e){return T("searchOne",t,e)}function J(t,e){return T("searchResources",t,e)}function T(t,e,n){let r=p(),[o,u]=(0,a.useState)(),[i,f]=(0,a.useState)(!1),[v,g]=(0,a.useState)(),[P,y]=(0,a.useState)();return(0,a.useEffect)(()=>{let O=r.fhirSearchUrl(e,n).toString();O!==o&&(u(O),r[t](e,n).then(h=>{f(!1),g(h),y(x.allOk)}).catch(h=>{f(!1),g(void 0),y((0,x.normalizeOperationOutcome)(h))}))},[r,t,e,n,o,g]),[v,i,P]}
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts", "../../src/MedplumProvider/MedplumProvider.tsx", "../../src/MedplumProvider/MedplumProvider.context.ts", "../../src/useResource/useResource.ts", "../../src/useSearch/useSearch.ts"],
4
- "sourcesContent": ["export * from './MedplumProvider/MedplumProvider';\nexport * from './MedplumProvider/MedplumProvider.context';\nexport * from './useResource/useResource';\nexport * from './useSearch/useSearch';\n", "import { MedplumClient } from '@medplum/core';\nimport { ReactNode, useEffect, useMemo, useState } from 'react';\nimport { MepdlumNavigateFunction, reactContext } from './MedplumProvider.context';\n\nexport interface MedplumProviderProps {\n medplum: MedplumClient;\n navigate?: MepdlumNavigateFunction;\n children: ReactNode;\n}\n\n/**\n * The MedplumProvider component provides Medplum context state.\n *\n * Medplum context includes:\n * 1) medplum - Medplum client library\n * 2) profile - The current user profile (if signed in)\n * @param props - The MedplumProvider React props.\n * @returns The MedplumProvider React node.\n */\nexport function MedplumProvider(props: MedplumProviderProps): JSX.Element {\n const medplum = props.medplum;\n const navigate = props.navigate ?? defaultNavigate;\n\n const [state, setState] = useState({\n profile: medplum.getProfile(),\n loading: !medplum.isInitialized,\n });\n\n useEffect(() => {\n if (!medplum) {\n return;\n }\n if (!medplum.isInitialized) {\n setState((s) => ({ ...s, loading: true }));\n medplum\n .getInitPromise()\n .then(() => setState((s) => ({ ...s, loading: false })))\n .catch(console.error);\n }\n }, [medplum, medplum.isInitialized]);\n\n useEffect(() => {\n function eventListener(): void {\n setState({\n ...state,\n profile: medplum.getProfile(),\n });\n }\n\n medplum.addEventListener('change', eventListener);\n return () => medplum.removeEventListener('change', eventListener);\n }, [medplum, state]);\n\n const medplumContext = useMemo(\n () => ({\n ...state,\n medplum,\n navigate,\n }),\n [state, medplum, navigate]\n );\n\n return <reactContext.Provider value={medplumContext}>{props.children}</reactContext.Provider>;\n}\n\n/**\n * The default \"navigate\" function which simply uses window.location.href.\n * @param path - The path to navigate to.\n */\nfunction defaultNavigate(path: string): void {\n window.location.assign(path);\n}\n", "import { MedplumClient, ProfileResource } from '@medplum/core';\nimport { createContext, useContext } from 'react';\n\nexport const reactContext = createContext(undefined as MedplumContext | undefined);\n\nexport type MepdlumNavigateFunction = (path: string) => void;\n\nexport interface MedplumContext {\n medplum: MedplumClient;\n navigate: MepdlumNavigateFunction;\n profile?: ProfileResource;\n loading: boolean;\n}\n\n/**\n * Returns the MedplumContext instance.\n * @returns The MedplumContext instance.\n */\nexport function useMedplumContext(): MedplumContext {\n return useContext(reactContext) as MedplumContext;\n}\n\n/**\n * Returns the MedplumClient instance.\n * This is a shortcut for useMedplumContext().medplum.\n * @returns The MedplumClient instance.\n */\nexport function useMedplum(): MedplumClient {\n return useMedplumContext().medplum;\n}\n\n/**\n * Returns the Medplum navigate function.\n * @returns The Medplum navigate function.\n */\nexport function useMedplumNavigate(): MepdlumNavigateFunction {\n return useMedplumContext().navigate;\n}\n\n/**\n * Returns the current Medplum user profile (if signed in).\n * This is a shortcut for useMedplumContext().profile.\n * @returns The current user profile.\n */\nexport function useMedplumProfile(): ProfileResource | undefined {\n return useMedplumContext().profile;\n}\n", "import { deepEquals, isReference, isResource, MedplumClient, normalizeOperationOutcome } from '@medplum/core';\nimport { OperationOutcome, Reference, Resource } from '@medplum/fhirtypes';\nimport { useCallback, useEffect, useState } from 'react';\nimport { useMedplum } from '../MedplumProvider/MedplumProvider.context';\n\n/**\n * React Hook to use a FHIR reference.\n * Handles the complexity of resolving references and caching resources.\n * @param value - The resource or reference to resource.\n * @param setOutcome - Optional callback to set the OperationOutcome.\n * @returns The resolved resource.\n */\nexport function useResource<T extends Resource>(\n value: Reference<T> | T | undefined,\n setOutcome?: (outcome: OperationOutcome) => void\n): T | undefined {\n const medplum = useMedplum();\n const [resource, setResource] = useState<T | undefined>(getInitialResource(medplum, value));\n\n const setResourceIfChanged = useCallback(\n (r: T | undefined) => {\n if (!deepEquals(r, resource)) {\n setResource(r);\n }\n },\n [resource, setResource]\n );\n\n useEffect(() => {\n setResourceIfChanged(getInitialResource(medplum, value));\n }, [medplum, value, setResourceIfChanged]);\n\n useEffect(() => {\n let subscribed = true;\n\n if (isReference(value)) {\n medplum\n .readReference(value as Reference<T>)\n .then((r) => {\n if (subscribed) {\n setResourceIfChanged(r);\n }\n })\n .catch((err) => {\n if (subscribed) {\n setResourceIfChanged(undefined);\n if (setOutcome) {\n setOutcome(normalizeOperationOutcome(err));\n }\n }\n });\n }\n\n return (() => (subscribed = false)) as () => void;\n }, [medplum, resource, value, setResourceIfChanged, setOutcome]);\n\n return resource;\n}\n\n/**\n * Returns the initial resource value based on the input value.\n * If the input value is a resource, returns the resource.\n * If the input value is a reference to a resource available in the cache, returns the resource.\n * Otherwise, returns undefined.\n * @param medplum - The medplum client.\n * @param value - The resource or reference to resource.\n * @returns An initial resource if available; undefined otherwise.\n */\nfunction getInitialResource<T extends Resource>(\n medplum: MedplumClient,\n value: Reference<T> | T | undefined\n): T | undefined {\n if (value) {\n if (isResource(value)) {\n return value;\n }\n\n if (isReference(value)) {\n return medplum.getCachedReference(value as Reference<T>);\n }\n }\n\n return undefined;\n}\n", "import { allOk, normalizeOperationOutcome, QueryTypes, ResourceArray } from '@medplum/core';\nimport { Bundle, ExtractResource, OperationOutcome, ResourceType } from '@medplum/fhirtypes';\nimport { useEffect, useState } from 'react';\nimport { useMedplum } from '../MedplumProvider/MedplumProvider.context';\n\ntype SearchFn = 'search' | 'searchOne' | 'searchResources';\n\n/**\n * React hook for searching FHIR resources.\n *\n * This is a convenience hook for calling the MedplumClient.search() method.\n *\n * @param resourceType - The FHIR resource type to search.\n * @param query - Optional search parameters.\n * @returns A 3-element tuple containing the search result, loading flag, and operation outcome.\n */\nexport function useSearch<K extends ResourceType>(\n resourceType: K,\n query?: QueryTypes\n): [Bundle<ExtractResource<K>> | undefined, boolean, OperationOutcome | undefined] {\n return useSearchImpl<K, Bundle<ExtractResource<K>>>('search', resourceType, query);\n}\n\n/**\n * React hook for searching for a single FHIR resource.\n *\n * This is a convenience hook for calling the MedplumClient.searchOne() method.\n *\n * @param resourceType - The FHIR resource type to search.\n * @param query - Optional search parameters.\n * @returns A 3-element tuple containing the search result, loading flag, and operation outcome.\n */\nexport function useSearchOne<K extends ResourceType>(\n resourceType: K,\n query?: QueryTypes\n): [ExtractResource<K> | undefined, boolean, OperationOutcome | undefined] {\n return useSearchImpl<K, ExtractResource<K>>('searchOne', resourceType, query);\n}\n\n/**\n * React hook for searching for an array of FHIR resources.\n *\n * This is a convenience hook for calling the MedplumClient.searchResources() method.\n *\n * @param resourceType - The FHIR resource type to search.\n * @param query - Optional search parameters.\n * @returns A 3-element tuple containing the search result, loading flag, and operation outcome.\n */\nexport function useSearchResources<K extends ResourceType>(\n resourceType: K,\n query?: QueryTypes\n): [ResourceArray<ExtractResource<K>> | undefined, boolean, OperationOutcome | undefined] {\n return useSearchImpl<K, ResourceArray<ExtractResource<K>>>('searchResources', resourceType, query);\n}\n\nfunction useSearchImpl<K extends ResourceType, ReturnType>(\n searchFn: SearchFn,\n resourceType: K,\n query: QueryTypes | undefined\n): [ReturnType | undefined, boolean, OperationOutcome | undefined] {\n const medplum = useMedplum();\n const [searchKey, setSearchKey] = useState<string>();\n const [loading, setLoading] = useState<boolean>(false);\n const [result, setResult] = useState<ReturnType>();\n const [outcome, setOutcome] = useState<OperationOutcome>();\n\n useEffect(() => {\n const key = medplum.fhirSearchUrl(resourceType, query).toString();\n if (key !== searchKey) {\n setSearchKey(key);\n medplum[searchFn](resourceType, query)\n .then((res) => {\n setLoading(false);\n setResult(res as ReturnType);\n setOutcome(allOk);\n })\n .catch((err) => {\n setLoading(false);\n setResult(undefined);\n setOutcome(normalizeOperationOutcome(err));\n });\n }\n }, [medplum, searchFn, resourceType, query, searchKey, setResult]);\n\n return [result, loading, outcome];\n}\n"],
4
+ "sourcesContent": ["export * from './MedplumProvider/MedplumProvider';\nexport * from './MedplumProvider/MedplumProvider.context';\nexport * from './useResource/useResource';\nexport * from './useSearch/useSearch';\n", "import { MedplumClient } from '@medplum/core';\nimport { ReactNode, useEffect, useMemo, useState } from 'react';\nimport { MepdlumNavigateFunction, reactContext } from './MedplumProvider.context';\n\nexport interface MedplumProviderProps {\n medplum: MedplumClient;\n navigate?: MepdlumNavigateFunction;\n children: ReactNode;\n}\n\n/**\n * The MedplumProvider component provides Medplum context state.\n *\n * Medplum context includes:\n * 1) medplum - Medplum client library\n * 2) profile - The current user profile (if signed in)\n * @param props - The MedplumProvider React props.\n * @returns The MedplumProvider React node.\n */\nexport function MedplumProvider(props: MedplumProviderProps): JSX.Element {\n const medplum = props.medplum;\n const navigate = props.navigate ?? defaultNavigate;\n\n const [state, setState] = useState({\n profile: medplum.getProfile(),\n loading: !medplum.isInitialized,\n });\n\n useEffect(() => {\n if (!medplum) {\n return;\n }\n if (!medplum.isInitialized) {\n setState((s) => ({ ...s, loading: true }));\n medplum\n .getInitPromise()\n .then(() => setState((s) => ({ ...s, loading: false })))\n .catch(console.error);\n }\n }, [medplum, medplum.isInitialized]);\n\n useEffect(() => {\n function eventListener(): void {\n setState({\n ...state,\n profile: medplum.getProfile(),\n });\n }\n\n medplum.addEventListener('change', eventListener);\n return () => medplum.removeEventListener('change', eventListener);\n }, [medplum, state]);\n\n const medplumContext = useMemo(\n () => ({\n ...state,\n medplum,\n navigate,\n }),\n [state, medplum, navigate]\n );\n\n return <reactContext.Provider value={medplumContext}>{props.children}</reactContext.Provider>;\n}\n\n/**\n * The default \"navigate\" function which simply uses window.location.href.\n * @param path - The path to navigate to.\n */\nfunction defaultNavigate(path: string): void {\n window.location.assign(path);\n}\n", "import { MedplumClient, ProfileResource } from '@medplum/core';\nimport { createContext, useContext } from 'react';\n\nexport const reactContext = createContext(undefined as MedplumContext | undefined);\n\nexport type MepdlumNavigateFunction = (path: string) => void;\n\nexport interface MedplumContext {\n medplum: MedplumClient;\n navigate: MepdlumNavigateFunction;\n profile?: ProfileResource;\n loading: boolean;\n}\n\n/**\n * Returns the MedplumContext instance.\n * @returns The MedplumContext instance.\n */\nexport function useMedplumContext(): MedplumContext {\n return useContext(reactContext) as MedplumContext;\n}\n\n/**\n * Returns the MedplumClient instance.\n * This is a shortcut for useMedplumContext().medplum.\n * @returns The MedplumClient instance.\n */\nexport function useMedplum(): MedplumClient {\n return useMedplumContext().medplum;\n}\n\n/**\n * Returns the Medplum navigate function.\n * @returns The Medplum navigate function.\n */\nexport function useMedplumNavigate(): MepdlumNavigateFunction {\n return useMedplumContext().navigate;\n}\n\n/**\n * Returns the current Medplum user profile (if signed in).\n * This is a shortcut for useMedplumContext().profile.\n * @returns The current user profile.\n */\nexport function useMedplumProfile(): ProfileResource | undefined {\n return useMedplumContext().profile;\n}\n", "import { deepEquals, isReference, isResource, MedplumClient, normalizeOperationOutcome } from '@medplum/core';\nimport { OperationOutcome, Reference, Resource } from '@medplum/fhirtypes';\nimport { useCallback, useEffect, useState } from 'react';\nimport { useMedplum } from '../MedplumProvider/MedplumProvider.context';\n\n/**\n * React Hook to use a FHIR reference.\n * Handles the complexity of resolving references and caching resources.\n * @param value - The resource or reference to resource.\n * @param setOutcome - Optional callback to set the OperationOutcome.\n * @returns The resolved resource.\n */\nexport function useResource<T extends Resource>(\n value: Reference<T> | Partial<T> | undefined,\n setOutcome?: (outcome: OperationOutcome) => void\n): T | undefined {\n const medplum = useMedplum();\n const [resource, setResource] = useState<T | undefined>(getInitialResource(medplum, value));\n\n const setResourceIfChanged = useCallback(\n (r: T | undefined) => {\n if (!deepEquals(r, resource)) {\n setResource(r);\n }\n },\n [resource, setResource]\n );\n\n useEffect(() => {\n setResourceIfChanged(getInitialResource(medplum, value));\n }, [medplum, value, setResourceIfChanged]);\n\n useEffect(() => {\n let subscribed = true;\n\n if (isReference(value)) {\n medplum\n .readReference(value as Reference<T>)\n .then((r) => {\n if (subscribed) {\n setResourceIfChanged(r);\n }\n })\n .catch((err) => {\n if (subscribed) {\n setResourceIfChanged(undefined);\n if (setOutcome) {\n setOutcome(normalizeOperationOutcome(err));\n }\n }\n });\n }\n\n return (() => (subscribed = false)) as () => void;\n }, [medplum, resource, value, setResourceIfChanged, setOutcome]);\n\n return resource;\n}\n\n/**\n * Returns the initial resource value based on the input value.\n * If the input value is a resource, returns the resource.\n * If the input value is a reference to a resource available in the cache, returns the resource.\n * Otherwise, returns undefined.\n * @param medplum - The medplum client.\n * @param value - The resource or reference to resource.\n * @returns An initial resource if available; undefined otherwise.\n */\nfunction getInitialResource<T extends Resource>(\n medplum: MedplumClient,\n value: Reference<T> | Partial<T> | undefined\n): T | undefined {\n if (value) {\n if (isResource(value)) {\n return value as T;\n }\n\n if (isReference(value)) {\n return medplum.getCachedReference(value as Reference<T>);\n }\n }\n\n return undefined;\n}\n", "import { allOk, normalizeOperationOutcome, QueryTypes, ResourceArray } from '@medplum/core';\nimport { Bundle, ExtractResource, OperationOutcome, ResourceType } from '@medplum/fhirtypes';\nimport { useEffect, useState } from 'react';\nimport { useMedplum } from '../MedplumProvider/MedplumProvider.context';\n\ntype SearchFn = 'search' | 'searchOne' | 'searchResources';\n\n/**\n * React hook for searching FHIR resources.\n *\n * This is a convenience hook for calling the MedplumClient.search() method.\n *\n * @param resourceType - The FHIR resource type to search.\n * @param query - Optional search parameters.\n * @returns A 3-element tuple containing the search result, loading flag, and operation outcome.\n */\nexport function useSearch<K extends ResourceType>(\n resourceType: K,\n query?: QueryTypes\n): [Bundle<ExtractResource<K>> | undefined, boolean, OperationOutcome | undefined] {\n return useSearchImpl<K, Bundle<ExtractResource<K>>>('search', resourceType, query);\n}\n\n/**\n * React hook for searching for a single FHIR resource.\n *\n * This is a convenience hook for calling the MedplumClient.searchOne() method.\n *\n * @param resourceType - The FHIR resource type to search.\n * @param query - Optional search parameters.\n * @returns A 3-element tuple containing the search result, loading flag, and operation outcome.\n */\nexport function useSearchOne<K extends ResourceType>(\n resourceType: K,\n query?: QueryTypes\n): [ExtractResource<K> | undefined, boolean, OperationOutcome | undefined] {\n return useSearchImpl<K, ExtractResource<K>>('searchOne', resourceType, query);\n}\n\n/**\n * React hook for searching for an array of FHIR resources.\n *\n * This is a convenience hook for calling the MedplumClient.searchResources() method.\n *\n * @param resourceType - The FHIR resource type to search.\n * @param query - Optional search parameters.\n * @returns A 3-element tuple containing the search result, loading flag, and operation outcome.\n */\nexport function useSearchResources<K extends ResourceType>(\n resourceType: K,\n query?: QueryTypes\n): [ResourceArray<ExtractResource<K>> | undefined, boolean, OperationOutcome | undefined] {\n return useSearchImpl<K, ResourceArray<ExtractResource<K>>>('searchResources', resourceType, query);\n}\n\nfunction useSearchImpl<K extends ResourceType, ReturnType>(\n searchFn: SearchFn,\n resourceType: K,\n query: QueryTypes | undefined\n): [ReturnType | undefined, boolean, OperationOutcome | undefined] {\n const medplum = useMedplum();\n const [searchKey, setSearchKey] = useState<string>();\n const [loading, setLoading] = useState<boolean>(false);\n const [result, setResult] = useState<ReturnType>();\n const [outcome, setOutcome] = useState<OperationOutcome>();\n\n useEffect(() => {\n const key = medplum.fhirSearchUrl(resourceType, query).toString();\n if (key !== searchKey) {\n setSearchKey(key);\n medplum[searchFn](resourceType, query)\n .then((res) => {\n setLoading(false);\n setResult(res as ReturnType);\n setOutcome(allOk);\n })\n .catch((err) => {\n setLoading(false);\n setResult(undefined);\n setOutcome(normalizeOperationOutcome(err));\n });\n }\n }, [medplum, searchFn, resourceType, query, searchKey, setResult]);\n\n return [result, loading, outcome];\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": ["src_exports", "__export", "MedplumProvider", "reactContext", "useMedplum", "useMedplumContext", "useMedplumNavigate", "useMedplumProfile", "useResource", "useSearch", "useSearchOne", "useSearchResources", "__toCommonJS", "import_react", "import_react", "reactContext", "useMedplumContext", "useMedplum", "useMedplumNavigate", "useMedplumProfile", "import_jsx_runtime", "MedplumProvider", "props", "medplum", "navigate", "defaultNavigate", "state", "setState", "s", "eventListener", "medplumContext", "reactContext", "path", "import_core", "import_react", "useResource", "value", "setOutcome", "medplum", "useMedplum", "resource", "setResource", "getInitialResource", "setResourceIfChanged", "r", "subscribed", "err", "import_core", "import_react", "useSearch", "resourceType", "query", "useSearchImpl", "useSearchOne", "useSearchResources", "searchFn", "medplum", "useMedplum", "searchKey", "setSearchKey", "loading", "setLoading", "result", "setResult", "outcome", "setOutcome", "key", "res", "err"]
7
7
  }
@@ -74,7 +74,7 @@ export declare function useMedplumProfile(): ProfileResource | undefined;
74
74
  * @param setOutcome - Optional callback to set the OperationOutcome.
75
75
  * @returns The resolved resource.
76
76
  */
77
- export declare function useResource<T extends Resource>(value: Reference<T> | T | undefined, setOutcome?: (outcome: OperationOutcome) => void): T | undefined;
77
+ export declare function useResource<T extends Resource>(value: Reference<T> | Partial<T> | undefined, setOutcome?: (outcome: OperationOutcome) => void): T | undefined;
78
78
 
79
79
  /**
80
80
  * React hook for searching FHIR resources.
@@ -74,7 +74,7 @@ export declare function useMedplumProfile(): ProfileResource | undefined;
74
74
  * @param setOutcome - Optional callback to set the OperationOutcome.
75
75
  * @returns The resolved resource.
76
76
  */
77
- export declare function useResource<T extends Resource>(value: Reference<T> | T | undefined, setOutcome?: (outcome: OperationOutcome) => void): T | undefined;
77
+ export declare function useResource<T extends Resource>(value: Reference<T> | Partial<T> | undefined, setOutcome?: (outcome: OperationOutcome) => void): T | undefined;
78
78
 
79
79
  /**
80
80
  * React hook for searching FHIR resources.
@@ -1,2 +1,2 @@
1
- import{useEffect as g,useMemo as v,useState as E}from"react";import{createContext as C,useContext as K}from"react";var p=C(void 0);function m(){return K(p)}function s(){return m().medplum}function B(){return m().navigate}function w(){return m().profile}import{jsx as S}from"react/jsx-runtime";function H(t){let e=t.medplum,o=t.navigate??P,[r,u]=E({profile:e.getProfile(),loading:!e.isInitialized});g(()=>{e&&(e.isInitialized||(u(n=>({...n,loading:!0})),e.getInitPromise().then(()=>u(n=>({...n,loading:!1}))).catch(console.error)))},[e,e.isInitialized]),g(()=>{function n(){u({...r,profile:e.getProfile()})}return e.addEventListener("change",n),()=>e.removeEventListener("change",n)},[e,r]);let i=v(()=>({...r,medplum:e,navigate:o}),[r,e,o]);return S(p.Provider,{value:i,children:t.children})}function P(t){window.location.assign(t)}import{deepEquals as b,isReference as T,isResource as N,normalizeOperationOutcome as I}from"@medplum/core";import{useCallback as F,useEffect as h,useState as z}from"react";function j(t,e){let o=s(),[r,u]=z(M(o,t)),i=F(n=>{b(n,r)||u(n)},[r,u]);return h(()=>{i(M(o,t))},[o,t,i]),h(()=>{let n=!0;return T(t)&&o.readReference(t).then(c=>{n&&i(c)}).catch(c=>{n&&(i(void 0),e&&e(I(c)))}),()=>n=!1},[o,r,t,i,e]),r}function M(t,e){if(e){if(N(e))return e;if(T(e))return t.getCachedReference(e)}}import{allOk as Q,normalizeOperationOutcome as L}from"@medplum/core";import{useEffect as k,useState as d}from"react";function ue(t,e){return l("search",t,e)}function ie(t,e){return l("searchOne",t,e)}function ce(t,e){return l("searchResources",t,e)}function l(t,e,o){let r=s(),[u,i]=d(),[n,c]=d(!1),[y,a]=d(),[O,R]=d();return k(()=>{let x=r.fhirSearchUrl(e,o).toString();x!==u&&(i(x),r[t](e,o).then(f=>{c(!1),a(f),R(Q)}).catch(f=>{c(!1),a(void 0),R(L(f))}))},[r,t,e,o,u,a]),[y,n,O]}export{H as MedplumProvider,p as reactContext,s as useMedplum,m as useMedplumContext,B as useMedplumNavigate,w as useMedplumProfile,j as useResource,ue as useSearch,ie as useSearchOne,ce as useSearchResources};
1
+ import{useEffect as g,useMemo as v,useState as P}from"react";import{createContext as C,useContext as K}from"react";var p=C(void 0);function m(){return K(p)}function s(){return m().medplum}function B(){return m().navigate}function w(){return m().profile}import{jsx as S}from"react/jsx-runtime";function H(t){let e=t.medplum,o=t.navigate??E,[r,i]=P({profile:e.getProfile(),loading:!e.isInitialized});g(()=>{e&&(e.isInitialized||(i(n=>({...n,loading:!0})),e.getInitPromise().then(()=>i(n=>({...n,loading:!1}))).catch(console.error)))},[e,e.isInitialized]),g(()=>{function n(){i({...r,profile:e.getProfile()})}return e.addEventListener("change",n),()=>e.removeEventListener("change",n)},[e,r]);let u=v(()=>({...r,medplum:e,navigate:o}),[r,e,o]);return S(p.Provider,{value:u,children:t.children})}function E(t){window.location.assign(t)}import{deepEquals as b,isReference as T,isResource as N,normalizeOperationOutcome as I}from"@medplum/core";import{useCallback as F,useEffect as h,useState as z}from"react";function j(t,e){let o=s(),[r,i]=z(M(o,t)),u=F(n=>{b(n,r)||i(n)},[r,i]);return h(()=>{u(M(o,t))},[o,t,u]),h(()=>{let n=!0;return T(t)&&o.readReference(t).then(c=>{n&&u(c)}).catch(c=>{n&&(u(void 0),e&&e(I(c)))}),()=>n=!1},[o,r,t,u,e]),r}function M(t,e){if(e){if(N(e))return e;if(T(e))return t.getCachedReference(e)}}import{allOk as Q,normalizeOperationOutcome as L}from"@medplum/core";import{useEffect as k,useState as d}from"react";function ie(t,e){return l("search",t,e)}function ue(t,e){return l("searchOne",t,e)}function ce(t,e){return l("searchResources",t,e)}function l(t,e,o){let r=s(),[i,u]=d(),[n,c]=d(!1),[y,a]=d(),[O,R]=d();return k(()=>{let x=r.fhirSearchUrl(e,o).toString();x!==i&&(u(x),r[t](e,o).then(f=>{c(!1),a(f),R(Q)}).catch(f=>{c(!1),a(void 0),R(L(f))}))},[r,t,e,o,i,a]),[y,n,O]}export{H as MedplumProvider,p as reactContext,s as useMedplum,m as useMedplumContext,B as useMedplumNavigate,w as useMedplumProfile,j as useResource,ie as useSearch,ue as useSearchOne,ce as useSearchResources};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/MedplumProvider/MedplumProvider.tsx", "../../src/MedplumProvider/MedplumProvider.context.ts", "../../src/useResource/useResource.ts", "../../src/useSearch/useSearch.ts"],
4
- "sourcesContent": ["import { MedplumClient } from '@medplum/core';\nimport { ReactNode, useEffect, useMemo, useState } from 'react';\nimport { MepdlumNavigateFunction, reactContext } from './MedplumProvider.context';\n\nexport interface MedplumProviderProps {\n medplum: MedplumClient;\n navigate?: MepdlumNavigateFunction;\n children: ReactNode;\n}\n\n/**\n * The MedplumProvider component provides Medplum context state.\n *\n * Medplum context includes:\n * 1) medplum - Medplum client library\n * 2) profile - The current user profile (if signed in)\n * @param props - The MedplumProvider React props.\n * @returns The MedplumProvider React node.\n */\nexport function MedplumProvider(props: MedplumProviderProps): JSX.Element {\n const medplum = props.medplum;\n const navigate = props.navigate ?? defaultNavigate;\n\n const [state, setState] = useState({\n profile: medplum.getProfile(),\n loading: !medplum.isInitialized,\n });\n\n useEffect(() => {\n if (!medplum) {\n return;\n }\n if (!medplum.isInitialized) {\n setState((s) => ({ ...s, loading: true }));\n medplum\n .getInitPromise()\n .then(() => setState((s) => ({ ...s, loading: false })))\n .catch(console.error);\n }\n }, [medplum, medplum.isInitialized]);\n\n useEffect(() => {\n function eventListener(): void {\n setState({\n ...state,\n profile: medplum.getProfile(),\n });\n }\n\n medplum.addEventListener('change', eventListener);\n return () => medplum.removeEventListener('change', eventListener);\n }, [medplum, state]);\n\n const medplumContext = useMemo(\n () => ({\n ...state,\n medplum,\n navigate,\n }),\n [state, medplum, navigate]\n );\n\n return <reactContext.Provider value={medplumContext}>{props.children}</reactContext.Provider>;\n}\n\n/**\n * The default \"navigate\" function which simply uses window.location.href.\n * @param path - The path to navigate to.\n */\nfunction defaultNavigate(path: string): void {\n window.location.assign(path);\n}\n", "import { MedplumClient, ProfileResource } from '@medplum/core';\nimport { createContext, useContext } from 'react';\n\nexport const reactContext = createContext(undefined as MedplumContext | undefined);\n\nexport type MepdlumNavigateFunction = (path: string) => void;\n\nexport interface MedplumContext {\n medplum: MedplumClient;\n navigate: MepdlumNavigateFunction;\n profile?: ProfileResource;\n loading: boolean;\n}\n\n/**\n * Returns the MedplumContext instance.\n * @returns The MedplumContext instance.\n */\nexport function useMedplumContext(): MedplumContext {\n return useContext(reactContext) as MedplumContext;\n}\n\n/**\n * Returns the MedplumClient instance.\n * This is a shortcut for useMedplumContext().medplum.\n * @returns The MedplumClient instance.\n */\nexport function useMedplum(): MedplumClient {\n return useMedplumContext().medplum;\n}\n\n/**\n * Returns the Medplum navigate function.\n * @returns The Medplum navigate function.\n */\nexport function useMedplumNavigate(): MepdlumNavigateFunction {\n return useMedplumContext().navigate;\n}\n\n/**\n * Returns the current Medplum user profile (if signed in).\n * This is a shortcut for useMedplumContext().profile.\n * @returns The current user profile.\n */\nexport function useMedplumProfile(): ProfileResource | undefined {\n return useMedplumContext().profile;\n}\n", "import { deepEquals, isReference, isResource, MedplumClient, normalizeOperationOutcome } from '@medplum/core';\nimport { OperationOutcome, Reference, Resource } from '@medplum/fhirtypes';\nimport { useCallback, useEffect, useState } from 'react';\nimport { useMedplum } from '../MedplumProvider/MedplumProvider.context';\n\n/**\n * React Hook to use a FHIR reference.\n * Handles the complexity of resolving references and caching resources.\n * @param value - The resource or reference to resource.\n * @param setOutcome - Optional callback to set the OperationOutcome.\n * @returns The resolved resource.\n */\nexport function useResource<T extends Resource>(\n value: Reference<T> | T | undefined,\n setOutcome?: (outcome: OperationOutcome) => void\n): T | undefined {\n const medplum = useMedplum();\n const [resource, setResource] = useState<T | undefined>(getInitialResource(medplum, value));\n\n const setResourceIfChanged = useCallback(\n (r: T | undefined) => {\n if (!deepEquals(r, resource)) {\n setResource(r);\n }\n },\n [resource, setResource]\n );\n\n useEffect(() => {\n setResourceIfChanged(getInitialResource(medplum, value));\n }, [medplum, value, setResourceIfChanged]);\n\n useEffect(() => {\n let subscribed = true;\n\n if (isReference(value)) {\n medplum\n .readReference(value as Reference<T>)\n .then((r) => {\n if (subscribed) {\n setResourceIfChanged(r);\n }\n })\n .catch((err) => {\n if (subscribed) {\n setResourceIfChanged(undefined);\n if (setOutcome) {\n setOutcome(normalizeOperationOutcome(err));\n }\n }\n });\n }\n\n return (() => (subscribed = false)) as () => void;\n }, [medplum, resource, value, setResourceIfChanged, setOutcome]);\n\n return resource;\n}\n\n/**\n * Returns the initial resource value based on the input value.\n * If the input value is a resource, returns the resource.\n * If the input value is a reference to a resource available in the cache, returns the resource.\n * Otherwise, returns undefined.\n * @param medplum - The medplum client.\n * @param value - The resource or reference to resource.\n * @returns An initial resource if available; undefined otherwise.\n */\nfunction getInitialResource<T extends Resource>(\n medplum: MedplumClient,\n value: Reference<T> | T | undefined\n): T | undefined {\n if (value) {\n if (isResource(value)) {\n return value;\n }\n\n if (isReference(value)) {\n return medplum.getCachedReference(value as Reference<T>);\n }\n }\n\n return undefined;\n}\n", "import { allOk, normalizeOperationOutcome, QueryTypes, ResourceArray } from '@medplum/core';\nimport { Bundle, ExtractResource, OperationOutcome, ResourceType } from '@medplum/fhirtypes';\nimport { useEffect, useState } from 'react';\nimport { useMedplum } from '../MedplumProvider/MedplumProvider.context';\n\ntype SearchFn = 'search' | 'searchOne' | 'searchResources';\n\n/**\n * React hook for searching FHIR resources.\n *\n * This is a convenience hook for calling the MedplumClient.search() method.\n *\n * @param resourceType - The FHIR resource type to search.\n * @param query - Optional search parameters.\n * @returns A 3-element tuple containing the search result, loading flag, and operation outcome.\n */\nexport function useSearch<K extends ResourceType>(\n resourceType: K,\n query?: QueryTypes\n): [Bundle<ExtractResource<K>> | undefined, boolean, OperationOutcome | undefined] {\n return useSearchImpl<K, Bundle<ExtractResource<K>>>('search', resourceType, query);\n}\n\n/**\n * React hook for searching for a single FHIR resource.\n *\n * This is a convenience hook for calling the MedplumClient.searchOne() method.\n *\n * @param resourceType - The FHIR resource type to search.\n * @param query - Optional search parameters.\n * @returns A 3-element tuple containing the search result, loading flag, and operation outcome.\n */\nexport function useSearchOne<K extends ResourceType>(\n resourceType: K,\n query?: QueryTypes\n): [ExtractResource<K> | undefined, boolean, OperationOutcome | undefined] {\n return useSearchImpl<K, ExtractResource<K>>('searchOne', resourceType, query);\n}\n\n/**\n * React hook for searching for an array of FHIR resources.\n *\n * This is a convenience hook for calling the MedplumClient.searchResources() method.\n *\n * @param resourceType - The FHIR resource type to search.\n * @param query - Optional search parameters.\n * @returns A 3-element tuple containing the search result, loading flag, and operation outcome.\n */\nexport function useSearchResources<K extends ResourceType>(\n resourceType: K,\n query?: QueryTypes\n): [ResourceArray<ExtractResource<K>> | undefined, boolean, OperationOutcome | undefined] {\n return useSearchImpl<K, ResourceArray<ExtractResource<K>>>('searchResources', resourceType, query);\n}\n\nfunction useSearchImpl<K extends ResourceType, ReturnType>(\n searchFn: SearchFn,\n resourceType: K,\n query: QueryTypes | undefined\n): [ReturnType | undefined, boolean, OperationOutcome | undefined] {\n const medplum = useMedplum();\n const [searchKey, setSearchKey] = useState<string>();\n const [loading, setLoading] = useState<boolean>(false);\n const [result, setResult] = useState<ReturnType>();\n const [outcome, setOutcome] = useState<OperationOutcome>();\n\n useEffect(() => {\n const key = medplum.fhirSearchUrl(resourceType, query).toString();\n if (key !== searchKey) {\n setSearchKey(key);\n medplum[searchFn](resourceType, query)\n .then((res) => {\n setLoading(false);\n setResult(res as ReturnType);\n setOutcome(allOk);\n })\n .catch((err) => {\n setLoading(false);\n setResult(undefined);\n setOutcome(normalizeOperationOutcome(err));\n });\n }\n }, [medplum, searchFn, resourceType, query, searchKey, setResult]);\n\n return [result, loading, outcome];\n}\n"],
4
+ "sourcesContent": ["import { MedplumClient } from '@medplum/core';\nimport { ReactNode, useEffect, useMemo, useState } from 'react';\nimport { MepdlumNavigateFunction, reactContext } from './MedplumProvider.context';\n\nexport interface MedplumProviderProps {\n medplum: MedplumClient;\n navigate?: MepdlumNavigateFunction;\n children: ReactNode;\n}\n\n/**\n * The MedplumProvider component provides Medplum context state.\n *\n * Medplum context includes:\n * 1) medplum - Medplum client library\n * 2) profile - The current user profile (if signed in)\n * @param props - The MedplumProvider React props.\n * @returns The MedplumProvider React node.\n */\nexport function MedplumProvider(props: MedplumProviderProps): JSX.Element {\n const medplum = props.medplum;\n const navigate = props.navigate ?? defaultNavigate;\n\n const [state, setState] = useState({\n profile: medplum.getProfile(),\n loading: !medplum.isInitialized,\n });\n\n useEffect(() => {\n if (!medplum) {\n return;\n }\n if (!medplum.isInitialized) {\n setState((s) => ({ ...s, loading: true }));\n medplum\n .getInitPromise()\n .then(() => setState((s) => ({ ...s, loading: false })))\n .catch(console.error);\n }\n }, [medplum, medplum.isInitialized]);\n\n useEffect(() => {\n function eventListener(): void {\n setState({\n ...state,\n profile: medplum.getProfile(),\n });\n }\n\n medplum.addEventListener('change', eventListener);\n return () => medplum.removeEventListener('change', eventListener);\n }, [medplum, state]);\n\n const medplumContext = useMemo(\n () => ({\n ...state,\n medplum,\n navigate,\n }),\n [state, medplum, navigate]\n );\n\n return <reactContext.Provider value={medplumContext}>{props.children}</reactContext.Provider>;\n}\n\n/**\n * The default \"navigate\" function which simply uses window.location.href.\n * @param path - The path to navigate to.\n */\nfunction defaultNavigate(path: string): void {\n window.location.assign(path);\n}\n", "import { MedplumClient, ProfileResource } from '@medplum/core';\nimport { createContext, useContext } from 'react';\n\nexport const reactContext = createContext(undefined as MedplumContext | undefined);\n\nexport type MepdlumNavigateFunction = (path: string) => void;\n\nexport interface MedplumContext {\n medplum: MedplumClient;\n navigate: MepdlumNavigateFunction;\n profile?: ProfileResource;\n loading: boolean;\n}\n\n/**\n * Returns the MedplumContext instance.\n * @returns The MedplumContext instance.\n */\nexport function useMedplumContext(): MedplumContext {\n return useContext(reactContext) as MedplumContext;\n}\n\n/**\n * Returns the MedplumClient instance.\n * This is a shortcut for useMedplumContext().medplum.\n * @returns The MedplumClient instance.\n */\nexport function useMedplum(): MedplumClient {\n return useMedplumContext().medplum;\n}\n\n/**\n * Returns the Medplum navigate function.\n * @returns The Medplum navigate function.\n */\nexport function useMedplumNavigate(): MepdlumNavigateFunction {\n return useMedplumContext().navigate;\n}\n\n/**\n * Returns the current Medplum user profile (if signed in).\n * This is a shortcut for useMedplumContext().profile.\n * @returns The current user profile.\n */\nexport function useMedplumProfile(): ProfileResource | undefined {\n return useMedplumContext().profile;\n}\n", "import { deepEquals, isReference, isResource, MedplumClient, normalizeOperationOutcome } from '@medplum/core';\nimport { OperationOutcome, Reference, Resource } from '@medplum/fhirtypes';\nimport { useCallback, useEffect, useState } from 'react';\nimport { useMedplum } from '../MedplumProvider/MedplumProvider.context';\n\n/**\n * React Hook to use a FHIR reference.\n * Handles the complexity of resolving references and caching resources.\n * @param value - The resource or reference to resource.\n * @param setOutcome - Optional callback to set the OperationOutcome.\n * @returns The resolved resource.\n */\nexport function useResource<T extends Resource>(\n value: Reference<T> | Partial<T> | undefined,\n setOutcome?: (outcome: OperationOutcome) => void\n): T | undefined {\n const medplum = useMedplum();\n const [resource, setResource] = useState<T | undefined>(getInitialResource(medplum, value));\n\n const setResourceIfChanged = useCallback(\n (r: T | undefined) => {\n if (!deepEquals(r, resource)) {\n setResource(r);\n }\n },\n [resource, setResource]\n );\n\n useEffect(() => {\n setResourceIfChanged(getInitialResource(medplum, value));\n }, [medplum, value, setResourceIfChanged]);\n\n useEffect(() => {\n let subscribed = true;\n\n if (isReference(value)) {\n medplum\n .readReference(value as Reference<T>)\n .then((r) => {\n if (subscribed) {\n setResourceIfChanged(r);\n }\n })\n .catch((err) => {\n if (subscribed) {\n setResourceIfChanged(undefined);\n if (setOutcome) {\n setOutcome(normalizeOperationOutcome(err));\n }\n }\n });\n }\n\n return (() => (subscribed = false)) as () => void;\n }, [medplum, resource, value, setResourceIfChanged, setOutcome]);\n\n return resource;\n}\n\n/**\n * Returns the initial resource value based on the input value.\n * If the input value is a resource, returns the resource.\n * If the input value is a reference to a resource available in the cache, returns the resource.\n * Otherwise, returns undefined.\n * @param medplum - The medplum client.\n * @param value - The resource or reference to resource.\n * @returns An initial resource if available; undefined otherwise.\n */\nfunction getInitialResource<T extends Resource>(\n medplum: MedplumClient,\n value: Reference<T> | Partial<T> | undefined\n): T | undefined {\n if (value) {\n if (isResource(value)) {\n return value as T;\n }\n\n if (isReference(value)) {\n return medplum.getCachedReference(value as Reference<T>);\n }\n }\n\n return undefined;\n}\n", "import { allOk, normalizeOperationOutcome, QueryTypes, ResourceArray } from '@medplum/core';\nimport { Bundle, ExtractResource, OperationOutcome, ResourceType } from '@medplum/fhirtypes';\nimport { useEffect, useState } from 'react';\nimport { useMedplum } from '../MedplumProvider/MedplumProvider.context';\n\ntype SearchFn = 'search' | 'searchOne' | 'searchResources';\n\n/**\n * React hook for searching FHIR resources.\n *\n * This is a convenience hook for calling the MedplumClient.search() method.\n *\n * @param resourceType - The FHIR resource type to search.\n * @param query - Optional search parameters.\n * @returns A 3-element tuple containing the search result, loading flag, and operation outcome.\n */\nexport function useSearch<K extends ResourceType>(\n resourceType: K,\n query?: QueryTypes\n): [Bundle<ExtractResource<K>> | undefined, boolean, OperationOutcome | undefined] {\n return useSearchImpl<K, Bundle<ExtractResource<K>>>('search', resourceType, query);\n}\n\n/**\n * React hook for searching for a single FHIR resource.\n *\n * This is a convenience hook for calling the MedplumClient.searchOne() method.\n *\n * @param resourceType - The FHIR resource type to search.\n * @param query - Optional search parameters.\n * @returns A 3-element tuple containing the search result, loading flag, and operation outcome.\n */\nexport function useSearchOne<K extends ResourceType>(\n resourceType: K,\n query?: QueryTypes\n): [ExtractResource<K> | undefined, boolean, OperationOutcome | undefined] {\n return useSearchImpl<K, ExtractResource<K>>('searchOne', resourceType, query);\n}\n\n/**\n * React hook for searching for an array of FHIR resources.\n *\n * This is a convenience hook for calling the MedplumClient.searchResources() method.\n *\n * @param resourceType - The FHIR resource type to search.\n * @param query - Optional search parameters.\n * @returns A 3-element tuple containing the search result, loading flag, and operation outcome.\n */\nexport function useSearchResources<K extends ResourceType>(\n resourceType: K,\n query?: QueryTypes\n): [ResourceArray<ExtractResource<K>> | undefined, boolean, OperationOutcome | undefined] {\n return useSearchImpl<K, ResourceArray<ExtractResource<K>>>('searchResources', resourceType, query);\n}\n\nfunction useSearchImpl<K extends ResourceType, ReturnType>(\n searchFn: SearchFn,\n resourceType: K,\n query: QueryTypes | undefined\n): [ReturnType | undefined, boolean, OperationOutcome | undefined] {\n const medplum = useMedplum();\n const [searchKey, setSearchKey] = useState<string>();\n const [loading, setLoading] = useState<boolean>(false);\n const [result, setResult] = useState<ReturnType>();\n const [outcome, setOutcome] = useState<OperationOutcome>();\n\n useEffect(() => {\n const key = medplum.fhirSearchUrl(resourceType, query).toString();\n if (key !== searchKey) {\n setSearchKey(key);\n medplum[searchFn](resourceType, query)\n .then((res) => {\n setLoading(false);\n setResult(res as ReturnType);\n setOutcome(allOk);\n })\n .catch((err) => {\n setLoading(false);\n setResult(undefined);\n setOutcome(normalizeOperationOutcome(err));\n });\n }\n }, [medplum, searchFn, resourceType, query, searchKey, setResult]);\n\n return [result, loading, outcome];\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": ["useEffect", "useMemo", "useState", "createContext", "useContext", "reactContext", "useMedplumContext", "useMedplum", "useMedplumNavigate", "useMedplumProfile", "jsx", "MedplumProvider", "props", "medplum", "navigate", "defaultNavigate", "state", "setState", "useState", "useEffect", "s", "eventListener", "medplumContext", "useMemo", "reactContext", "path", "deepEquals", "isReference", "isResource", "normalizeOperationOutcome", "useCallback", "useEffect", "useState", "useResource", "value", "setOutcome", "medplum", "useMedplum", "resource", "setResource", "useState", "getInitialResource", "setResourceIfChanged", "useCallback", "r", "deepEquals", "useEffect", "subscribed", "isReference", "err", "normalizeOperationOutcome", "isResource", "allOk", "normalizeOperationOutcome", "useEffect", "useState", "useSearch", "resourceType", "query", "useSearchImpl", "useSearchOne", "useSearchResources", "searchFn", "medplum", "useMedplum", "searchKey", "setSearchKey", "useState", "loading", "setLoading", "result", "setResult", "outcome", "setOutcome", "useEffect", "key", "res", "allOk", "err", "normalizeOperationOutcome"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medplum/react-hooks",
3
- "version": "2.2.7",
3
+ "version": "3.0.0",
4
4
  "description": "Medplum React Hooks Library",
5
5
  "keywords": [
6
6
  "medplum",
@@ -61,19 +61,19 @@
61
61
  "@medplum/definitions": "*",
62
62
  "@medplum/fhirtypes": "*",
63
63
  "@medplum/mock": "*",
64
- "@testing-library/dom": "9.3.3",
65
- "@testing-library/jest-dom": "6.1.5",
64
+ "@testing-library/dom": "9.3.4",
65
+ "@testing-library/jest-dom": "6.2.0",
66
66
  "@testing-library/react": "14.1.2",
67
67
  "@types/jest": "29.5.11",
68
- "@types/node": "20.10.3",
69
- "@types/react": "18.2.42",
70
- "@types/react-dom": "18.2.17",
68
+ "@types/node": "20.11.0",
69
+ "@types/react": "18.2.47",
70
+ "@types/react-dom": "18.2.18",
71
71
  "jest": "29.7.0",
72
72
  "jest-each": "29.7.0",
73
73
  "react": "18.2.0",
74
74
  "react-dom": "18.2.0",
75
75
  "rimraf": "5.0.5",
76
- "typescript": "5.3.2"
76
+ "typescript": "5.3.3"
77
77
  },
78
78
  "peerDependencies": {
79
79
  "@medplum/core": "*",