@medplum/react 0.9.28 → 0.9.31

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.
Files changed (240) hide show
  1. package/dist/cjs/AddressDisplay.d.ts +6 -0
  2. package/dist/cjs/AddressInput.d.ts +8 -0
  3. package/dist/cjs/AnnotationInput.d.ts +8 -0
  4. package/dist/cjs/AttachmentArrayDisplay.d.ts +7 -0
  5. package/dist/cjs/AttachmentArrayInput.d.ts +9 -0
  6. package/dist/cjs/AttachmentDisplay.d.ts +7 -0
  7. package/dist/cjs/AttachmentInput.d.ts +9 -0
  8. package/dist/cjs/Autocomplete.d.ts +20 -0
  9. package/dist/cjs/Avatar.d.ts +12 -0
  10. package/dist/cjs/BackboneElementDisplay.d.ts +9 -0
  11. package/dist/cjs/BackboneElementInput.d.ts +9 -0
  12. package/dist/cjs/Button.d.ts +15 -0
  13. package/dist/cjs/CalendarInput.d.ts +16 -0
  14. package/dist/cjs/Checkbox.d.ts +12 -0
  15. package/dist/cjs/CheckboxFormSection.d.ts +9 -0
  16. package/dist/cjs/CodeInput.d.ts +9 -0
  17. package/dist/cjs/CodeableConceptDisplay.d.ts +6 -0
  18. package/dist/cjs/CodeableConceptInput.d.ts +9 -0
  19. package/dist/cjs/CodingDisplay.d.ts +6 -0
  20. package/dist/cjs/CodingInput.d.ts +9 -0
  21. package/dist/cjs/ContactDetailDisplay.d.ts +6 -0
  22. package/dist/cjs/ContactDetailInput.d.ts +8 -0
  23. package/dist/cjs/ContactPointDisplay.d.ts +6 -0
  24. package/dist/cjs/ContactPointInput.d.ts +8 -0
  25. package/dist/cjs/DateTimeInput.d.ts +23 -0
  26. package/dist/cjs/DefaultResourceTimeline.d.ts +6 -0
  27. package/dist/cjs/DescriptionList.d.ts +12 -0
  28. package/dist/cjs/DiagnosticReportDisplay.d.ts +12 -0
  29. package/dist/cjs/Dialog.d.ts +10 -0
  30. package/dist/cjs/Document.d.ts +7 -0
  31. package/dist/cjs/EncounterTimeline.d.ts +6 -0
  32. package/dist/cjs/ErrorBoundary.d.ts +18 -0
  33. package/dist/cjs/ExtensionInput.d.ts +8 -0
  34. package/dist/cjs/FhirPathDisplay.d.ts +9 -0
  35. package/dist/cjs/FhirPathTable.d.ts +29 -0
  36. package/dist/cjs/FooterLinks.d.ts +6 -0
  37. package/dist/cjs/Form.d.ts +8 -0
  38. package/dist/cjs/FormSection.d.ts +11 -0
  39. package/dist/cjs/FormUtils.d.ts +5 -0
  40. package/dist/cjs/GoogleButton.d.ts +8 -0
  41. package/dist/cjs/Header.d.ts +12 -0
  42. package/dist/cjs/HeaderSearchInput.d.ts +10 -0
  43. package/dist/cjs/HumanNameDisplay.d.ts +8 -0
  44. package/dist/cjs/HumanNameInput.d.ts +8 -0
  45. package/dist/cjs/IdentifierDisplay.d.ts +6 -0
  46. package/dist/cjs/IdentifierInput.d.ts +8 -0
  47. package/dist/cjs/Input.d.ts +22 -0
  48. package/dist/cjs/InputRow.d.ts +7 -0
  49. package/dist/cjs/Loading.d.ts +3 -0
  50. package/dist/cjs/Logo.d.ts +6 -0
  51. package/dist/cjs/MedplumLink.d.ts +13 -0
  52. package/dist/cjs/MedplumProvider.d.ts +34 -0
  53. package/dist/cjs/MenuItem.d.ts +9 -0
  54. package/dist/cjs/MenuSeparator.d.ts +3 -0
  55. package/dist/cjs/PatientTimeline.d.ts +6 -0
  56. package/dist/cjs/PeriodInput.d.ts +8 -0
  57. package/dist/cjs/PlanDefinitionBuilder.d.ts +7 -0
  58. package/dist/cjs/Popup.d.ts +14 -0
  59. package/dist/cjs/QuantityDisplay.d.ts +7 -0
  60. package/dist/cjs/QuantityInput.d.ts +8 -0
  61. package/dist/cjs/QuestionnaireBuilder.d.ts +8 -0
  62. package/dist/cjs/QuestionnaireForm.d.ts +14 -0
  63. package/dist/cjs/QuestionnaireUtils.d.ts +30 -0
  64. package/dist/cjs/RangeDisplay.d.ts +7 -0
  65. package/dist/cjs/RangeInput.d.ts +14 -0
  66. package/dist/cjs/RatioDisplay.d.ts +6 -0
  67. package/dist/cjs/RatioInput.d.ts +14 -0
  68. package/dist/cjs/ReferenceDisplay.d.ts +7 -0
  69. package/dist/cjs/ReferenceInput.d.ts +9 -0
  70. package/dist/cjs/RequestGroupDisplay.d.ts +9 -0
  71. package/dist/cjs/ResourceArrayDisplay.d.ts +11 -0
  72. package/dist/cjs/ResourceArrayInput.d.ts +11 -0
  73. package/dist/cjs/ResourceBadge.d.ts +9 -0
  74. package/dist/cjs/ResourceBlame.d.ts +10 -0
  75. package/dist/cjs/ResourceDiff.d.ts +9 -0
  76. package/dist/cjs/ResourceDiffTable.d.ts +9 -0
  77. package/dist/cjs/ResourceForm.d.ts +10 -0
  78. package/dist/cjs/ResourceHistoryTable.d.ts +9 -0
  79. package/dist/cjs/ResourceInput.d.ts +12 -0
  80. package/dist/cjs/ResourceName.d.ts +7 -0
  81. package/dist/cjs/ResourcePropertyDisplay.d.ts +24 -0
  82. package/dist/cjs/ResourcePropertyInput.d.ts +21 -0
  83. package/dist/cjs/ResourceTable.d.ts +7 -0
  84. package/dist/cjs/ResourceTimeline.d.ts +11 -0
  85. package/dist/cjs/Scheduler.d.ts +7 -0
  86. package/dist/cjs/Scrollable.d.ts +9 -0
  87. package/dist/cjs/SearchControl.d.ts +40 -0
  88. package/dist/cjs/SearchControlField.d.ts +41 -0
  89. package/dist/cjs/SearchFieldEditor.d.ts +11 -0
  90. package/dist/cjs/SearchFilterEditor.d.ts +11 -0
  91. package/dist/cjs/SearchFilterValueDialog.d.ts +15 -0
  92. package/dist/cjs/SearchFilterValueDisplay.d.ts +7 -0
  93. package/dist/cjs/SearchFilterValueInput.d.ts +12 -0
  94. package/dist/cjs/SearchPopupMenu.d.ts +15 -0
  95. package/dist/cjs/SearchUtils.d.ts +174 -0
  96. package/dist/cjs/Select.d.ts +16 -0
  97. package/dist/cjs/ServiceRequestTimeline.d.ts +6 -0
  98. package/dist/cjs/StatusBadge.d.ts +6 -0
  99. package/dist/cjs/SubMenu.d.ts +7 -0
  100. package/dist/cjs/Tab.d.ts +12 -0
  101. package/dist/cjs/TabList.d.ts +10 -0
  102. package/dist/cjs/TabPanel.d.ts +6 -0
  103. package/dist/cjs/TabSwitch.d.ts +6 -0
  104. package/dist/cjs/TextArea.d.ts +18 -0
  105. package/dist/cjs/Timeline.d.ts +17 -0
  106. package/dist/cjs/TimingInput.d.ts +8 -0
  107. package/dist/cjs/TitleBar.d.ts +6 -0
  108. package/dist/cjs/UploadButton.d.ts +7 -0
  109. package/dist/cjs/auth/AuthenticationForm.d.ts +14 -0
  110. package/dist/cjs/auth/ChooseProfileForm.d.ts +8 -0
  111. package/dist/cjs/auth/NewProjectForm.d.ts +7 -0
  112. package/dist/cjs/auth/NewUserForm.d.ts +10 -0
  113. package/dist/cjs/auth/RegisterForm.d.ts +12 -0
  114. package/dist/{esm → cjs/auth}/SignInForm.d.ts +1 -1
  115. package/dist/cjs/constants.d.ts +1 -0
  116. package/dist/cjs/index.d.ts +87 -0
  117. package/dist/cjs/index.js +660 -565
  118. package/dist/cjs/index.js.map +1 -1
  119. package/dist/cjs/index.min.js +1 -1
  120. package/dist/cjs/index.min.js.map +1 -1
  121. package/dist/cjs/stories/AddressInput.stories.d.ts +6 -0
  122. package/dist/cjs/stories/AttachmentArrayInput.stories.d.ts +6 -0
  123. package/dist/cjs/stories/AttachmentInput.stories.d.ts +6 -0
  124. package/dist/cjs/stories/Autocomplete.stories.d.ts +9 -0
  125. package/dist/cjs/stories/Avatar.stories.d.ts +10 -0
  126. package/dist/cjs/stories/Button.stories.d.ts +9 -0
  127. package/dist/cjs/stories/CodeableConceptDisplay.stories.d.ts +8 -0
  128. package/dist/cjs/stories/DiagnosticReportDisplay.stories.d.ts +5 -0
  129. package/dist/cjs/stories/Dialog.stories.d.ts +5 -0
  130. package/dist/cjs/stories/EncounterTimeline.stories.d.ts +5 -0
  131. package/dist/cjs/stories/FhirPathDisplay.stories.d.ts +7 -0
  132. package/dist/cjs/stories/FormSection.stories.d.ts +6 -0
  133. package/dist/cjs/stories/Header.stories.d.ts +8 -0
  134. package/dist/cjs/stories/Input.stories.d.ts +6 -0
  135. package/dist/cjs/stories/Loading.stories.d.ts +5 -0
  136. package/dist/cjs/stories/Logo.stories.d.ts +5 -0
  137. package/dist/cjs/stories/PatientTimeline.stories.d.ts +5 -0
  138. package/dist/cjs/stories/PlanDefinitionBuilder.stories.d.ts +5 -0
  139. package/dist/cjs/stories/QuestionnaireBuilder.stories.d.ts +7 -0
  140. package/dist/cjs/stories/QuestionnaireForm.stories.d.ts +11 -0
  141. package/dist/cjs/stories/ReferenceInput.stories.d.ts +6 -0
  142. package/dist/cjs/stories/RegisterForm.stories.d.ts +7 -0
  143. package/dist/cjs/stories/RequestGroupDisplay.stories.d.ts +5 -0
  144. package/dist/cjs/stories/ResourceBlame.stories.d.ts +5 -0
  145. package/dist/cjs/stories/ResourceForm.stories.d.ts +12 -0
  146. package/dist/cjs/stories/ResourceHistoryTable.stories.d.ts +5 -0
  147. package/dist/cjs/stories/ResourceTable.stories.d.ts +7 -0
  148. package/dist/cjs/stories/Scheduler.stories.d.ts +5 -0
  149. package/dist/cjs/stories/SearchControl.stories.d.ts +13 -0
  150. package/dist/cjs/stories/Select.stories.d.ts +6 -0
  151. package/dist/cjs/stories/SignInForm.stories.d.ts +8 -0
  152. package/dist/cjs/stories/StatusBadge.stories.d.ts +5 -0
  153. package/dist/cjs/stories/Tabs.stories.d.ts +6 -0
  154. package/dist/cjs/stories/Timeline.stories.d.ts +5 -0
  155. package/dist/cjs/stories/TimingInput.stories.d.ts +6 -0
  156. package/dist/cjs/stories/UploadButton.stories.d.ts +6 -0
  157. package/dist/cjs/styles.css +248 -247
  158. package/dist/cjs/test.setup.d.ts +1 -0
  159. package/dist/cjs/useResource.d.ts +8 -0
  160. package/dist/cjs/utils/blame.d.ts +8 -0
  161. package/dist/cjs/utils/date.d.ts +6 -0
  162. package/dist/cjs/utils/diff.d.ts +16 -0
  163. package/dist/cjs/utils/dom.d.ts +15 -0
  164. package/dist/cjs/utils/outcomes.d.ts +2 -0
  165. package/dist/cjs/utils/recaptcha.d.ts +12 -0
  166. package/dist/cjs/utils.d.ts +5 -0
  167. package/dist/esm/Autocomplete.js +1 -0
  168. package/dist/esm/Autocomplete.js.map +1 -1
  169. package/dist/esm/CalendarInput.d.ts +1 -0
  170. package/dist/esm/CalendarInput.js +6 -5
  171. package/dist/esm/CalendarInput.js.map +1 -1
  172. package/dist/esm/CodeInput.js +1 -1
  173. package/dist/esm/CodeInput.js.map +1 -1
  174. package/dist/esm/CodeableConceptInput.js +1 -1
  175. package/dist/esm/CodeableConceptInput.js.map +1 -1
  176. package/dist/esm/CodingInput.js +1 -1
  177. package/dist/esm/CodingInput.js.map +1 -1
  178. package/dist/esm/FhirPathTable.js +5 -2
  179. package/dist/esm/FhirPathTable.js.map +1 -1
  180. package/dist/esm/GoogleButton.js +1 -1
  181. package/dist/esm/GoogleButton.js.map +1 -1
  182. package/dist/esm/Header.js +7 -3
  183. package/dist/esm/Header.js.map +1 -1
  184. package/dist/esm/MedplumLink.js +29 -14
  185. package/dist/esm/MedplumLink.js.map +1 -1
  186. package/dist/esm/PlanDefinitionBuilder.js +1 -1
  187. package/dist/esm/PlanDefinitionBuilder.js.map +1 -1
  188. package/dist/esm/QuestionnaireBuilder.js +1 -1
  189. package/dist/esm/QuestionnaireBuilder.js.map +1 -1
  190. package/dist/esm/QuestionnaireForm.js +2 -1
  191. package/dist/esm/QuestionnaireForm.js.map +1 -1
  192. package/dist/esm/RequestGroupDisplay.js +1 -1
  193. package/dist/esm/RequestGroupDisplay.js.map +1 -1
  194. package/dist/esm/ResourceBlame.js +1 -1
  195. package/dist/esm/ResourceBlame.js.map +1 -1
  196. package/dist/esm/ResourceDiffTable.js +1 -1
  197. package/dist/esm/ResourceDiffTable.js.map +1 -1
  198. package/dist/esm/ResourceForm.js +1 -1
  199. package/dist/esm/ResourceForm.js.map +1 -1
  200. package/dist/esm/ResourceHistoryTable.js +19 -12
  201. package/dist/esm/ResourceHistoryTable.js.map +1 -1
  202. package/dist/esm/ResourceTable.js +1 -1
  203. package/dist/esm/ResourceTable.js.map +1 -1
  204. package/dist/esm/ResourceTimeline.js +16 -8
  205. package/dist/esm/ResourceTimeline.js.map +1 -1
  206. package/dist/esm/Scheduler.js +13 -6
  207. package/dist/esm/Scheduler.js.map +1 -1
  208. package/dist/esm/SearchControl.js +5 -2
  209. package/dist/esm/SearchControl.js.map +1 -1
  210. package/dist/esm/auth/AuthenticationForm.d.ts +14 -0
  211. package/dist/esm/{SignInForm.js → auth/AuthenticationForm.js} +12 -75
  212. package/dist/esm/auth/AuthenticationForm.js.map +1 -0
  213. package/dist/esm/auth/ChooseProfileForm.d.ts +8 -0
  214. package/dist/esm/auth/ChooseProfileForm.js +32 -0
  215. package/dist/esm/auth/ChooseProfileForm.js.map +1 -0
  216. package/dist/esm/auth/NewProjectForm.d.ts +7 -0
  217. package/dist/esm/auth/NewProjectForm.js +42 -0
  218. package/dist/esm/auth/NewProjectForm.js.map +1 -0
  219. package/dist/esm/auth/NewUserForm.d.ts +10 -0
  220. package/dist/esm/auth/NewUserForm.js +87 -0
  221. package/dist/esm/auth/NewUserForm.js.map +1 -0
  222. package/dist/esm/auth/RegisterForm.d.ts +12 -0
  223. package/dist/esm/auth/RegisterForm.js +39 -0
  224. package/dist/esm/auth/RegisterForm.js.map +1 -0
  225. package/dist/esm/auth/SignInForm.d.ts +17 -0
  226. package/dist/esm/auth/SignInForm.js +52 -0
  227. package/dist/esm/auth/SignInForm.js.map +1 -0
  228. package/dist/esm/index.d.ts +3 -2
  229. package/dist/esm/index.js +3 -2
  230. package/dist/esm/index.js.map +1 -1
  231. package/dist/esm/index.min.js +1 -1
  232. package/dist/esm/index.min.js.map +1 -1
  233. package/dist/esm/styles.css +248 -247
  234. package/dist/esm/utils/recaptcha.js +10 -4
  235. package/dist/esm/utils/recaptcha.js.map +1 -1
  236. package/package.json +16 -18
  237. package/dist/esm/RegisterForm.d.ts +0 -18
  238. package/dist/esm/RegisterForm.js +0 -121
  239. package/dist/esm/RegisterForm.js.map +0 -1
  240. package/dist/esm/SignInForm.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Autocomplete.js","sources":["../../src/Autocomplete.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport './Autocomplete.css';\nimport { killEvent } from './utils/dom';\n\nexport interface AutocompleteProps<T> {\n name: string;\n multiple?: boolean;\n autofocus?: boolean;\n defaultValue?: T[];\n className?: string;\n placeholder?: string;\n loadOnFocus?: boolean;\n loadOptions: (input: string, signal: AbortSignal) => Promise<T[]>;\n buildUnstructured?: (input: string) => T;\n getId: (item: T) => string;\n getIcon?: (item: T) => JSX.Element;\n getDisplay: (item: T) => JSX.Element;\n getHelpText?: (item: T) => string | undefined;\n onChange?: (values: T[]) => void;\n onCreateNew?: () => void;\n}\n\nexport function Autocomplete<T>(props: AutocompleteProps<T>): JSX.Element {\n const inputRef = useRef<HTMLInputElement>(null);\n const [focused, setFocused] = useState(false);\n const [lastValue, setLastValue] = useState<string | undefined>(undefined);\n const [timer, setTimer] = useState<number>();\n const [dropDownVisible, setDropDownVisible] = useState(false);\n const [values, setValues] = useState(props.defaultValue ?? []);\n const [options, setOptions] = useState<T[]>([]);\n const [selectedIndex, setSelectedIndex] = useState(-1);\n const [abortController, setAbortController] = useState<AbortController>();\n const [autoSubmit, setAutoSubmit] = useState<boolean>();\n\n const lastValueRef = useRef<string>();\n lastValueRef.current = lastValue;\n\n const timerRef = useRef<number>();\n timerRef.current = timer;\n\n const abortControllerRef = useRef<AbortController>();\n abortControllerRef.current = abortController;\n\n const autoSubmitRef = useRef<boolean>();\n autoSubmitRef.current = autoSubmit;\n\n useEffect(() => {\n return () => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n }\n };\n }, []);\n\n useEffect(() => {\n setValues(props.defaultValue ?? []);\n }, [props.defaultValue]);\n\n function setValuesWrapper(newValues: T[]): void {\n setValues(newValues);\n if (props.onChange) {\n props.onChange(newValues);\n }\n }\n\n /**\n * Adds an option to the list of selected options.\n * @param option The option.\n */\n function addOption(option: T): void {\n const inputElement = inputRef.current as HTMLInputElement;\n inputElement.value = '';\n\n const newValues = props.multiple ? [...values, option] : [option];\n setFocused(true);\n setDropDownVisible(false);\n setLastValue('');\n setOptions([]);\n setSelectedIndex(-1);\n setValuesWrapper(newValues);\n }\n\n function handleClick(): void {\n inputRef.current?.focus();\n }\n\n function handleFocus(): void {\n setFocused(true);\n if (props.loadOnFocus) {\n handleInput();\n }\n }\n\n function handleBlur(): void {\n setFocused(false);\n dismissOnDelay();\n }\n\n /**\n * Handles an input event.\n * Clears existing timers.\n * Schedules a timer to execute the search after a short delay.\n */\n function handleInput(): void {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n setAbortController(undefined);\n }\n\n if (timerRef.current !== undefined) {\n window.clearTimeout(timerRef.current);\n }\n\n const newTimer = window.setTimeout(() => handleTimer(), 100);\n setTimer(newTimer);\n }\n\n function handleKeyDown(e: React.KeyboardEvent): void {\n switch (e.key) {\n case 'Enter':\n case 'Tab':\n handleSelectKey(e);\n break;\n\n case 'ArrowUp':\n moveSelection(-1);\n killEvent(e);\n break;\n\n case 'ArrowDown':\n moveSelection(1);\n killEvent(e);\n break;\n\n case 'Backspace':\n handleBackspaceKey(e);\n break;\n\n case ',':\n case ';':\n handleSeparatorKey(e);\n }\n }\n\n /**\n * Handles the \"enter\" or \"tab\" keys. The enter key logic is:\n * Try to add an option with tryAddOption. On success, cancel event.\n * Otherwise, let the browser handle the enter key normally.\n *\n * @param e The key down event.\n */\n function handleSelectKey(e: React.KeyboardEvent): void {\n if (!timerRef.current && !abortControllerRef.current && tryAddOption()) {\n killEvent(e);\n inputRef.current?.focus();\n } else {\n // The user pressed enter, but we don't have results yet.\n // We need to wait for the results to come in.\n setAutoSubmit(true);\n }\n }\n\n /**\n * Handles the \"backspace\" key. The backspace key logic is:\n * If the input is empty and there is at least one item, delete the last item.\n * Otherwise, let the browser handle the backspace key normally.\n *\n * @param e The key down event.\n */\n function handleBackspaceKey(e: React.KeyboardEvent): void {\n if (inputRef.current?.value) {\n // If there is still text in the input,\n // then handle backspace as normal.\n return;\n }\n\n if (values.length > 0) {\n // If there are selected items,\n // then delete the last item.\n killEvent(e);\n setValuesWrapper(values.slice(0, values.length - 1));\n }\n }\n\n /**\n * Handles a \"separator\" key (comma, semicolon, others?).\n *\n * The separator key logic is:\n * If the drop down is visible and something is selected, choose that.\n * If the drop down is visible but nothing is selected, choose the first.\n * If there is content in the input, use that as a \"gray\" option.\n * Otherwise, ignore.\n *\n * @param e The key down event.\n */\n function handleSeparatorKey(e: React.KeyboardEvent): void {\n tryAddOption();\n killEvent(e);\n inputRef.current?.focus();\n }\n\n /**\n * Tries to capture the existing input as an option.\n *\n * @return True if captured an option; false otherwise.\n */\n function tryAddOption(): boolean {\n let option: T | undefined;\n\n if (selectedIndex >= 0 && selectedIndex < options.length) {\n // Currently highlighted row\n option = options[selectedIndex];\n } else if (selectedIndex === -1 && options.length > 0) {\n // Default to first row\n option = options[0];\n } else if (props.buildUnstructured && inputRef.current?.value) {\n // Build semi-structured item\n option = props.buildUnstructured(inputRef.current.value);\n }\n\n if (!option) {\n return false;\n }\n\n addOption(option);\n return true;\n }\n\n /**\n * Handles a timer tick event.\n * If the contents of the input have changed, sends xhr to the server\n * for updated contents.\n */\n function handleTimer(): void {\n setTimer(undefined);\n\n const value = inputRef.current?.value?.trim() || '';\n if (value === lastValueRef.current) {\n // Nothing has changed, move on\n return;\n }\n\n setLastValue(value);\n\n const newAbortController = new AbortController();\n setAbortController(newAbortController);\n\n props\n .loadOptions(value, newAbortController.signal)\n .then((newOptions: T[]) => {\n if (!newAbortController.signal.aborted) {\n setDropDownVisible(newOptions.length > 0);\n setOptions(newOptions);\n setAbortController(undefined);\n if (autoSubmitRef.current) {\n addOption(newOptions[0]);\n setAutoSubmit(false);\n }\n }\n })\n .catch(console.log);\n }\n\n /**\n * Moves the selected row.\n * @param delta The amount to move the selection, up is negative.\n */\n function moveSelection(delta: number): void {\n let index = selectedIndex + delta;\n\n if (index < 0) {\n index = 0;\n } else if (index >= options.length) {\n index = options.length - 1;\n }\n\n setSelectedIndex(index);\n }\n\n /**\n * Handles a hover event.\n * @param _e The mouse event.\n * @param index The drop down option index.\n */\n function handleDropDownHover(_e: React.MouseEvent, index: number): void {\n setSelectedIndex(index);\n }\n\n /**\n * Handles a click event.\n * @param e The mouse event.\n * @param option The drop down option.\n */\n function handleDropDownClick(e: React.MouseEvent, option: T): void {\n killEvent(e);\n addOption(option);\n }\n\n /**\n * Dismisses the drop down menu after a slight delay.\n */\n function dismissOnDelay(): void {\n window.setTimeout(() => {\n setDropDownVisible(false);\n }, 200);\n }\n\n const baseClassName = props.className ?? 'medplum-autocomplete-container';\n\n return (\n <div\n data-testid=\"autocomplete\"\n className={baseClassName + (focused ? ' focused' : '')}\n onClick={() => handleClick()}\n >\n <ul onClick={() => handleClick()}>\n {values.map((value) => (\n <li key={props.getId(value)} data-testid=\"selected\" className=\"medplum-autocomplete-item choice\">\n {props.getDisplay(value)}\n </li>\n ))}\n <li className=\"medplum-autocomplete-item\">\n <input\n type=\"text\"\n autoFocus={props.autofocus}\n placeholder={values.length === 0 ? props.placeholder : undefined}\n autoComplete=\"off\"\n autoCapitalize=\"off\"\n spellCheck=\"true\"\n onFocus={() => handleFocus()}\n onBlur={() => handleBlur()}\n onChange={() => handleInput()}\n onInput={() => handleInput()}\n onKeyDown={(e: React.KeyboardEvent) => handleKeyDown(e)}\n ref={inputRef}\n data-testid=\"input-element\"\n />\n </li>\n </ul>\n {dropDownVisible && (\n <div className=\"medplum-autocomplete\" data-testid=\"dropdown\">\n {options.map((option, index) => (\n <div\n key={props.getId(option)}\n className={\n index === selectedIndex\n ? 'medplum-autocomplete-row medplum-autocomplete-active'\n : 'medplum-autocomplete-row'\n }\n onMouseOver={(e) => handleDropDownHover(e, index)}\n onClick={(e) => handleDropDownClick(e, option)}\n >\n {props.getIcon && <div className=\"medplum-autocomplete-icon\">{props.getIcon(option)}</div>}\n <div className=\"medplum-autocomplete-label\">\n {props.getDisplay(option)}\n {props.getHelpText && <div className=\"medplum-autocomplete-help-text\">{props.getHelpText(option)}</div>}\n </div>\n </div>\n ))}\n {props.onCreateNew && (\n <div className=\"medplum-autocomplete-row\" onClick={props.onCreateNew}>\n <div className=\"medplum-autocomplete-label\">Create new...</div>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Autocomplete.js","sources":["../../src/Autocomplete.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport { killEvent } from './utils/dom';\nimport './Autocomplete.css';\n\nexport interface AutocompleteProps<T> {\n name: string;\n multiple?: boolean;\n autofocus?: boolean;\n defaultValue?: T[];\n className?: string;\n placeholder?: string;\n loadOnFocus?: boolean;\n loadOptions: (input: string, signal: AbortSignal) => Promise<T[]>;\n buildUnstructured?: (input: string) => T;\n getId: (item: T) => string;\n getIcon?: (item: T) => JSX.Element;\n getDisplay: (item: T) => JSX.Element;\n getHelpText?: (item: T) => string | undefined;\n onChange?: (values: T[]) => void;\n onCreateNew?: () => void;\n}\n\nexport function Autocomplete<T>(props: AutocompleteProps<T>): JSX.Element {\n const inputRef = useRef<HTMLInputElement>(null);\n const [focused, setFocused] = useState(false);\n const [lastValue, setLastValue] = useState<string | undefined>(undefined);\n const [timer, setTimer] = useState<number>();\n const [dropDownVisible, setDropDownVisible] = useState(false);\n const [values, setValues] = useState(props.defaultValue ?? []);\n const [options, setOptions] = useState<T[]>([]);\n const [selectedIndex, setSelectedIndex] = useState(-1);\n const [abortController, setAbortController] = useState<AbortController>();\n const [autoSubmit, setAutoSubmit] = useState<boolean>();\n\n const lastValueRef = useRef<string>();\n lastValueRef.current = lastValue;\n\n const timerRef = useRef<number>();\n timerRef.current = timer;\n\n const abortControllerRef = useRef<AbortController>();\n abortControllerRef.current = abortController;\n\n const autoSubmitRef = useRef<boolean>();\n autoSubmitRef.current = autoSubmit;\n\n useEffect(() => {\n return () => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n }\n };\n }, []);\n\n useEffect(() => {\n setValues(props.defaultValue ?? []);\n }, [props.defaultValue]);\n\n function setValuesWrapper(newValues: T[]): void {\n setValues(newValues);\n if (props.onChange) {\n props.onChange(newValues);\n }\n }\n\n /**\n * Adds an option to the list of selected options.\n * @param option The option.\n */\n function addOption(option: T): void {\n const inputElement = inputRef.current as HTMLInputElement;\n inputElement.value = '';\n\n const newValues = props.multiple ? [...values, option] : [option];\n setFocused(true);\n setDropDownVisible(false);\n setLastValue('');\n setOptions([]);\n setSelectedIndex(-1);\n setValuesWrapper(newValues);\n }\n\n function handleClick(): void {\n inputRef.current?.focus();\n }\n\n function handleFocus(): void {\n setFocused(true);\n if (props.loadOnFocus) {\n handleInput();\n }\n }\n\n function handleBlur(): void {\n tryAddOption();\n setFocused(false);\n dismissOnDelay();\n }\n\n /**\n * Handles an input event.\n * Clears existing timers.\n * Schedules a timer to execute the search after a short delay.\n */\n function handleInput(): void {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n setAbortController(undefined);\n }\n\n if (timerRef.current !== undefined) {\n window.clearTimeout(timerRef.current);\n }\n\n const newTimer = window.setTimeout(() => handleTimer(), 100);\n setTimer(newTimer);\n }\n\n function handleKeyDown(e: React.KeyboardEvent): void {\n switch (e.key) {\n case 'Enter':\n case 'Tab':\n handleSelectKey(e);\n break;\n\n case 'ArrowUp':\n moveSelection(-1);\n killEvent(e);\n break;\n\n case 'ArrowDown':\n moveSelection(1);\n killEvent(e);\n break;\n\n case 'Backspace':\n handleBackspaceKey(e);\n break;\n\n case ',':\n case ';':\n handleSeparatorKey(e);\n }\n }\n\n /**\n * Handles the \"enter\" or \"tab\" keys. The enter key logic is:\n * Try to add an option with tryAddOption. On success, cancel event.\n * Otherwise, let the browser handle the enter key normally.\n *\n * @param e The key down event.\n */\n function handleSelectKey(e: React.KeyboardEvent): void {\n if (!timerRef.current && !abortControllerRef.current && tryAddOption()) {\n killEvent(e);\n inputRef.current?.focus();\n } else {\n // The user pressed enter, but we don't have results yet.\n // We need to wait for the results to come in.\n setAutoSubmit(true);\n }\n }\n\n /**\n * Handles the \"backspace\" key. The backspace key logic is:\n * If the input is empty and there is at least one item, delete the last item.\n * Otherwise, let the browser handle the backspace key normally.\n *\n * @param e The key down event.\n */\n function handleBackspaceKey(e: React.KeyboardEvent): void {\n if (inputRef.current?.value) {\n // If there is still text in the input,\n // then handle backspace as normal.\n return;\n }\n\n if (values.length > 0) {\n // If there are selected items,\n // then delete the last item.\n killEvent(e);\n setValuesWrapper(values.slice(0, values.length - 1));\n }\n }\n\n /**\n * Handles a \"separator\" key (comma, semicolon, others?).\n *\n * The separator key logic is:\n * If the drop down is visible and something is selected, choose that.\n * If the drop down is visible but nothing is selected, choose the first.\n * If there is content in the input, use that as a \"gray\" option.\n * Otherwise, ignore.\n *\n * @param e The key down event.\n */\n function handleSeparatorKey(e: React.KeyboardEvent): void {\n tryAddOption();\n killEvent(e);\n inputRef.current?.focus();\n }\n\n /**\n * Tries to capture the existing input as an option.\n *\n * @return True if captured an option; false otherwise.\n */\n function tryAddOption(): boolean {\n let option: T | undefined;\n\n if (selectedIndex >= 0 && selectedIndex < options.length) {\n // Currently highlighted row\n option = options[selectedIndex];\n } else if (selectedIndex === -1 && options.length > 0) {\n // Default to first row\n option = options[0];\n } else if (props.buildUnstructured && inputRef.current?.value) {\n // Build semi-structured item\n option = props.buildUnstructured(inputRef.current.value);\n }\n\n if (!option) {\n return false;\n }\n\n addOption(option);\n return true;\n }\n\n /**\n * Handles a timer tick event.\n * If the contents of the input have changed, sends xhr to the server\n * for updated contents.\n */\n function handleTimer(): void {\n setTimer(undefined);\n\n const value = inputRef.current?.value?.trim() || '';\n if (value === lastValueRef.current) {\n // Nothing has changed, move on\n return;\n }\n\n setLastValue(value);\n\n const newAbortController = new AbortController();\n setAbortController(newAbortController);\n\n props\n .loadOptions(value, newAbortController.signal)\n .then((newOptions: T[]) => {\n if (!newAbortController.signal.aborted) {\n setDropDownVisible(newOptions.length > 0);\n setOptions(newOptions);\n setAbortController(undefined);\n if (autoSubmitRef.current) {\n addOption(newOptions[0]);\n setAutoSubmit(false);\n }\n }\n })\n .catch(console.log);\n }\n\n /**\n * Moves the selected row.\n * @param delta The amount to move the selection, up is negative.\n */\n function moveSelection(delta: number): void {\n let index = selectedIndex + delta;\n\n if (index < 0) {\n index = 0;\n } else if (index >= options.length) {\n index = options.length - 1;\n }\n\n setSelectedIndex(index);\n }\n\n /**\n * Handles a hover event.\n * @param _e The mouse event.\n * @param index The drop down option index.\n */\n function handleDropDownHover(_e: React.MouseEvent, index: number): void {\n setSelectedIndex(index);\n }\n\n /**\n * Handles a click event.\n * @param e The mouse event.\n * @param option The drop down option.\n */\n function handleDropDownClick(e: React.MouseEvent, option: T): void {\n killEvent(e);\n addOption(option);\n }\n\n /**\n * Dismisses the drop down menu after a slight delay.\n */\n function dismissOnDelay(): void {\n window.setTimeout(() => {\n setDropDownVisible(false);\n }, 200);\n }\n\n const baseClassName = props.className ?? 'medplum-autocomplete-container';\n\n return (\n <div\n data-testid=\"autocomplete\"\n className={baseClassName + (focused ? ' focused' : '')}\n onClick={() => handleClick()}\n >\n <ul onClick={() => handleClick()}>\n {values.map((value) => (\n <li key={props.getId(value)} data-testid=\"selected\" className=\"medplum-autocomplete-item choice\">\n {props.getDisplay(value)}\n </li>\n ))}\n <li className=\"medplum-autocomplete-item\">\n <input\n type=\"text\"\n autoFocus={props.autofocus}\n placeholder={values.length === 0 ? props.placeholder : undefined}\n autoComplete=\"off\"\n autoCapitalize=\"off\"\n spellCheck=\"true\"\n onFocus={() => handleFocus()}\n onBlur={() => handleBlur()}\n onChange={() => handleInput()}\n onInput={() => handleInput()}\n onKeyDown={(e: React.KeyboardEvent) => handleKeyDown(e)}\n ref={inputRef}\n data-testid=\"input-element\"\n />\n </li>\n </ul>\n {dropDownVisible && (\n <div className=\"medplum-autocomplete\" data-testid=\"dropdown\">\n {options.map((option, index) => (\n <div\n key={props.getId(option)}\n className={\n index === selectedIndex\n ? 'medplum-autocomplete-row medplum-autocomplete-active'\n : 'medplum-autocomplete-row'\n }\n onMouseOver={(e) => handleDropDownHover(e, index)}\n onClick={(e) => handleDropDownClick(e, option)}\n >\n {props.getIcon && <div className=\"medplum-autocomplete-icon\">{props.getIcon(option)}</div>}\n <div className=\"medplum-autocomplete-label\">\n {props.getDisplay(option)}\n {props.getHelpText && <div className=\"medplum-autocomplete-help-text\">{props.getHelpText(option)}</div>}\n </div>\n </div>\n ))}\n {props.onCreateNew && (\n <div className=\"medplum-autocomplete-row\" onClick={props.onCreateNew}>\n <div className=\"medplum-autocomplete-label\">Create new...</div>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ import { Slot } from '@medplum/fhirtypes';
3
3
  import './CalendarInput.css';
4
4
  export interface CalendarInputProps {
5
5
  slots: Slot[];
6
+ onChangeMonth: (date: Date) => void;
6
7
  onClick: (date: Date) => void;
7
8
  }
8
9
  /**
@@ -11,12 +11,14 @@ function getMonthString(date) {
11
11
  return date.toLocaleString('default', { month: 'long' }) + ' ' + date.getFullYear();
12
12
  }
13
13
  function CalendarInput(props) {
14
+ const { onChangeMonth, onClick } = props;
14
15
  const [month, setMonth] = useState(getStartMonth);
15
16
  function moveMonth(delta) {
16
17
  setMonth((currMonth) => {
17
- const prevMonth = new Date(currMonth.getTime());
18
- prevMonth.setMonth(currMonth.getMonth() + delta);
19
- return prevMonth;
18
+ const newMonth = new Date(currMonth.getTime());
19
+ newMonth.setMonth(currMonth.getMonth() + delta);
20
+ onChangeMonth(newMonth);
21
+ return newMonth;
20
22
  });
21
23
  }
22
24
  const grid = useMemo(() => buildGrid(month, props.slots), [month, props.slots]);
@@ -36,7 +38,7 @@ function CalendarInput(props) {
36
38
  React.createElement("th", null, "THU"),
37
39
  React.createElement("th", null, "FRI"),
38
40
  React.createElement("th", null, "SAT"))),
39
- React.createElement("tbody", null, grid.map((week, weekIndex) => (React.createElement("tr", { key: 'week-' + weekIndex }, week.map((day, dayIndex) => (React.createElement("td", { key: 'day-' + dayIndex }, day && (React.createElement("button", { disabled: !day.available, onClick: () => props.onClick(day.date) }, day.date.getDate()))))))))))));
41
+ React.createElement("tbody", null, grid.map((week, weekIndex) => (React.createElement("tr", { key: 'week-' + weekIndex }, week.map((day, dayIndex) => (React.createElement("td", { key: 'day-' + dayIndex }, day && (React.createElement("button", { disabled: !day.available, onClick: () => onClick(day.date) }, day.date.getDate()))))))))))));
40
42
  }
41
43
  function getStartMonth() {
42
44
  const result = new Date();
@@ -55,7 +57,6 @@ function buildGrid(startDate, slots) {
55
57
  while (d.getMonth() === startDate.getMonth()) {
56
58
  row.push({
57
59
  date: new Date(d.getTime()),
58
- // available: isAvailable(d),
59
60
  available: isDayAvailable(d, slots),
60
61
  });
61
62
  if (d.getDay() === 6) {
@@ -1 +1 @@
1
- {"version":3,"file":"CalendarInput.js","sources":["../../src/CalendarInput.tsx"],"sourcesContent":["import React, { useMemo, useState } from 'react';\nimport { Button } from './Button';\nimport { InputRow } from './InputRow';\nimport { Slot } from '@medplum/fhirtypes';\nimport './CalendarInput.css';\n\nexport interface CalendarInputProps {\n slots: Slot[];\n onClick: (date: Date) => void;\n}\n\n/**\n * Returns a month display string (e.g. \"January 2020\").\n * @param date Any date within the month.\n * @returns The month display string (e.g. \"January 2020\")\n */\nexport function getMonthString(date: Date): string {\n return date.toLocaleString('default', { month: 'long' }) + ' ' + date.getFullYear();\n}\n\ninterface CalendarCell {\n date: Date;\n available: boolean;\n}\n\ntype OptionalCalendarCell = CalendarCell | undefined;\n\nexport function CalendarInput(props: CalendarInputProps): JSX.Element {\n const [month, setMonth] = useState<Date>(getStartMonth);\n\n function moveMonth(delta: number): void {\n setMonth((currMonth) => {\n const prevMonth = new Date(currMonth.getTime());\n prevMonth.setMonth(currMonth.getMonth() + delta);\n return prevMonth;\n });\n }\n\n const grid = useMemo(() => buildGrid(month, props.slots), [month, props.slots]);\n\n return (\n <div>\n <InputRow>\n <p style={{ flex: 1 }}>{getMonthString(month)}</p>\n <p>\n <Button label=\"Previous month\" onClick={() => moveMonth(-1)}>\n &lt;\n </Button>\n <Button label=\"Next month\" onClick={() => moveMonth(1)}>\n &gt;\n </Button>\n </p>\n </InputRow>\n <table className=\"medplum-calendar-table\">\n <thead>\n <tr>\n <th>SUN</th>\n <th>MON</th>\n <th>TUE</th>\n <th>WED</th>\n <th>THU</th>\n <th>FRI</th>\n <th>SAT</th>\n </tr>\n </thead>\n <tbody>\n {grid.map((week, weekIndex) => (\n <tr key={'week-' + weekIndex}>\n {week.map((day, dayIndex) => (\n <td key={'day-' + dayIndex}>\n {day && (\n <button disabled={!day.available} onClick={() => props.onClick(day.date)}>\n {day.date.getDate()}\n </button>\n )}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n\nexport function getStartMonth(): Date {\n const result = new Date();\n result.setDate(1);\n result.setHours(0, 0, 0, 0);\n return result;\n}\n\nfunction buildGrid(startDate: Date, slots: Slot[]): OptionalCalendarCell[][] {\n const d = new Date(startDate.getFullYear(), startDate.getMonth());\n const grid: OptionalCalendarCell[][] = [];\n let row: OptionalCalendarCell[] = [];\n\n // Fill leading empty days\n for (let i = 0; i < d.getDay(); i++) {\n row.push(undefined);\n }\n\n while (d.getMonth() === startDate.getMonth()) {\n row.push({\n date: new Date(d.getTime()),\n // available: isAvailable(d),\n available: isDayAvailable(d, slots),\n });\n\n if (d.getDay() === 6) {\n grid.push(row);\n row = [];\n }\n\n d.setDate(d.getDate() + 1);\n }\n\n // Fill trailing empty days\n if (d.getDay() !== 0) {\n for (let i = d.getDay(); i < 7; i++) {\n row.push(undefined);\n }\n grid.push(row);\n }\n\n return grid;\n}\n\n/**\n * Returns true if the given date is available for booking.\n * @param day The day to check.\n * @param slots The list of available slots.\n * @returns True if there are any available slots for the day.\n */\nfunction isDayAvailable(day: Date, slots: Slot[]): boolean {\n // Note that slot start and end time may or may not be in UTC.\n for (const slot of slots) {\n const slotStart = new Date(slot.start as string);\n if (\n slotStart.getFullYear() === day.getFullYear() &&\n slotStart.getMonth() === day.getMonth() &&\n slotStart.getDate() === day.getDate()\n ) {\n return true;\n }\n }\n\n return false;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CalendarInput.js","sources":["../../src/CalendarInput.tsx"],"sourcesContent":["import { Slot } from '@medplum/fhirtypes';\nimport React, { useMemo, useState } from 'react';\nimport { Button } from './Button';\nimport { InputRow } from './InputRow';\nimport './CalendarInput.css';\n\nexport interface CalendarInputProps {\n slots: Slot[];\n onChangeMonth: (date: Date) => void;\n onClick: (date: Date) => void;\n}\n\n/**\n * Returns a month display string (e.g. \"January 2020\").\n * @param date Any date within the month.\n * @returns The month display string (e.g. \"January 2020\")\n */\nexport function getMonthString(date: Date): string {\n return date.toLocaleString('default', { month: 'long' }) + ' ' + date.getFullYear();\n}\n\ninterface CalendarCell {\n date: Date;\n available: boolean;\n}\n\ntype OptionalCalendarCell = CalendarCell | undefined;\n\nexport function CalendarInput(props: CalendarInputProps): JSX.Element {\n const { onChangeMonth, onClick } = props;\n const [month, setMonth] = useState<Date>(getStartMonth);\n\n function moveMonth(delta: number): void {\n setMonth((currMonth) => {\n const newMonth = new Date(currMonth.getTime());\n newMonth.setMonth(currMonth.getMonth() + delta);\n onChangeMonth(newMonth);\n return newMonth;\n });\n }\n\n const grid = useMemo(() => buildGrid(month, props.slots), [month, props.slots]);\n\n return (\n <div>\n <InputRow>\n <p style={{ flex: 1 }}>{getMonthString(month)}</p>\n <p>\n <Button label=\"Previous month\" onClick={() => moveMonth(-1)}>\n &lt;\n </Button>\n <Button label=\"Next month\" onClick={() => moveMonth(1)}>\n &gt;\n </Button>\n </p>\n </InputRow>\n <table className=\"medplum-calendar-table\">\n <thead>\n <tr>\n <th>SUN</th>\n <th>MON</th>\n <th>TUE</th>\n <th>WED</th>\n <th>THU</th>\n <th>FRI</th>\n <th>SAT</th>\n </tr>\n </thead>\n <tbody>\n {grid.map((week, weekIndex) => (\n <tr key={'week-' + weekIndex}>\n {week.map((day, dayIndex) => (\n <td key={'day-' + dayIndex}>\n {day && (\n <button disabled={!day.available} onClick={() => onClick(day.date)}>\n {day.date.getDate()}\n </button>\n )}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n\nexport function getStartMonth(): Date {\n const result = new Date();\n result.setDate(1);\n result.setHours(0, 0, 0, 0);\n return result;\n}\n\nfunction buildGrid(startDate: Date, slots: Slot[]): OptionalCalendarCell[][] {\n const d = new Date(startDate.getFullYear(), startDate.getMonth());\n const grid: OptionalCalendarCell[][] = [];\n let row: OptionalCalendarCell[] = [];\n\n // Fill leading empty days\n for (let i = 0; i < d.getDay(); i++) {\n row.push(undefined);\n }\n\n while (d.getMonth() === startDate.getMonth()) {\n row.push({\n date: new Date(d.getTime()),\n available: isDayAvailable(d, slots),\n });\n\n if (d.getDay() === 6) {\n grid.push(row);\n row = [];\n }\n\n d.setDate(d.getDate() + 1);\n }\n\n // Fill trailing empty days\n if (d.getDay() !== 0) {\n for (let i = d.getDay(); i < 7; i++) {\n row.push(undefined);\n }\n grid.push(row);\n }\n\n return grid;\n}\n\n/**\n * Returns true if the given date is available for booking.\n * @param day The day to check.\n * @param slots The list of available slots.\n * @returns True if there are any available slots for the day.\n */\nfunction isDayAvailable(day: Date, slots: Slot[]): boolean {\n // Note that slot start and end time may or may not be in UTC.\n for (const slot of slots) {\n const slotStart = new Date(slot.start as string);\n if (\n slotStart.getFullYear() === day.getFullYear() &&\n slotStart.getMonth() === day.getMonth() &&\n slotStart.getDate() === day.getDate()\n ) {\n return true;\n }\n }\n\n return false;\n}\n"],"names":[],"mappings":"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"}
@@ -17,7 +17,7 @@ function CodeInput(props) {
17
17
  contains.forEach((e) => (cachedDisplayValues[e.code] = e.display));
18
18
  return contains.map((e) => e.code);
19
19
  });
20
- }, buildUnstructured: (str) => str, getId: (item) => item, getDisplay: (item) => React.createElement(React.Fragment, null, cachedDisplayValues[item] || item), name: props.name, defaultValue: defaultValue, onChange: (values) => {
20
+ }, buildUnstructured: (str) => str, getId: (item) => item, getDisplay: (item) => React.createElement(React.Fragment, null, cachedDisplayValues[item] || item), name: props.name, defaultValue: defaultValue, loadOnFocus: true, onChange: (values) => {
21
21
  if (props.onChange) {
22
22
  props.onChange(values[0]);
23
23
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CodeInput.js","sources":["../../src/CodeInput.tsx"],"sourcesContent":["import { ElementDefinition, ValueSet, ValueSetExpansion, ValueSetExpansionContains } from '@medplum/fhirtypes';\nimport React from 'react';\nimport { Autocomplete } from './Autocomplete';\nimport { useMedplum } from './MedplumProvider';\n\nexport interface CodeInputProps {\n property: ElementDefinition;\n name: string;\n defaultValue?: string;\n onChange?: (value: string) => void;\n}\n\nconst cachedDisplayValues: Record<string, string> = {};\n\nexport function CodeInput(props: CodeInputProps): JSX.Element {\n const medplum = useMedplum();\n\n let defaultValue = undefined;\n if (props.defaultValue) {\n defaultValue = [props.defaultValue];\n }\n\n return (\n <Autocomplete\n loadOptions={(input: string): Promise<string[]> => {\n const system = props.property.binding?.valueSet as string;\n return medplum.searchValueSet(system, input).then((valueSet: ValueSet) => {\n const contains = (valueSet.expansion as ValueSetExpansion).contains as ValueSetExpansionContains[];\n contains.forEach((e) => (cachedDisplayValues[e.code as string] = e.display as string));\n return contains.map((e) => e.code as string);\n });\n }}\n buildUnstructured={(str: string) => str}\n getId={(item: string) => item}\n getDisplay={(item: string) => <>{cachedDisplayValues[item] || item}</>}\n name={props.name}\n defaultValue={defaultValue}\n onChange={(values: string[]) => {\n if (props.onChange) {\n props.onChange(values[0]);\n }\n }}\n />\n );\n}\n"],"names":[],"mappings":";;;;AAYA,MAAM,mBAAmB,GAA2B,EAAE,CAAC;AAEjD,SAAU,SAAS,CAAC,KAAqB,EAAA;AAC7C,IAAA,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAE7B,IAAI,YAAY,GAAG,SAAS,CAAC;IAC7B,IAAI,KAAK,CAAC,YAAY,EAAE;AACtB,QAAA,YAAY,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;AACrC,KAAA;IAED,QACE,oBAAC,YAAY,EAAA,EACX,WAAW,EAAE,CAAC,KAAa,KAAuB;;YAChD,MAAM,MAAM,GAAG,CAAA,EAAA,GAAA,KAAK,CAAC,QAAQ,CAAC,OAAO,MAAE,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,QAAkB,CAAC;AAC1D,YAAA,OAAO,OAAO,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,QAAkB,KAAI;AACvE,gBAAA,MAAM,QAAQ,GAAI,QAAQ,CAAC,SAA+B,CAAC,QAAuC,CAAC;gBACnG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,mBAAmB,CAAC,CAAC,CAAC,IAAc,CAAC,GAAG,CAAC,CAAC,OAAiB,CAAC,CAAC,CAAC;AACvF,gBAAA,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAc,CAAC,CAAC;AAC/C,aAAC,CAAC,CAAC;SACJ,EACD,iBAAiB,EAAE,CAAC,GAAW,KAAK,GAAG,EACvC,KAAK,EAAE,CAAC,IAAY,KAAK,IAAI,EAC7B,UAAU,EAAE,CAAC,IAAY,KAAK,KAAG,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,EAAA,mBAAmB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAI,EACtE,IAAI,EAAE,KAAK,CAAC,IAAI,EAChB,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,CAAC,MAAgB,KAAI;YAC7B,IAAI,KAAK,CAAC,QAAQ,EAAE;gBAClB,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3B,aAAA;SACF,EAAA,CACD,EACF;AACJ;;;;"}
1
+ {"version":3,"file":"CodeInput.js","sources":["../../src/CodeInput.tsx"],"sourcesContent":["import { ElementDefinition, ValueSet, ValueSetExpansion, ValueSetExpansionContains } from '@medplum/fhirtypes';\nimport React from 'react';\nimport { Autocomplete } from './Autocomplete';\nimport { useMedplum } from './MedplumProvider';\n\nexport interface CodeInputProps {\n property: ElementDefinition;\n name: string;\n defaultValue?: string;\n onChange?: (value: string) => void;\n}\n\nconst cachedDisplayValues: Record<string, string> = {};\n\nexport function CodeInput(props: CodeInputProps): JSX.Element {\n const medplum = useMedplum();\n\n let defaultValue = undefined;\n if (props.defaultValue) {\n defaultValue = [props.defaultValue];\n }\n\n return (\n <Autocomplete\n loadOptions={(input: string): Promise<string[]> => {\n const system = props.property.binding?.valueSet as string;\n return medplum.searchValueSet(system, input).then((valueSet: ValueSet) => {\n const contains = (valueSet.expansion as ValueSetExpansion).contains as ValueSetExpansionContains[];\n contains.forEach((e) => (cachedDisplayValues[e.code as string] = e.display as string));\n return contains.map((e) => e.code as string);\n });\n }}\n buildUnstructured={(str: string) => str}\n getId={(item: string) => item}\n getDisplay={(item: string) => <>{cachedDisplayValues[item] || item}</>}\n name={props.name}\n defaultValue={defaultValue}\n loadOnFocus={true}\n onChange={(values: string[]) => {\n if (props.onChange) {\n props.onChange(values[0]);\n }\n }}\n />\n );\n}\n"],"names":[],"mappings":";;;;AAYA,MAAM,mBAAmB,GAA2B,EAAE,CAAC;AAEjD,SAAU,SAAS,CAAC,KAAqB,EAAA;AAC7C,IAAA,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAE7B,IAAI,YAAY,GAAG,SAAS,CAAC;IAC7B,IAAI,KAAK,CAAC,YAAY,EAAE;AACtB,QAAA,YAAY,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;AACrC,KAAA;IAED,QACE,oBAAC,YAAY,EAAA,EACX,WAAW,EAAE,CAAC,KAAa,KAAuB;;YAChD,MAAM,MAAM,GAAG,CAAA,EAAA,GAAA,KAAK,CAAC,QAAQ,CAAC,OAAO,MAAE,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,QAAkB,CAAC;AAC1D,YAAA,OAAO,OAAO,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,QAAkB,KAAI;AACvE,gBAAA,MAAM,QAAQ,GAAI,QAAQ,CAAC,SAA+B,CAAC,QAAuC,CAAC;gBACnG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,mBAAmB,CAAC,CAAC,CAAC,IAAc,CAAC,GAAG,CAAC,CAAC,OAAiB,CAAC,CAAC,CAAC;AACvF,gBAAA,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAc,CAAC,CAAC;AAC/C,aAAC,CAAC,CAAC;SACJ,EACD,iBAAiB,EAAE,CAAC,GAAW,KAAK,GAAG,EACvC,KAAK,EAAE,CAAC,IAAY,KAAK,IAAI,EAC7B,UAAU,EAAE,CAAC,IAAY,KAAK,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,EAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAI,EACtE,IAAI,EAAE,KAAK,CAAC,IAAI,EAChB,YAAY,EAAE,YAAY,EAC1B,WAAW,EAAE,IAAI,EACjB,QAAQ,EAAE,CAAC,MAAgB,KAAI;YAC7B,IAAI,KAAK,CAAC,QAAQ,EAAE;gBAClB,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3B,aAAA;SACF,EAAA,CACD,EACF;AACJ;;;;"}
@@ -15,7 +15,7 @@ function CodeableConceptInput(props) {
15
15
  return medplum.searchValueSet(system, input).then((valueSet) => {
16
16
  return valueSet.expansion.contains.map(valueSetElementToCodeableConcept);
17
17
  });
18
- }, buildUnstructured: buildUnstructured, getId: getId, getDisplay: getDisplay, name: props.name, defaultValue: defaultValue, onChange: (values) => {
18
+ }, buildUnstructured: buildUnstructured, getId: getId, getDisplay: getDisplay, name: props.name, defaultValue: defaultValue, loadOnFocus: true, onChange: (values) => {
19
19
  if (props.onChange) {
20
20
  props.onChange(values[0]);
21
21
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CodeableConceptInput.js","sources":["../../src/CodeableConceptInput.tsx"],"sourcesContent":["import { stringify } from '@medplum/core';\nimport {\n CodeableConcept,\n ElementDefinition,\n ValueSet,\n ValueSetExpansion,\n ValueSetExpansionContains,\n} from '@medplum/fhirtypes';\nimport React from 'react';\nimport { Autocomplete } from './Autocomplete';\nimport { useMedplum } from './MedplumProvider';\n\nexport interface CodeableConceptInputProps {\n property: ElementDefinition;\n name: string;\n defaultValue?: CodeableConcept;\n onChange?: (value: CodeableConcept) => void;\n}\n\nexport function CodeableConceptInput(props: CodeableConceptInputProps): JSX.Element {\n const medplum = useMedplum();\n\n let defaultValue = undefined;\n if (props.defaultValue) {\n defaultValue = [props.defaultValue];\n }\n\n return (\n <Autocomplete\n loadOptions={(input: string): Promise<CodeableConcept[]> => {\n const system = props.property.binding?.valueSet as string;\n return medplum.searchValueSet(system, input).then((valueSet: ValueSet) => {\n return ((valueSet.expansion as ValueSetExpansion).contains as ValueSetExpansionContains[]).map(\n valueSetElementToCodeableConcept\n );\n });\n }}\n buildUnstructured={buildUnstructured}\n getId={getId}\n getDisplay={getDisplay}\n name={props.name}\n defaultValue={defaultValue}\n onChange={(values: CodeableConcept[]) => {\n if (props.onChange) {\n props.onChange(values[0]);\n }\n }}\n />\n );\n}\n\nfunction valueSetElementToCodeableConcept(element: ValueSetExpansionContains): CodeableConcept {\n return {\n text: element.display,\n coding: [\n {\n system: element.system,\n code: element.code,\n display: element.display,\n },\n ],\n };\n}\n\nfunction buildUnstructured(str: string): CodeableConcept {\n return { text: str };\n}\n\nfunction getId(concept: CodeableConcept): string {\n if (concept.coding && concept.coding.length > 0) {\n return concept.coding[0].code as string;\n }\n return stringify(concept);\n}\n\nfunction getDisplay(concept: CodeableConcept): JSX.Element {\n const text = concept.coding?.[0]?.display ?? concept.coding?.[0]?.code ?? concept.text;\n return <>{text}</>;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CodeableConceptInput.js","sources":["../../src/CodeableConceptInput.tsx"],"sourcesContent":["import { stringify } from '@medplum/core';\nimport {\n CodeableConcept,\n ElementDefinition,\n ValueSet,\n ValueSetExpansion,\n ValueSetExpansionContains,\n} from '@medplum/fhirtypes';\nimport React from 'react';\nimport { Autocomplete } from './Autocomplete';\nimport { useMedplum } from './MedplumProvider';\n\nexport interface CodeableConceptInputProps {\n property: ElementDefinition;\n name: string;\n defaultValue?: CodeableConcept;\n onChange?: (value: CodeableConcept) => void;\n}\n\nexport function CodeableConceptInput(props: CodeableConceptInputProps): JSX.Element {\n const medplum = useMedplum();\n\n let defaultValue = undefined;\n if (props.defaultValue) {\n defaultValue = [props.defaultValue];\n }\n\n return (\n <Autocomplete\n loadOptions={(input: string): Promise<CodeableConcept[]> => {\n const system = props.property.binding?.valueSet as string;\n return medplum.searchValueSet(system, input).then((valueSet: ValueSet) => {\n return ((valueSet.expansion as ValueSetExpansion).contains as ValueSetExpansionContains[]).map(\n valueSetElementToCodeableConcept\n );\n });\n }}\n buildUnstructured={buildUnstructured}\n getId={getId}\n getDisplay={getDisplay}\n name={props.name}\n defaultValue={defaultValue}\n loadOnFocus={true}\n onChange={(values: CodeableConcept[]) => {\n if (props.onChange) {\n props.onChange(values[0]);\n }\n }}\n />\n );\n}\n\nfunction valueSetElementToCodeableConcept(element: ValueSetExpansionContains): CodeableConcept {\n return {\n text: element.display,\n coding: [\n {\n system: element.system,\n code: element.code,\n display: element.display,\n },\n ],\n };\n}\n\nfunction buildUnstructured(str: string): CodeableConcept {\n return { text: str };\n}\n\nfunction getId(concept: CodeableConcept): string {\n if (concept.coding && concept.coding.length > 0) {\n return concept.coding[0].code as string;\n }\n return stringify(concept);\n}\n\nfunction getDisplay(concept: CodeableConcept): JSX.Element {\n const text = concept.coding?.[0]?.display ?? concept.coding?.[0]?.code ?? concept.text;\n return <>{text}</>;\n}\n"],"names":[],"mappings":"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"}
@@ -19,7 +19,7 @@ function CodingInput(props) {
19
19
  display: e.display,
20
20
  }));
21
21
  });
22
- }, buildUnstructured: (str) => ({ code: str }), getId: (item) => item.code, getDisplay: (item) => React.createElement(CodingDisplay, { value: item }), name: props.name, defaultValue: defaultValue, onChange: (values) => {
22
+ }, buildUnstructured: (str) => ({ code: str }), getId: (item) => item.code, getDisplay: (item) => React.createElement(CodingDisplay, { value: item }), name: props.name, defaultValue: defaultValue, loadOnFocus: true, onChange: (values) => {
23
23
  if (props.onChange) {
24
24
  props.onChange(values[0]);
25
25
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CodingInput.js","sources":["../../src/CodingInput.tsx"],"sourcesContent":["import { Coding, ElementDefinition, ValueSet, ValueSetExpansion, ValueSetExpansionContains } from '@medplum/fhirtypes';\nimport React from 'react';\nimport { Autocomplete } from './Autocomplete';\nimport { CodingDisplay } from './CodingDisplay';\nimport { useMedplum } from './MedplumProvider';\n\nexport interface CodingInputProps {\n property: ElementDefinition;\n name: string;\n defaultValue?: Coding;\n onChange?: (value: Coding) => void;\n}\n\nexport function CodingInput(props: CodingInputProps): JSX.Element {\n const medplum = useMedplum();\n\n let defaultValue = undefined;\n if (props.defaultValue) {\n defaultValue = [props.defaultValue];\n }\n\n return (\n <Autocomplete\n loadOptions={(input: string): Promise<Coding[]> => {\n const system = props.property.binding?.valueSet as string;\n return medplum.searchValueSet(system, input).then((valueSet: ValueSet) => {\n return ((valueSet.expansion as ValueSetExpansion).contains as ValueSetExpansionContains[]).map(\n (e) =>\n ({\n system: e.system,\n code: e.code,\n display: e.display,\n } as Coding)\n );\n });\n }}\n buildUnstructured={(str: string) => ({ code: str })}\n getId={(item: Coding) => item.code as string}\n getDisplay={(item: Coding) => <CodingDisplay value={item} />}\n name={props.name}\n defaultValue={defaultValue}\n onChange={(values: Coding[]) => {\n if (props.onChange) {\n props.onChange(values[0]);\n }\n }}\n />\n );\n}\n"],"names":[],"mappings":";;;;;AAaM,SAAU,WAAW,CAAC,KAAuB,EAAA;AACjD,IAAA,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAE7B,IAAI,YAAY,GAAG,SAAS,CAAC;IAC7B,IAAI,KAAK,CAAC,YAAY,EAAE;AACtB,QAAA,YAAY,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;AACrC,KAAA;IAED,QACE,oBAAC,YAAY,EAAA,EACX,WAAW,EAAE,CAAC,KAAa,KAAuB;;YAChD,MAAM,MAAM,GAAG,CAAA,EAAA,GAAA,KAAK,CAAC,QAAQ,CAAC,OAAO,MAAE,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,QAAkB,CAAC;AAC1D,YAAA,OAAO,OAAO,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,QAAkB,KAAI;AACvE,gBAAA,OAAS,QAAQ,CAAC,SAA+B,CAAC,QAAwC,CAAC,GAAG,CAC5F,CAAC,CAAC,MACC;oBACC,MAAM,EAAE,CAAC,CAAC,MAAM;oBAChB,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,OAAO,EAAE,CAAC,CAAC,OAAO;AACR,iBAAA,CAAA,CACf,CAAC;AACJ,aAAC,CAAC,CAAC;SACJ,EACD,iBAAiB,EAAE,CAAC,GAAW,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EACnD,KAAK,EAAE,CAAC,IAAY,KAAK,IAAI,CAAC,IAAc,EAC5C,UAAU,EAAE,CAAC,IAAY,KAAK,KAAA,CAAA,aAAA,CAAC,aAAa,EAAA,EAAC,KAAK,EAAE,IAAI,EAAA,CAAI,EAC5D,IAAI,EAAE,KAAK,CAAC,IAAI,EAChB,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,CAAC,MAAgB,KAAI;YAC7B,IAAI,KAAK,CAAC,QAAQ,EAAE;gBAClB,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3B,aAAA;SACF,EAAA,CACD,EACF;AACJ;;;;"}
1
+ {"version":3,"file":"CodingInput.js","sources":["../../src/CodingInput.tsx"],"sourcesContent":["import { Coding, ElementDefinition, ValueSet, ValueSetExpansion, ValueSetExpansionContains } from '@medplum/fhirtypes';\nimport React from 'react';\nimport { Autocomplete } from './Autocomplete';\nimport { CodingDisplay } from './CodingDisplay';\nimport { useMedplum } from './MedplumProvider';\n\nexport interface CodingInputProps {\n property: ElementDefinition;\n name: string;\n defaultValue?: Coding;\n onChange?: (value: Coding) => void;\n}\n\nexport function CodingInput(props: CodingInputProps): JSX.Element {\n const medplum = useMedplum();\n\n let defaultValue = undefined;\n if (props.defaultValue) {\n defaultValue = [props.defaultValue];\n }\n\n return (\n <Autocomplete\n loadOptions={(input: string): Promise<Coding[]> => {\n const system = props.property.binding?.valueSet as string;\n return medplum.searchValueSet(system, input).then((valueSet: ValueSet) => {\n return ((valueSet.expansion as ValueSetExpansion).contains as ValueSetExpansionContains[]).map(\n (e) =>\n ({\n system: e.system,\n code: e.code,\n display: e.display,\n } as Coding)\n );\n });\n }}\n buildUnstructured={(str: string) => ({ code: str })}\n getId={(item: Coding) => item.code as string}\n getDisplay={(item: Coding) => <CodingDisplay value={item} />}\n name={props.name}\n defaultValue={defaultValue}\n loadOnFocus={true}\n onChange={(values: Coding[]) => {\n if (props.onChange) {\n props.onChange(values[0]);\n }\n }}\n />\n );\n}\n"],"names":[],"mappings":";;;;;AAaM,SAAU,WAAW,CAAC,KAAuB,EAAA;AACjD,IAAA,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAE7B,IAAI,YAAY,GAAG,SAAS,CAAC;IAC7B,IAAI,KAAK,CAAC,YAAY,EAAE;AACtB,QAAA,YAAY,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;AACrC,KAAA;IAED,QACE,oBAAC,YAAY,EAAA,EACX,WAAW,EAAE,CAAC,KAAa,KAAuB;;YAChD,MAAM,MAAM,GAAG,CAAA,EAAA,GAAA,KAAK,CAAC,QAAQ,CAAC,OAAO,MAAE,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,QAAkB,CAAC;AAC1D,YAAA,OAAO,OAAO,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,QAAkB,KAAI;AACvE,gBAAA,OAAS,QAAQ,CAAC,SAA+B,CAAC,QAAwC,CAAC,GAAG,CAC5F,CAAC,CAAC,MACC;oBACC,MAAM,EAAE,CAAC,CAAC,MAAM;oBAChB,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,OAAO,EAAE,CAAC,CAAC,OAAO;AACR,iBAAA,CAAA,CACf,CAAC;AACJ,aAAC,CAAC,CAAC;AACL,SAAC,EACD,iBAAiB,EAAE,CAAC,GAAW,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EACnD,KAAK,EAAE,CAAC,IAAY,KAAK,IAAI,CAAC,IAAc,EAC5C,UAAU,EAAE,CAAC,IAAY,KAAK,KAAC,CAAA,aAAA,CAAA,aAAa,EAAC,EAAA,KAAK,EAAE,IAAI,EAAI,CAAA,EAC5D,IAAI,EAAE,KAAK,CAAC,IAAI,EAChB,YAAY,EAAE,YAAY,EAC1B,WAAW,EAAE,IAAI,EACjB,QAAQ,EAAE,CAAC,MAAgB,KAAI;YAC7B,IAAI,KAAK,CAAC,QAAQ,EAAE;gBAClB,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3B,aAAA;SACF,EAAA,CACD,EACF;AACJ;;;;"}
@@ -81,11 +81,14 @@ function FhirPathTable(props) {
81
81
  }
82
82
  }
83
83
  useEffect(() => {
84
- medplum.requestSchema(props.resourceType).then((newSchema) => {
84
+ medplum
85
+ .requestSchema(props.resourceType)
86
+ .then((newSchema) => {
85
87
  // The schema could have the same object identity,
86
88
  // so need to use the spread operator to kick React re-render.
87
89
  setSchema(Object.assign({}, newSchema));
88
- });
90
+ })
91
+ .catch(console.log);
89
92
  }, [medplum, props.resourceType]);
90
93
  const typeSchema = (_a = schema === null || schema === void 0 ? void 0 : schema.types) === null || _a === void 0 ? void 0 : _a[props.resourceType];
91
94
  if (!typeSchema) {
@@ -1 +1 @@
1
- {"version":3,"file":"FhirPathTable.js","sources":["../../src/FhirPathTable.tsx"],"sourcesContent":["import { IndexedStructureDefinition, PropertyType } from '@medplum/core';\nimport { OperationOutcome, Resource } from '@medplum/fhirtypes';\nimport React, { useEffect, useRef, useState } from 'react';\nimport { Button } from './Button';\nimport { FhirPathDisplay } from './FhirPathDisplay';\nimport { Loading } from './Loading';\nimport { useMedplum } from './MedplumProvider';\nimport { SearchClickEvent } from './SearchControl';\nimport { isCheckboxCell, killEvent } from './utils/dom';\nimport './SearchControl.css';\n\nexport interface SmartSearchField {\n readonly propertyType: PropertyType;\n readonly name: string;\n readonly fhirPath: string;\n}\n\nexport interface FhirPathTableProps {\n resourceType: string;\n query: string;\n fields: SmartSearchField[];\n checkboxesEnabled?: boolean;\n onClick?: (e: SearchClickEvent) => void;\n onAuxClick?: (e: SearchClickEvent) => void;\n onBulk?: (ids: string[]) => void;\n}\n\nexport interface SmartSearchResponse {\n data: {\n ResourceList: Resource[];\n };\n}\n\n/**\n * The FhirPathTable component represents the embeddable search table control.\n */\nexport function FhirPathTable(props: FhirPathTableProps): JSX.Element {\n const medplum = useMedplum();\n const [schema, setSchema] = useState<IndexedStructureDefinition | undefined>();\n const [outcome, setOutcome] = useState<OperationOutcome | undefined>();\n const { query, fields } = props;\n const [response, setResponse] = useState<SmartSearchResponse | undefined>();\n const [selected, setSelected] = useState<{ [id: string]: boolean }>({});\n\n const responseRef = useRef<SmartSearchResponse>();\n responseRef.current = response;\n\n const selectedRef = useRef<{ [id: string]: boolean }>({});\n selectedRef.current = selected;\n\n useEffect(() => {\n setOutcome(undefined);\n medplum.graphql(query).then(setResponse).catch(setOutcome);\n }, [medplum, query]);\n\n function handleSingleCheckboxClick(e: React.ChangeEvent, id: string): void {\n e.stopPropagation();\n\n const el = e.target as HTMLInputElement;\n const checked = el.checked;\n const newSelected = { ...selectedRef.current };\n if (checked) {\n newSelected[id] = true;\n } else {\n delete newSelected[id];\n }\n setSelected(newSelected);\n }\n\n function handleAllCheckboxClick(e: React.ChangeEvent): void {\n e.stopPropagation();\n\n const el = e.target as HTMLInputElement;\n const checked = el.checked;\n const newSelected = {} as { [id: string]: boolean };\n const resources = responseRef.current?.data?.ResourceList;\n if (checked && resources) {\n resources.forEach((resource) => {\n if (resource?.id) {\n newSelected[resource.id] = true;\n }\n });\n }\n setSelected(newSelected);\n }\n\n function isAllSelected(): boolean {\n const resources = responseRef.current?.data?.ResourceList;\n if (!resources || resources.length === 0) {\n return false;\n }\n for (const resource of resources) {\n if (resource?.id && !selectedRef.current[resource.id]) {\n return false;\n }\n }\n return true;\n }\n\n function handleRowClick(e: React.MouseEvent, resource: Resource): void {\n if (isCheckboxCell(e.target as Element)) {\n // Ignore clicks on checkboxes\n return;\n }\n\n killEvent(e);\n\n if (e.button !== 1 && props.onClick) {\n props.onClick(new SearchClickEvent(resource, e));\n }\n\n if (e.button === 1 && props.onAuxClick) {\n props.onAuxClick(new SearchClickEvent(resource, e));\n }\n }\n\n useEffect(() => {\n medplum.requestSchema(props.resourceType).then((newSchema) => {\n // The schema could have the same object identity,\n // so need to use the spread operator to kick React re-render.\n setSchema({ ...newSchema });\n });\n }, [medplum, props.resourceType]);\n\n const typeSchema = schema?.types?.[props.resourceType];\n if (!typeSchema) {\n return <Loading />;\n }\n\n const checkboxColumn = props.checkboxesEnabled;\n\n return (\n <div className=\"medplum-search-control\" onContextMenu={(e) => killEvent(e)} data-testid=\"search-control\">\n <table>\n <thead>\n <tr>\n {checkboxColumn && (\n <th className=\"medplum-search-icon-cell\">\n <input\n type=\"checkbox\"\n value=\"checked\"\n aria-label=\"all-checkbox\"\n data-testid=\"all-checkbox\"\n checked={isAllSelected()}\n onChange={(e) => handleAllCheckboxClick(e)}\n />\n </th>\n )}\n {fields.map((field) => (\n <th key={field.name}>{field.name}</th>\n ))}\n </tr>\n </thead>\n <tbody>\n {response?.data?.ResourceList?.map(\n (resource) =>\n resource && (\n <tr\n key={resource.id}\n data-testid=\"search-control-row\"\n onClick={(e) => handleRowClick(e, resource)}\n onAuxClick={(e) => handleRowClick(e, resource)}\n >\n {checkboxColumn && (\n <td className=\"medplum-search-icon-cell\">\n <input\n type=\"checkbox\"\n value=\"checked\"\n data-testid=\"row-checkbox\"\n aria-label={`Checkbox for ${resource.id}`}\n checked={!!selected[resource.id as string]}\n onChange={(e) => handleSingleCheckboxClick(e, resource.id as string)}\n />\n </td>\n )}\n {fields.map((field) => {\n return (\n <td key={field.name}>\n <FhirPathDisplay propertyType={field.propertyType} path={field.fhirPath} resource={resource} />\n </td>\n );\n })}\n </tr>\n )\n )}\n </tbody>\n </table>\n {response?.data?.ResourceList?.length === 0 && (\n <div data-testid=\"empty-search\" className=\"medplum-empty-search\">\n No results\n </div>\n )}\n {outcome && (\n <div data-testid=\"search-error\" className=\"medplum-empty-search\">\n <pre style={{ textAlign: 'left' }}>{JSON.stringify(outcome, undefined, 2)}</pre>\n </div>\n )}\n {props.onBulk && (\n <Button size=\"small\" onClick={() => (props.onBulk as (ids: string[]) => any)(Object.keys(selectedRef.current))}>\n Bulk...\n </Button>\n )}\n </div>\n );\n}\n\nexport const MemoizedFhirPathTable = React.memo(FhirPathTable);\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FhirPathTable.js","sources":["../../src/FhirPathTable.tsx"],"sourcesContent":["import { IndexedStructureDefinition, PropertyType } from '@medplum/core';\nimport { OperationOutcome, Resource } from '@medplum/fhirtypes';\nimport React, { useEffect, useRef, useState } from 'react';\nimport { Button } from './Button';\nimport { FhirPathDisplay } from './FhirPathDisplay';\nimport { Loading } from './Loading';\nimport { useMedplum } from './MedplumProvider';\nimport { SearchClickEvent } from './SearchControl';\nimport { isCheckboxCell, killEvent } from './utils/dom';\nimport './SearchControl.css';\n\nexport interface SmartSearchField {\n readonly propertyType: PropertyType;\n readonly name: string;\n readonly fhirPath: string;\n}\n\nexport interface FhirPathTableProps {\n resourceType: string;\n query: string;\n fields: SmartSearchField[];\n checkboxesEnabled?: boolean;\n onClick?: (e: SearchClickEvent) => void;\n onAuxClick?: (e: SearchClickEvent) => void;\n onBulk?: (ids: string[]) => void;\n}\n\nexport interface SmartSearchResponse {\n data: {\n ResourceList: Resource[];\n };\n}\n\n/**\n * The FhirPathTable component represents the embeddable search table control.\n */\nexport function FhirPathTable(props: FhirPathTableProps): JSX.Element {\n const medplum = useMedplum();\n const [schema, setSchema] = useState<IndexedStructureDefinition | undefined>();\n const [outcome, setOutcome] = useState<OperationOutcome | undefined>();\n const { query, fields } = props;\n const [response, setResponse] = useState<SmartSearchResponse | undefined>();\n const [selected, setSelected] = useState<{ [id: string]: boolean }>({});\n\n const responseRef = useRef<SmartSearchResponse>();\n responseRef.current = response;\n\n const selectedRef = useRef<{ [id: string]: boolean }>({});\n selectedRef.current = selected;\n\n useEffect(() => {\n setOutcome(undefined);\n medplum.graphql(query).then(setResponse).catch(setOutcome);\n }, [medplum, query]);\n\n function handleSingleCheckboxClick(e: React.ChangeEvent, id: string): void {\n e.stopPropagation();\n\n const el = e.target as HTMLInputElement;\n const checked = el.checked;\n const newSelected = { ...selectedRef.current };\n if (checked) {\n newSelected[id] = true;\n } else {\n delete newSelected[id];\n }\n setSelected(newSelected);\n }\n\n function handleAllCheckboxClick(e: React.ChangeEvent): void {\n e.stopPropagation();\n\n const el = e.target as HTMLInputElement;\n const checked = el.checked;\n const newSelected = {} as { [id: string]: boolean };\n const resources = responseRef.current?.data?.ResourceList;\n if (checked && resources) {\n resources.forEach((resource) => {\n if (resource?.id) {\n newSelected[resource.id] = true;\n }\n });\n }\n setSelected(newSelected);\n }\n\n function isAllSelected(): boolean {\n const resources = responseRef.current?.data?.ResourceList;\n if (!resources || resources.length === 0) {\n return false;\n }\n for (const resource of resources) {\n if (resource?.id && !selectedRef.current[resource.id]) {\n return false;\n }\n }\n return true;\n }\n\n function handleRowClick(e: React.MouseEvent, resource: Resource): void {\n if (isCheckboxCell(e.target as Element)) {\n // Ignore clicks on checkboxes\n return;\n }\n\n killEvent(e);\n\n if (e.button !== 1 && props.onClick) {\n props.onClick(new SearchClickEvent(resource, e));\n }\n\n if (e.button === 1 && props.onAuxClick) {\n props.onAuxClick(new SearchClickEvent(resource, e));\n }\n }\n\n useEffect(() => {\n medplum\n .requestSchema(props.resourceType)\n .then((newSchema) => {\n // The schema could have the same object identity,\n // so need to use the spread operator to kick React re-render.\n setSchema({ ...newSchema });\n })\n .catch(console.log);\n }, [medplum, props.resourceType]);\n\n const typeSchema = schema?.types?.[props.resourceType];\n if (!typeSchema) {\n return <Loading />;\n }\n\n const checkboxColumn = props.checkboxesEnabled;\n\n return (\n <div className=\"medplum-search-control\" onContextMenu={(e) => killEvent(e)} data-testid=\"search-control\">\n <table>\n <thead>\n <tr>\n {checkboxColumn && (\n <th className=\"medplum-search-icon-cell\">\n <input\n type=\"checkbox\"\n value=\"checked\"\n aria-label=\"all-checkbox\"\n data-testid=\"all-checkbox\"\n checked={isAllSelected()}\n onChange={(e) => handleAllCheckboxClick(e)}\n />\n </th>\n )}\n {fields.map((field) => (\n <th key={field.name}>{field.name}</th>\n ))}\n </tr>\n </thead>\n <tbody>\n {response?.data?.ResourceList?.map(\n (resource) =>\n resource && (\n <tr\n key={resource.id}\n data-testid=\"search-control-row\"\n onClick={(e) => handleRowClick(e, resource)}\n onAuxClick={(e) => handleRowClick(e, resource)}\n >\n {checkboxColumn && (\n <td className=\"medplum-search-icon-cell\">\n <input\n type=\"checkbox\"\n value=\"checked\"\n data-testid=\"row-checkbox\"\n aria-label={`Checkbox for ${resource.id}`}\n checked={!!selected[resource.id as string]}\n onChange={(e) => handleSingleCheckboxClick(e, resource.id as string)}\n />\n </td>\n )}\n {fields.map((field) => {\n return (\n <td key={field.name}>\n <FhirPathDisplay propertyType={field.propertyType} path={field.fhirPath} resource={resource} />\n </td>\n );\n })}\n </tr>\n )\n )}\n </tbody>\n </table>\n {response?.data?.ResourceList?.length === 0 && (\n <div data-testid=\"empty-search\" className=\"medplum-empty-search\">\n No results\n </div>\n )}\n {outcome && (\n <div data-testid=\"search-error\" className=\"medplum-empty-search\">\n <pre style={{ textAlign: 'left' }}>{JSON.stringify(outcome, undefined, 2)}</pre>\n </div>\n )}\n {props.onBulk && (\n <Button size=\"small\" onClick={() => (props.onBulk as (ids: string[]) => any)(Object.keys(selectedRef.current))}>\n Bulk...\n </Button>\n )}\n </div>\n );\n}\n\nexport const MemoizedFhirPathTable = React.memo(FhirPathTable);\n"],"names":[],"mappings":"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"}
@@ -37,7 +37,7 @@ function getGoogleClientId(clientId) {
37
37
  return clientId;
38
38
  }
39
39
  const origin = window.location.protocol + '//' + window.location.host;
40
- const authorizedOrigins = (_b = (_a = "http://localhost:3000,http://localhost:6006,https://app.medplum.com,https://docs.medplum.com") === null || _a === void 0 ? void 0 : _a.split(',')) !== null && _b !== void 0 ? _b : [];
40
+ const authorizedOrigins = (_b = (_a = "http://localhost:3000,http://127.0.0.1:3000,http://localhost:6006,http://127.0.0.1:6006,https://app.medplum.com,https://docs.medplum.com") === null || _a === void 0 ? void 0 : _a.split(',')) !== null && _b !== void 0 ? _b : [];
41
41
  if (authorizedOrigins.includes(origin)) {
42
42
  return "921088377005-3j1sa10vr6hj86jgmdfh2l53v3mp7lfi.apps.googleusercontent.com";
43
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"GoogleButton.js","sources":["../../src/GoogleButton.tsx"],"sourcesContent":["import { GoogleCredentialResponse } from '@medplum/core';\nimport React, { useEffect, useRef, useState } from 'react';\nimport { useMedplum } from './MedplumProvider';\nimport { createScriptTag } from './utils';\n\ninterface GoogleApi {\n accounts: {\n id: {\n initialize: (args: any) => void;\n renderButton: (parent: HTMLElement, args: any) => void;\n };\n };\n}\n\ndeclare const google: GoogleApi;\n\nexport interface GoogleButtonProps {\n readonly googleClientId?: string;\n readonly handleGoogleCredential: (response: GoogleCredentialResponse) => void;\n}\n\nexport function GoogleButton(props: GoogleButtonProps): JSX.Element | null {\n const medplum = useMedplum();\n const { googleClientId, handleGoogleCredential } = props;\n const parentRef = useRef<HTMLDivElement>(null);\n const [scriptLoaded, setScriptLoaded] = useState<boolean>(typeof google !== 'undefined');\n const [initialized, setInitialized] = useState<boolean>(false);\n const [buttonRendered, setButtonRendered] = useState<boolean>(false);\n\n useEffect(() => {\n if (typeof google === 'undefined') {\n createScriptTag('https://accounts.google.com/gsi/client', () => setScriptLoaded(true));\n return;\n }\n\n if (!initialized) {\n google.accounts.id.initialize({\n client_id: googleClientId,\n callback: handleGoogleCredential,\n });\n setInitialized(true);\n }\n\n if (parentRef.current && !buttonRendered) {\n google.accounts.id.renderButton(parentRef.current, {});\n setButtonRendered(true);\n }\n }, [medplum, googleClientId, initialized, scriptLoaded, parentRef, buttonRendered, handleGoogleCredential]);\n\n if (!googleClientId) {\n return null;\n }\n\n return <div ref={parentRef} />;\n}\n\nexport function getGoogleClientId(clientId: string | undefined): string | undefined {\n if (clientId) {\n return clientId;\n }\n\n const origin = window.location.protocol + '//' + window.location.host;\n const authorizedOrigins = process.env.GOOGLE_AUTH_ORIGINS?.split(',') ?? [];\n if (authorizedOrigins.includes(origin)) {\n return process.env.GOOGLE_CLIENT_ID;\n }\n\n return undefined;\n}\n"],"names":[],"mappings":";;;;AAqBM,SAAU,YAAY,CAAC,KAAwB,EAAA;AACnD,IAAA,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;AAC7B,IAAA,MAAM,EAAE,cAAc,EAAE,sBAAsB,EAAE,GAAG,KAAK,CAAC;AACzD,IAAA,MAAM,SAAS,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;AAC/C,IAAA,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAU,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC;IACzF,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAU,KAAK,CAAC,CAAC;IAC/D,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAU,KAAK,CAAC,CAAC;IAErE,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;YACjC,eAAe,CAAC,wCAAwC,EAAE,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;YACvF,OAAO;AACR,SAAA;QAED,IAAI,CAAC,WAAW,EAAE;AAChB,YAAA,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC;AAC5B,gBAAA,SAAS,EAAE,cAAc;AACzB,gBAAA,QAAQ,EAAE,sBAAsB;AACjC,aAAA,CAAC,CAAC;YACH,cAAc,CAAC,IAAI,CAAC,CAAC;AACtB,SAAA;AAED,QAAA,IAAI,SAAS,CAAC,OAAO,IAAI,CAAC,cAAc,EAAE;AACxC,YAAA,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACvD,iBAAiB,CAAC,IAAI,CAAC,CAAC;AACzB,SAAA;AACH,KAAC,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,sBAAsB,CAAC,CAAC,CAAC;IAE5G,IAAI,CAAC,cAAc,EAAE;AACnB,QAAA,OAAO,IAAI,CAAC;AACb,KAAA;AAED,IAAA,OAAO,KAAK,CAAA,aAAA,CAAA,KAAA,EAAA,EAAA,GAAG,EAAE,SAAS,GAAI,CAAC;AACjC,CAAC;AAEK,SAAU,iBAAiB,CAAC,QAA4B,EAAA;;AAC5D,IAAA,IAAI,QAAQ,EAAE;AACZ,QAAA,OAAO,QAAQ,CAAC;AACjB,KAAA;AAED,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,GAAG,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;AACtE,IAAA,MAAM,iBAAiB,GAAG,CAAA,EAAA,GAAA,CAAA,EAAA,GAAA,8FAA+B,MAAA,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAE,KAAK,CAAC,GAAG,CAAC,MAAA,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,EAAA,GAAI,EAAE,CAAC;AAC5E,IAAA,IAAI,iBAAiB,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;AACtC,QAAA,OAAO,0EAA4B,CAAC;AACrC,KAAA;AAED,IAAA,OAAO,SAAS,CAAC;AACnB;;;;"}
1
+ {"version":3,"file":"GoogleButton.js","sources":["../../src/GoogleButton.tsx"],"sourcesContent":["import { GoogleCredentialResponse } from '@medplum/core';\nimport React, { useEffect, useRef, useState } from 'react';\nimport { useMedplum } from './MedplumProvider';\nimport { createScriptTag } from './utils';\n\ninterface GoogleApi {\n accounts: {\n id: {\n initialize: (args: any) => void;\n renderButton: (parent: HTMLElement, args: any) => void;\n };\n };\n}\n\ndeclare const google: GoogleApi;\n\nexport interface GoogleButtonProps {\n readonly googleClientId?: string;\n readonly handleGoogleCredential: (response: GoogleCredentialResponse) => void;\n}\n\nexport function GoogleButton(props: GoogleButtonProps): JSX.Element | null {\n const medplum = useMedplum();\n const { googleClientId, handleGoogleCredential } = props;\n const parentRef = useRef<HTMLDivElement>(null);\n const [scriptLoaded, setScriptLoaded] = useState<boolean>(typeof google !== 'undefined');\n const [initialized, setInitialized] = useState<boolean>(false);\n const [buttonRendered, setButtonRendered] = useState<boolean>(false);\n\n useEffect(() => {\n if (typeof google === 'undefined') {\n createScriptTag('https://accounts.google.com/gsi/client', () => setScriptLoaded(true));\n return;\n }\n\n if (!initialized) {\n google.accounts.id.initialize({\n client_id: googleClientId,\n callback: handleGoogleCredential,\n });\n setInitialized(true);\n }\n\n if (parentRef.current && !buttonRendered) {\n google.accounts.id.renderButton(parentRef.current, {});\n setButtonRendered(true);\n }\n }, [medplum, googleClientId, initialized, scriptLoaded, parentRef, buttonRendered, handleGoogleCredential]);\n\n if (!googleClientId) {\n return null;\n }\n\n return <div ref={parentRef} />;\n}\n\nexport function getGoogleClientId(clientId: string | undefined): string | undefined {\n if (clientId) {\n return clientId;\n }\n\n const origin = window.location.protocol + '//' + window.location.host;\n const authorizedOrigins = process.env.GOOGLE_AUTH_ORIGINS?.split(',') ?? [];\n if (authorizedOrigins.includes(origin)) {\n return process.env.GOOGLE_CLIENT_ID;\n }\n\n return undefined;\n}\n"],"names":[],"mappings":";;;;AAqBM,SAAU,YAAY,CAAC,KAAwB,EAAA;AACnD,IAAA,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;AAC7B,IAAA,MAAM,EAAE,cAAc,EAAE,sBAAsB,EAAE,GAAG,KAAK,CAAC;AACzD,IAAA,MAAM,SAAS,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;AAC/C,IAAA,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAU,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC;IACzF,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAU,KAAK,CAAC,CAAC;IAC/D,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAU,KAAK,CAAC,CAAC;IAErE,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;YACjC,eAAe,CAAC,wCAAwC,EAAE,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;YACvF,OAAO;AACR,SAAA;QAED,IAAI,CAAC,WAAW,EAAE;AAChB,YAAA,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC;AAC5B,gBAAA,SAAS,EAAE,cAAc;AACzB,gBAAA,QAAQ,EAAE,sBAAsB;AACjC,aAAA,CAAC,CAAC;YACH,cAAc,CAAC,IAAI,CAAC,CAAC;AACtB,SAAA;AAED,QAAA,IAAI,SAAS,CAAC,OAAO,IAAI,CAAC,cAAc,EAAE;AACxC,YAAA,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACvD,iBAAiB,CAAC,IAAI,CAAC,CAAC;AACzB,SAAA;AACH,KAAC,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,sBAAsB,CAAC,CAAC,CAAC;IAE5G,IAAI,CAAC,cAAc,EAAE;AACnB,QAAA,OAAO,IAAI,CAAC;AACb,KAAA;AAED,IAAA,OAAO,KAAK,CAAA,aAAA,CAAA,KAAA,EAAA,EAAA,GAAG,EAAE,SAAS,GAAI,CAAC;AACjC,CAAC;AAEK,SAAU,iBAAiB,CAAC,QAA4B,EAAA;;AAC5D,IAAA,IAAI,QAAQ,EAAE;AACZ,QAAA,OAAO,QAAQ,CAAC;AACjB,KAAA;AAED,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,GAAG,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;AACtE,IAAA,MAAM,iBAAiB,GAAG,CAAA,EAAA,GAAA,CAAA,EAAA,GAAA,0IAA+B,MAAA,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAE,KAAK,CAAC,GAAG,CAAC,MAAA,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,EAAA,GAAI,EAAE,CAAC;AAC5E,IAAA,IAAI,iBAAiB,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;AACtC,QAAA,OAAO,0EAA4B,CAAC;AACrC,KAAA;AAED,IAAA,OAAO,SAAS,CAAC;AACnB;;;;"}
@@ -48,9 +48,13 @@ function Header(props) {
48
48
  logins.map((login) => {
49
49
  var _a, _b, _c, _d;
50
50
  return ((_a = login.profile) === null || _a === void 0 ? void 0 : _a.reference) !== getReferenceString(context.profile) && (React.createElement("div", { className: "medplum-nav-menu-profile", key: (_b = login.profile) === null || _b === void 0 ? void 0 : _b.reference, onClick: () => {
51
- medplum.setActiveLogin(login);
52
- setUserMenuVisible(false);
53
- window.location.reload();
51
+ medplum
52
+ .setActiveLogin(login)
53
+ .then(() => {
54
+ setUserMenuVisible(false);
55
+ window.location.reload();
56
+ })
57
+ .catch(console.log);
54
58
  } },
55
59
  React.createElement("div", { className: "medplum-nav-menu-profile-icon" },
56
60
  React.createElement(Avatar, null)),
@@ -1 +1 @@
1
- {"version":3,"file":"Header.js","sources":["../../src/Header.tsx"],"sourcesContent":["import { getReferenceString, ProfileResource } from '@medplum/core';\nimport { HumanName, UserConfiguration } from '@medplum/fhirtypes';\nimport React, { useState } from 'react';\nimport { useLocation, useNavigate } from 'react-router-dom';\nimport { Avatar } from './Avatar';\nimport { Button } from './Button';\nimport { HeaderSearchInput, HeaderSearchTypes } from './HeaderSearchInput';\nimport { HumanNameDisplay } from './HumanNameDisplay';\nimport { MedplumLink } from './MedplumLink';\nimport { useMedplumContext } from './MedplumProvider';\nimport { Popup } from './Popup';\nimport './Header.css';\n\nexport interface HeaderProps {\n readonly title?: string;\n readonly bgColor?: string;\n readonly onLogo?: () => void;\n readonly onProfile?: () => void;\n readonly onSignOut?: () => void;\n readonly config?: UserConfiguration;\n}\n\nexport function Header(props: HeaderProps): JSX.Element {\n const navigate = useNavigate();\n const location = useLocation();\n const context = useMedplumContext();\n const medplum = context.medplum;\n const logins = medplum.getLogins();\n const [userMenuVisible, setUserMenuVisible] = useState(false);\n const [sidebarVisible, setSidebarVisible] = useState(false);\n\n return (\n <>\n <header role=\"banner\" data-testid=\"header\" style={{ background: props.bgColor }}>\n <div>\n <MedplumLink\n label=\"Toggle sidebar\"\n testid=\"header-menu-button\"\n onClick={() => setSidebarVisible(!sidebarVisible)}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{ width: 20, height: 20, verticalAlign: 'text-top' }}\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </MedplumLink>\n <MedplumLink id=\"medplum-header-logo\" testid=\"header-logo\" onClick={props.onLogo}>\n {props.title || 'Medplum'}\n </MedplumLink>\n {context.profile && (\n <HeaderSearchInput\n key={`header-input-${location.pathname}`}\n name=\"search\"\n className=\"medplum-nav-search-container\"\n placeholder=\"Search\"\n onChange={(resource: HeaderSearchTypes) => navigate(`/${resource.resourceType}/${resource.id}`)}\n />\n )}\n </div>\n {context.profile && (\n <div className=\"medplum-nav-menu-container\">\n <MedplumLink testid=\"header-profile-menu-button\" onClick={() => setUserMenuVisible(true)}>\n <Avatar size=\"small\" color=\"#f68d42\" value={context.profile} />\n </MedplumLink>\n <Popup\n visible={userMenuVisible}\n autoClose={true}\n activeClassName=\"medplum-nav-menu-popover\"\n onClose={() => setUserMenuVisible(false)}\n >\n <div className=\"medplum-nav-menu\">\n <div style={{ margin: 'auto', padding: '8px' }}>\n <Avatar size=\"large\" value={context.profile} />\n </div>\n <div style={{ margin: 'auto', padding: '8px' }}>\n <div style={{ margin: '4px auto 4px auto', fontWeight: 'bold' }}>\n <HumanNameDisplay value={context.profile?.name?.[0] as HumanName} />\n </div>\n <div style={{ margin: '4px auto 4px auto' }}>{medplum.getActiveLogin()?.project?.display}</div>\n <Button\n testid=\"header-profile-link\"\n onClick={() => {\n setUserMenuVisible(false);\n if (props.onProfile) {\n props.onProfile();\n }\n }}\n >\n Manage your account\n </Button>\n </div>\n {logins.length > 1 && (\n <div>\n <hr />\n {logins.map(\n (login) =>\n login.profile?.reference !== getReferenceString(context.profile as ProfileResource) && (\n <div\n className=\"medplum-nav-menu-profile\"\n key={login.profile?.reference}\n onClick={() => {\n medplum.setActiveLogin(login);\n setUserMenuVisible(false);\n window.location.reload();\n }}\n >\n <div className=\"medplum-nav-menu-profile-icon\">\n <Avatar />\n </div>\n <div className=\"medplum-nav-menu-profile-label\">\n {login.profile?.display}\n <div className=\"medplum-nav-menu-profile-help-text\">{login.project?.display}</div>\n </div>\n </div>\n )\n )}\n </div>\n )}\n <hr />\n <div style={{ margin: 'auto', padding: '8px' }}>\n <Button\n testid=\"header-add-account-button\"\n onClick={() => {\n navigate('/signin');\n }}\n >\n Add another account\n </Button>\n </div>\n <hr />\n <div style={{ margin: 'auto', padding: '8px' }}>\n <Button\n testid=\"header-signout-button\"\n onClick={() => {\n setUserMenuVisible(false);\n if (props.onSignOut) {\n props.onSignOut();\n }\n }}\n >\n Sign out of all accounts\n </Button>\n </div>\n <hr />\n <div style={{ margin: 'auto', padding: '8px', fontSize: '12px' }}>\n <a href=\"https://www.medplum.com/terms\">Terms</a>\n <a href=\"https://www.medplum.com/privacy\">Privacy</a>\n </div>\n </div>\n </Popup>\n </div>\n )}\n </header>\n <Popup\n modal={true}\n autoClose={true}\n visible={sidebarVisible}\n activeClassName=\"medplum-sidebar active\"\n inactiveClassName=\"medplum-sidebar\"\n onClose={() => setSidebarVisible(false)}\n >\n {props.config?.menu?.map((menu, index) => (\n <React.Fragment key={`menu-${index}-${props.config?.menu?.length}`}>\n <h5>{menu.title}</h5>\n <ul>\n {menu.link?.map((link) => (\n <li key={link.target}>\n <MedplumLink to={link.target}>{link.name}</MedplumLink>\n </li>\n ))}\n </ul>\n </React.Fragment>\n ))}\n <h5>Settings</h5>\n <ul>\n <li>\n <MedplumLink to={context.profile}>Profile</MedplumLink>\n </li>\n <li>\n <MedplumLink to=\"/changepassword\">Change password</MedplumLink>\n </li>\n </ul>\n </Popup>\n </>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Header.js","sources":["../../src/Header.tsx"],"sourcesContent":["import { getReferenceString, ProfileResource } from '@medplum/core';\nimport { HumanName, UserConfiguration } from '@medplum/fhirtypes';\nimport React, { useState } from 'react';\nimport { useLocation, useNavigate } from 'react-router-dom';\nimport { Avatar } from './Avatar';\nimport { Button } from './Button';\nimport { HeaderSearchInput, HeaderSearchTypes } from './HeaderSearchInput';\nimport { HumanNameDisplay } from './HumanNameDisplay';\nimport { MedplumLink } from './MedplumLink';\nimport { useMedplumContext } from './MedplumProvider';\nimport { Popup } from './Popup';\nimport './Header.css';\n\nexport interface HeaderProps {\n readonly title?: string;\n readonly bgColor?: string;\n readonly onLogo?: () => void;\n readonly onProfile?: () => void;\n readonly onSignOut?: () => void;\n readonly config?: UserConfiguration;\n}\n\nexport function Header(props: HeaderProps): JSX.Element {\n const navigate = useNavigate();\n const location = useLocation();\n const context = useMedplumContext();\n const medplum = context.medplum;\n const logins = medplum.getLogins();\n const [userMenuVisible, setUserMenuVisible] = useState(false);\n const [sidebarVisible, setSidebarVisible] = useState(false);\n\n return (\n <>\n <header role=\"banner\" data-testid=\"header\" style={{ background: props.bgColor }}>\n <div>\n <MedplumLink\n label=\"Toggle sidebar\"\n testid=\"header-menu-button\"\n onClick={() => setSidebarVisible(!sidebarVisible)}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{ width: 20, height: 20, verticalAlign: 'text-top' }}\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </MedplumLink>\n <MedplumLink id=\"medplum-header-logo\" testid=\"header-logo\" onClick={props.onLogo}>\n {props.title || 'Medplum'}\n </MedplumLink>\n {context.profile && (\n <HeaderSearchInput\n key={`header-input-${location.pathname}`}\n name=\"search\"\n className=\"medplum-nav-search-container\"\n placeholder=\"Search\"\n onChange={(resource: HeaderSearchTypes) => navigate(`/${resource.resourceType}/${resource.id}`)}\n />\n )}\n </div>\n {context.profile && (\n <div className=\"medplum-nav-menu-container\">\n <MedplumLink testid=\"header-profile-menu-button\" onClick={() => setUserMenuVisible(true)}>\n <Avatar size=\"small\" color=\"#f68d42\" value={context.profile} />\n </MedplumLink>\n <Popup\n visible={userMenuVisible}\n autoClose={true}\n activeClassName=\"medplum-nav-menu-popover\"\n onClose={() => setUserMenuVisible(false)}\n >\n <div className=\"medplum-nav-menu\">\n <div style={{ margin: 'auto', padding: '8px' }}>\n <Avatar size=\"large\" value={context.profile} />\n </div>\n <div style={{ margin: 'auto', padding: '8px' }}>\n <div style={{ margin: '4px auto 4px auto', fontWeight: 'bold' }}>\n <HumanNameDisplay value={context.profile?.name?.[0] as HumanName} />\n </div>\n <div style={{ margin: '4px auto 4px auto' }}>{medplum.getActiveLogin()?.project?.display}</div>\n <Button\n testid=\"header-profile-link\"\n onClick={() => {\n setUserMenuVisible(false);\n if (props.onProfile) {\n props.onProfile();\n }\n }}\n >\n Manage your account\n </Button>\n </div>\n {logins.length > 1 && (\n <div>\n <hr />\n {logins.map(\n (login) =>\n login.profile?.reference !== getReferenceString(context.profile as ProfileResource) && (\n <div\n className=\"medplum-nav-menu-profile\"\n key={login.profile?.reference}\n onClick={() => {\n medplum\n .setActiveLogin(login)\n .then(() => {\n setUserMenuVisible(false);\n window.location.reload();\n })\n .catch(console.log);\n }}\n >\n <div className=\"medplum-nav-menu-profile-icon\">\n <Avatar />\n </div>\n <div className=\"medplum-nav-menu-profile-label\">\n {login.profile?.display}\n <div className=\"medplum-nav-menu-profile-help-text\">{login.project?.display}</div>\n </div>\n </div>\n )\n )}\n </div>\n )}\n <hr />\n <div style={{ margin: 'auto', padding: '8px' }}>\n <Button\n testid=\"header-add-account-button\"\n onClick={() => {\n navigate('/signin');\n }}\n >\n Add another account\n </Button>\n </div>\n <hr />\n <div style={{ margin: 'auto', padding: '8px' }}>\n <Button\n testid=\"header-signout-button\"\n onClick={() => {\n setUserMenuVisible(false);\n if (props.onSignOut) {\n props.onSignOut();\n }\n }}\n >\n Sign out of all accounts\n </Button>\n </div>\n <hr />\n <div style={{ margin: 'auto', padding: '8px', fontSize: '12px' }}>\n <a href=\"https://www.medplum.com/terms\">Terms</a>\n <a href=\"https://www.medplum.com/privacy\">Privacy</a>\n </div>\n </div>\n </Popup>\n </div>\n )}\n </header>\n <Popup\n modal={true}\n autoClose={true}\n visible={sidebarVisible}\n activeClassName=\"medplum-sidebar active\"\n inactiveClassName=\"medplum-sidebar\"\n onClose={() => setSidebarVisible(false)}\n >\n {props.config?.menu?.map((menu, index) => (\n <React.Fragment key={`menu-${index}-${props.config?.menu?.length}`}>\n <h5>{menu.title}</h5>\n <ul>\n {menu.link?.map((link) => (\n <li key={link.target}>\n <MedplumLink to={link.target}>{link.name}</MedplumLink>\n </li>\n ))}\n </ul>\n </React.Fragment>\n ))}\n <h5>Settings</h5>\n <ul>\n <li>\n <MedplumLink to={context.profile}>Profile</MedplumLink>\n </li>\n <li>\n <MedplumLink to=\"/changepassword\">Change password</MedplumLink>\n </li>\n </ul>\n </Popup>\n </>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -4,20 +4,9 @@ import { killEvent } from './utils/dom.js';
4
4
 
5
5
  function MedplumLink(props) {
6
6
  const navigate = useNavigate();
7
- let href = '#';
8
- if (props.to) {
9
- if (typeof props.to === 'string') {
10
- href = props.to;
11
- }
12
- else if ('resourceType' in props.to) {
13
- href = `/${props.to.resourceType}/${props.to.id}`;
14
- }
15
- else if ('reference' in props.to) {
16
- href = `/${props.to.reference}`;
17
- }
18
- if (props.suffix) {
19
- href += '/' + props.suffix;
20
- }
7
+ let href = getHref(props.to);
8
+ if (props.suffix) {
9
+ href += '/' + props.suffix;
21
10
  }
22
11
  return (React.createElement("a", { href: href, id: props.id, "aria-label": props.label, "data-testid": props.testid || 'link', className: props.className, onClick: (e) => {
23
12
  killEvent(e);
@@ -29,6 +18,32 @@ function MedplumLink(props) {
29
18
  }
30
19
  } }, props.children));
31
20
  }
21
+ function getHref(to) {
22
+ if (to) {
23
+ if (typeof to === 'string') {
24
+ return getStringHref(to);
25
+ }
26
+ else if ('resourceType' in to) {
27
+ return getResourceHref(to);
28
+ }
29
+ else if ('reference' in to) {
30
+ return getReferenceHref(to);
31
+ }
32
+ }
33
+ return '#';
34
+ }
35
+ function getStringHref(to) {
36
+ if (to.startsWith('http://') || to.startsWith('https://') || to.startsWith('/')) {
37
+ return to;
38
+ }
39
+ return '/' + to;
40
+ }
41
+ function getResourceHref(to) {
42
+ return `/${to.resourceType}/${to.id}`;
43
+ }
44
+ function getReferenceHref(to) {
45
+ return `/${to.reference}`;
46
+ }
32
47
 
33
48
  export { MedplumLink };
34
49
  //# sourceMappingURL=MedplumLink.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MedplumLink.js","sources":["../../src/MedplumLink.tsx"],"sourcesContent":["import { Reference, Resource } from '@medplum/fhirtypes';\nimport React from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { killEvent } from './utils/dom';\n\nexport interface MedplumLinkProps {\n to?: Resource | Reference | string;\n suffix?: string;\n label?: string;\n id?: string;\n testid?: string;\n className?: string;\n onClick?: () => void;\n children: React.ReactNode;\n}\n\nexport function MedplumLink(props: MedplumLinkProps): JSX.Element {\n const navigate = useNavigate();\n\n let href = '#';\n if (props.to) {\n if (typeof props.to === 'string') {\n href = props.to;\n } else if ('resourceType' in props.to) {\n href = `/${props.to.resourceType}/${props.to.id}`;\n } else if ('reference' in props.to) {\n href = `/${props.to.reference}`;\n }\n\n if (props.suffix) {\n href += '/' + props.suffix;\n }\n }\n\n return (\n <a\n href={href}\n id={props.id}\n aria-label={props.label}\n data-testid={props.testid || 'link'}\n className={props.className}\n onClick={(e: React.SyntheticEvent) => {\n killEvent(e);\n if (props.onClick) {\n props.onClick();\n } else if (props.to) {\n navigate(href);\n }\n }}\n >\n {props.children}\n </a>\n );\n}\n"],"names":[],"mappings":";;;;AAgBM,SAAU,WAAW,CAAC,KAAuB,EAAA;AACjD,IAAA,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAE/B,IAAI,IAAI,GAAG,GAAG,CAAC;IACf,IAAI,KAAK,CAAC,EAAE,EAAE;AACZ,QAAA,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,EAAE;AAChC,YAAA,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC;AACjB,SAAA;AAAM,aAAA,IAAI,cAAc,IAAI,KAAK,CAAC,EAAE,EAAE;AACrC,YAAA,IAAI,GAAG,CAAA,CAAA,EAAI,KAAK,CAAC,EAAE,CAAC,YAAY,CAAI,CAAA,EAAA,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;AACnD,SAAA;AAAM,aAAA,IAAI,WAAW,IAAI,KAAK,CAAC,EAAE,EAAE;YAClC,IAAI,GAAG,IAAI,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC;AACjC,SAAA;QAED,IAAI,KAAK,CAAC,MAAM,EAAE;AAChB,YAAA,IAAI,IAAI,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC;AAC5B,SAAA;AACF,KAAA;AAED,IAAA,QACE,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EACE,IAAI,EAAE,IAAI,EACV,EAAE,EAAE,KAAK,CAAC,EAAE,EACA,YAAA,EAAA,KAAK,CAAC,KAAK,EAAA,aAAA,EACV,KAAK,CAAC,MAAM,IAAI,MAAM,EACnC,SAAS,EAAE,KAAK,CAAC,SAAS,EAC1B,OAAO,EAAE,CAAC,CAAuB,KAAI;YACnC,SAAS,CAAC,CAAC,CAAC,CAAC;YACb,IAAI,KAAK,CAAC,OAAO,EAAE;gBACjB,KAAK,CAAC,OAAO,EAAE,CAAC;AACjB,aAAA;iBAAM,IAAI,KAAK,CAAC,EAAE,EAAE;gBACnB,QAAQ,CAAC,IAAI,CAAC,CAAC;AAChB,aAAA;AACH,SAAC,IAEA,KAAK,CAAC,QAAQ,CACb,EACJ;AACJ;;;;"}
1
+ {"version":3,"file":"MedplumLink.js","sources":["../../src/MedplumLink.tsx"],"sourcesContent":["import { Reference, Resource } from '@medplum/fhirtypes';\nimport React from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { killEvent } from './utils/dom';\n\nexport interface MedplumLinkProps {\n to?: Resource | Reference | string;\n suffix?: string;\n label?: string;\n id?: string;\n testid?: string;\n className?: string;\n onClick?: () => void;\n children: React.ReactNode;\n}\n\nexport function MedplumLink(props: MedplumLinkProps): JSX.Element {\n const navigate = useNavigate();\n\n let href = getHref(props.to);\n if (props.suffix) {\n href += '/' + props.suffix;\n }\n\n return (\n <a\n href={href}\n id={props.id}\n aria-label={props.label}\n data-testid={props.testid || 'link'}\n className={props.className}\n onClick={(e: React.SyntheticEvent) => {\n killEvent(e);\n if (props.onClick) {\n props.onClick();\n } else if (props.to) {\n navigate(href);\n }\n }}\n >\n {props.children}\n </a>\n );\n}\n\nfunction getHref(to: Resource | Reference | string | undefined): string {\n if (to) {\n if (typeof to === 'string') {\n return getStringHref(to);\n } else if ('resourceType' in to) {\n return getResourceHref(to);\n } else if ('reference' in to) {\n return getReferenceHref(to);\n }\n }\n return '#';\n}\n\nfunction getStringHref(to: string): string {\n if (to.startsWith('http://') || to.startsWith('https://') || to.startsWith('/')) {\n return to;\n }\n return '/' + to;\n}\n\nfunction getResourceHref(to: Resource): string {\n return `/${to.resourceType}/${to.id}`;\n}\n\nfunction getReferenceHref(to: Reference): string {\n return `/${to.reference}`;\n}\n"],"names":[],"mappings":";;;;AAgBM,SAAU,WAAW,CAAC,KAAuB,EAAA;AACjD,IAAA,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAE/B,IAAI,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC7B,IAAI,KAAK,CAAC,MAAM,EAAE;AAChB,QAAA,IAAI,IAAI,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC;AAC5B,KAAA;AAED,IAAA,QACE,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EACE,IAAI,EAAE,IAAI,EACV,EAAE,EAAE,KAAK,CAAC,EAAE,EACA,YAAA,EAAA,KAAK,CAAC,KAAK,EAAA,aAAA,EACV,KAAK,CAAC,MAAM,IAAI,MAAM,EACnC,SAAS,EAAE,KAAK,CAAC,SAAS,EAC1B,OAAO,EAAE,CAAC,CAAuB,KAAI;YACnC,SAAS,CAAC,CAAC,CAAC,CAAC;YACb,IAAI,KAAK,CAAC,OAAO,EAAE;gBACjB,KAAK,CAAC,OAAO,EAAE,CAAC;AACjB,aAAA;iBAAM,IAAI,KAAK,CAAC,EAAE,EAAE;gBACnB,QAAQ,CAAC,IAAI,CAAC,CAAC;AAChB,aAAA;AACH,SAAC,IAEA,KAAK,CAAC,QAAQ,CACb,EACJ;AACJ,CAAC;AAED,SAAS,OAAO,CAAC,EAA6C,EAAA;AAC5D,IAAA,IAAI,EAAE,EAAE;AACN,QAAA,IAAI,OAAO,EAAE,KAAK,QAAQ,EAAE;AAC1B,YAAA,OAAO,aAAa,CAAC,EAAE,CAAC,CAAC;AAC1B,SAAA;aAAM,IAAI,cAAc,IAAI,EAAE,EAAE;AAC/B,YAAA,OAAO,eAAe,CAAC,EAAE,CAAC,CAAC;AAC5B,SAAA;aAAM,IAAI,WAAW,IAAI,EAAE,EAAE;AAC5B,YAAA,OAAO,gBAAgB,CAAC,EAAE,CAAC,CAAC;AAC7B,SAAA;AACF,KAAA;AACD,IAAA,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,aAAa,CAAC,EAAU,EAAA;IAC/B,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;AAC/E,QAAA,OAAO,EAAE,CAAC;AACX,KAAA;IACD,OAAO,GAAG,GAAG,EAAE,CAAC;AAClB,CAAC;AAED,SAAS,eAAe,CAAC,EAAY,EAAA;IACnC,OAAO,CAAA,CAAA,EAAI,EAAE,CAAC,YAAY,IAAI,EAAE,CAAC,EAAE,CAAA,CAAE,CAAC;AACxC,CAAC;AAED,SAAS,gBAAgB,CAAC,EAAa,EAAA;AACrC,IAAA,OAAO,CAAI,CAAA,EAAA,EAAE,CAAC,SAAS,EAAE,CAAC;AAC5B;;;;"}
@@ -30,7 +30,7 @@ function PlanDefinitionBuilder(props) {
30
30
  const valueRef = useRef();
31
31
  valueRef.current = value;
32
32
  useEffect(() => {
33
- medplum.requestSchema('PlanDefinition').then(setSchema);
33
+ medplum.requestSchema('PlanDefinition').then(setSchema).catch(console.log);
34
34
  }, [medplum]);
35
35
  useEffect(() => {
36
36
  setValue(ensurePlanDefinitionKeys(defaultValue !== null && defaultValue !== void 0 ? defaultValue : { resourceType: 'PlanDefinition' }));