@medplum/react 0.9.38 → 0.10.1

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 (291) hide show
  1. package/dist/cjs/AttachmentButton.d.ts +9 -0
  2. package/dist/cjs/CodeInput.d.ts +2 -1
  3. package/dist/cjs/CodeableConceptInput.d.ts +2 -1
  4. package/dist/cjs/CodingInput.d.ts +2 -1
  5. package/dist/cjs/DateTimeInput.d.ts +9 -2
  6. package/dist/cjs/DiagnosticReportDisplay.d.ts +0 -1
  7. package/dist/cjs/ReferenceInput.d.ts +1 -0
  8. package/dist/cjs/ResourceAvatar.d.ts +8 -0
  9. package/dist/cjs/ResourceBadge.d.ts +0 -1
  10. package/dist/cjs/ResourceHistoryTable.d.ts +0 -1
  11. package/dist/cjs/ResourceInput.d.ts +2 -3
  12. package/dist/cjs/SearchPopupMenu.d.ts +0 -4
  13. package/dist/cjs/SearchUtils.d.ts +5 -5
  14. package/dist/cjs/StatusBadge.d.ts +0 -1
  15. package/dist/cjs/ValueSetAutocomplete.d.ts +10 -0
  16. package/dist/cjs/auth/RegisterForm.d.ts +0 -1
  17. package/dist/cjs/auth/SignInForm.d.ts +0 -1
  18. package/dist/cjs/defaulttheme.css +0 -51
  19. package/dist/cjs/index.d.ts +3 -21
  20. package/dist/cjs/index.js +859 -1560
  21. package/dist/cjs/index.js.map +1 -1
  22. package/dist/cjs/index.min.js +1 -1
  23. package/dist/cjs/index.min.js.map +1 -1
  24. package/dist/cjs/stories/{UploadButton.stories.d.ts → AttachmentButton.stories.d.ts} +1 -0
  25. package/dist/cjs/stories/{FormSection.stories.d.ts → CodeInput.stories.d.ts} +0 -0
  26. package/dist/cjs/stories/{Input.stories.d.ts → CodeableConceptInput.stories.d.ts} +0 -0
  27. package/dist/cjs/stories/PeriodInput.stories.d.ts +6 -0
  28. package/dist/cjs/stories/{Avatar.stories.d.ts → ResourceAvatar.stories.d.ts} +0 -0
  29. package/dist/cjs/stories/ResourceForm.stories.d.ts +1 -0
  30. package/dist/cjs/stories/{Loading.stories.d.ts → ResourceInput.stories.d.ts} +2 -1
  31. package/dist/cjs/stories/SearchControl.stories.d.ts +1 -0
  32. package/dist/cjs/styles.css +35 -1206
  33. package/dist/cjs/utils/outcomes.d.ts +1 -0
  34. package/dist/esm/AddressInput.js +9 -21
  35. package/dist/esm/AddressInput.js.map +1 -1
  36. package/dist/esm/AnnotationInput.js +2 -2
  37. package/dist/esm/AnnotationInput.js.map +1 -1
  38. package/dist/esm/AttachmentArrayInput.js +11 -8
  39. package/dist/esm/AttachmentArrayInput.js.map +1 -1
  40. package/dist/esm/AttachmentButton.d.ts +9 -0
  41. package/dist/esm/{UploadButton.js → AttachmentButton.js} +9 -9
  42. package/dist/esm/AttachmentButton.js.map +1 -0
  43. package/dist/esm/AttachmentInput.js +3 -3
  44. package/dist/esm/AttachmentInput.js.map +1 -1
  45. package/dist/esm/CalendarInput.js +6 -7
  46. package/dist/esm/CalendarInput.js.map +1 -1
  47. package/dist/esm/CodeInput.d.ts +2 -1
  48. package/dist/esm/CodeInput.js +16 -21
  49. package/dist/esm/CodeInput.js.map +1 -1
  50. package/dist/esm/CodeableConceptInput.d.ts +2 -1
  51. package/dist/esm/CodeableConceptInput.js +18 -33
  52. package/dist/esm/CodeableConceptInput.js.map +1 -1
  53. package/dist/esm/CodingInput.d.ts +2 -1
  54. package/dist/esm/CodingInput.js +24 -23
  55. package/dist/esm/CodingInput.js.map +1 -1
  56. package/dist/esm/ContactDetailInput.js +3 -4
  57. package/dist/esm/ContactDetailInput.js.map +1 -1
  58. package/dist/esm/ContactPointInput.js +5 -21
  59. package/dist/esm/ContactPointInput.js.map +1 -1
  60. package/dist/esm/DateTimeInput.d.ts +9 -2
  61. package/dist/esm/DateTimeInput.js +13 -3
  62. package/dist/esm/DateTimeInput.js.map +1 -1
  63. package/dist/esm/DiagnosticReportDisplay.d.ts +0 -1
  64. package/dist/esm/DiagnosticReportDisplay.js +21 -2
  65. package/dist/esm/DiagnosticReportDisplay.js.map +1 -1
  66. package/dist/esm/EncounterTimeline.js +2 -0
  67. package/dist/esm/EncounterTimeline.js.map +1 -1
  68. package/dist/esm/ExtensionInput.js +2 -2
  69. package/dist/esm/ExtensionInput.js.map +1 -1
  70. package/dist/esm/FhirPathTable.js +4 -5
  71. package/dist/esm/FhirPathTable.js.map +1 -1
  72. package/dist/esm/HumanNameInput.js +7 -17
  73. package/dist/esm/HumanNameInput.js.map +1 -1
  74. package/dist/esm/IdentifierInput.js +4 -5
  75. package/dist/esm/IdentifierInput.js.map +1 -1
  76. package/dist/esm/Logo.js +4 -4
  77. package/dist/esm/Logo.js.map +1 -1
  78. package/dist/esm/PatientTimeline.js +2 -0
  79. package/dist/esm/PatientTimeline.js.map +1 -1
  80. package/dist/esm/PeriodInput.js +5 -5
  81. package/dist/esm/PeriodInput.js.map +1 -1
  82. package/dist/esm/PlanDefinitionBuilder.js +17 -29
  83. package/dist/esm/PlanDefinitionBuilder.js.map +1 -1
  84. package/dist/esm/QuantityInput.js +5 -12
  85. package/dist/esm/QuantityInput.js.map +1 -1
  86. package/dist/esm/QuestionnaireBuilder.js +22 -25
  87. package/dist/esm/QuestionnaireBuilder.js.map +1 -1
  88. package/dist/esm/QuestionnaireForm.js +35 -29
  89. package/dist/esm/QuestionnaireForm.js.map +1 -1
  90. package/dist/esm/RangeInput.js +2 -2
  91. package/dist/esm/RangeInput.js.map +1 -1
  92. package/dist/esm/RatioInput.js +2 -2
  93. package/dist/esm/RatioInput.js.map +1 -1
  94. package/dist/esm/ReferenceInput.d.ts +1 -0
  95. package/dist/esm/ReferenceInput.js +4 -6
  96. package/dist/esm/ReferenceInput.js.map +1 -1
  97. package/dist/esm/RequestGroupDisplay.js +1 -1
  98. package/dist/esm/RequestGroupDisplay.js.map +1 -1
  99. package/dist/esm/ResourceArrayInput.js +10 -7
  100. package/dist/esm/ResourceArrayInput.js.map +1 -1
  101. package/dist/esm/ResourceAvatar.d.ts +8 -0
  102. package/dist/esm/ResourceAvatar.js +24 -0
  103. package/dist/esm/ResourceAvatar.js.map +1 -0
  104. package/dist/esm/ResourceBadge.d.ts +0 -1
  105. package/dist/esm/ResourceBadge.js +2 -3
  106. package/dist/esm/ResourceBadge.js.map +1 -1
  107. package/dist/esm/ResourceBlame.js +3 -3
  108. package/dist/esm/ResourceBlame.js.map +1 -1
  109. package/dist/esm/ResourceForm.js +10 -10
  110. package/dist/esm/ResourceForm.js.map +1 -1
  111. package/dist/esm/ResourceHistoryTable.d.ts +0 -1
  112. package/dist/esm/ResourceHistoryTable.js +2 -1
  113. package/dist/esm/ResourceHistoryTable.js.map +1 -1
  114. package/dist/esm/ResourceInput.d.ts +2 -3
  115. package/dist/esm/ResourceInput.js +37 -29
  116. package/dist/esm/ResourceInput.js.map +1 -1
  117. package/dist/esm/ResourcePropertyInput.js +30 -18
  118. package/dist/esm/ResourcePropertyInput.js.map +1 -1
  119. package/dist/esm/ResourceTimeline.js +23 -17
  120. package/dist/esm/ResourceTimeline.js.map +1 -1
  121. package/dist/esm/Scheduler.js +7 -7
  122. package/dist/esm/Scheduler.js.map +1 -1
  123. package/dist/esm/SearchControl.js +76 -58
  124. package/dist/esm/SearchControl.js.map +1 -1
  125. package/dist/esm/SearchControlField.js.map +1 -1
  126. package/dist/esm/SearchFieldEditor.js +7 -7
  127. package/dist/esm/SearchFieldEditor.js.map +1 -1
  128. package/dist/esm/SearchFilterEditor.js +11 -15
  129. package/dist/esm/SearchFilterEditor.js.map +1 -1
  130. package/dist/esm/SearchFilterValueDialog.js +4 -3
  131. package/dist/esm/SearchFilterValueDialog.js.map +1 -1
  132. package/dist/esm/SearchFilterValueInput.js +6 -7
  133. package/dist/esm/SearchFilterValueInput.js.map +1 -1
  134. package/dist/esm/SearchPopupMenu.d.ts +0 -4
  135. package/dist/esm/SearchPopupMenu.js +59 -73
  136. package/dist/esm/SearchPopupMenu.js.map +1 -1
  137. package/dist/esm/SearchUtils.d.ts +5 -5
  138. package/dist/esm/SearchUtils.js +11 -12
  139. package/dist/esm/SearchUtils.js.map +1 -1
  140. package/dist/esm/ServiceRequestTimeline.js +2 -0
  141. package/dist/esm/ServiceRequestTimeline.js.map +1 -1
  142. package/dist/esm/StatusBadge.d.ts +0 -1
  143. package/dist/esm/StatusBadge.js +55 -1
  144. package/dist/esm/StatusBadge.js.map +1 -1
  145. package/dist/esm/Timeline.js +12 -20
  146. package/dist/esm/Timeline.js.map +1 -1
  147. package/dist/esm/TimingInput.js +14 -17
  148. package/dist/esm/TimingInput.js.map +1 -1
  149. package/dist/esm/ValueSetAutocomplete.d.ts +10 -0
  150. package/dist/esm/ValueSetAutocomplete.js +65 -0
  151. package/dist/esm/ValueSetAutocomplete.js.map +1 -0
  152. package/dist/esm/auth/AuthenticationForm.js +12 -20
  153. package/dist/esm/auth/AuthenticationForm.js.map +1 -1
  154. package/dist/esm/auth/ChooseProfileForm.js +10 -10
  155. package/dist/esm/auth/ChooseProfileForm.js.map +1 -1
  156. package/dist/esm/auth/NewProjectForm.js +12 -15
  157. package/dist/esm/auth/NewProjectForm.js.map +1 -1
  158. package/dist/esm/auth/NewUserForm.js +25 -33
  159. package/dist/esm/auth/NewUserForm.js.map +1 -1
  160. package/dist/esm/auth/RegisterForm.d.ts +0 -1
  161. package/dist/esm/auth/RegisterForm.js.map +1 -1
  162. package/dist/esm/auth/SignInForm.d.ts +0 -1
  163. package/dist/esm/auth/SignInForm.js.map +1 -1
  164. package/dist/esm/defaulttheme.css +0 -51
  165. package/dist/esm/index.d.ts +3 -21
  166. package/dist/esm/index.js +4 -22
  167. package/dist/esm/index.js.map +1 -1
  168. package/dist/esm/index.min.js +1 -1
  169. package/dist/esm/index.min.js.map +1 -1
  170. package/dist/esm/node_modules/tslib/tslib.es6.js +13 -1
  171. package/dist/esm/node_modules/tslib/tslib.es6.js.map +1 -1
  172. package/dist/esm/stories/{UploadButton.stories.d.ts → AttachmentButton.stories.d.ts} +1 -0
  173. package/dist/{cjs/stories/Select.stories.d.ts → esm/stories/CodeInput.stories.d.ts} +0 -0
  174. package/dist/esm/stories/{FormSection.stories.d.ts → CodeableConceptInput.stories.d.ts} +0 -0
  175. package/dist/esm/stories/PeriodInput.stories.d.ts +6 -0
  176. package/dist/esm/stories/{Avatar.stories.d.ts → ResourceAvatar.stories.d.ts} +0 -0
  177. package/dist/esm/stories/ResourceForm.stories.d.ts +1 -0
  178. package/dist/{cjs/stories/Dialog.stories.d.ts → esm/stories/ResourceInput.stories.d.ts} +2 -1
  179. package/dist/esm/stories/SearchControl.stories.d.ts +1 -0
  180. package/dist/esm/styles.css +35 -1206
  181. package/dist/esm/utils/outcomes.d.ts +1 -0
  182. package/dist/esm/utils/outcomes.js +5 -1
  183. package/dist/esm/utils/outcomes.js.map +1 -1
  184. package/package.json +27 -19
  185. package/dist/cjs/Autocomplete.d.ts +0 -20
  186. package/dist/cjs/Avatar.d.ts +0 -12
  187. package/dist/cjs/Button.d.ts +0 -15
  188. package/dist/cjs/Checkbox.d.ts +0 -12
  189. package/dist/cjs/Dialog.d.ts +0 -10
  190. package/dist/cjs/FooterLinks.d.ts +0 -6
  191. package/dist/cjs/Header.d.ts +0 -12
  192. package/dist/cjs/HeaderSearchInput.d.ts +0 -10
  193. package/dist/cjs/Input.d.ts +0 -22
  194. package/dist/cjs/InputRow.d.ts +0 -7
  195. package/dist/cjs/Loading.d.ts +0 -3
  196. package/dist/cjs/MenuItem.d.ts +0 -9
  197. package/dist/cjs/MenuSeparator.d.ts +0 -3
  198. package/dist/cjs/Popup.d.ts +0 -14
  199. package/dist/cjs/Scrollable.d.ts +0 -9
  200. package/dist/cjs/Select.d.ts +0 -16
  201. package/dist/cjs/SubMenu.d.ts +0 -7
  202. package/dist/cjs/Tab.d.ts +0 -12
  203. package/dist/cjs/TabList.d.ts +0 -10
  204. package/dist/cjs/TabPanel.d.ts +0 -6
  205. package/dist/cjs/TabSwitch.d.ts +0 -6
  206. package/dist/cjs/TextArea.d.ts +0 -18
  207. package/dist/cjs/TitleBar.d.ts +0 -6
  208. package/dist/cjs/UploadButton.d.ts +0 -7
  209. package/dist/cjs/stories/Autocomplete.stories.d.ts +0 -9
  210. package/dist/cjs/stories/Button.stories.d.ts +0 -9
  211. package/dist/cjs/stories/Header.stories.d.ts +0 -8
  212. package/dist/cjs/stories/Tabs.stories.d.ts +0 -6
  213. package/dist/esm/Autocomplete.d.ts +0 -20
  214. package/dist/esm/Autocomplete.js +0 -281
  215. package/dist/esm/Autocomplete.js.map +0 -1
  216. package/dist/esm/Avatar.d.ts +0 -12
  217. package/dist/esm/Avatar.js +0 -24
  218. package/dist/esm/Avatar.js.map +0 -1
  219. package/dist/esm/Button.d.ts +0 -15
  220. package/dist/esm/Button.js +0 -13
  221. package/dist/esm/Button.js.map +0 -1
  222. package/dist/esm/Checkbox.d.ts +0 -12
  223. package/dist/esm/Checkbox.js +0 -13
  224. package/dist/esm/Checkbox.js.map +0 -1
  225. package/dist/esm/Dialog.d.ts +0 -10
  226. package/dist/esm/Dialog.js +0 -43
  227. package/dist/esm/Dialog.js.map +0 -1
  228. package/dist/esm/FooterLinks.d.ts +0 -6
  229. package/dist/esm/FooterLinks.js +0 -8
  230. package/dist/esm/FooterLinks.js.map +0 -1
  231. package/dist/esm/Header.d.ts +0 -12
  232. package/dist/esm/Header.js +0 -99
  233. package/dist/esm/Header.js.map +0 -1
  234. package/dist/esm/HeaderSearchInput.d.ts +0 -10
  235. package/dist/esm/HeaderSearchInput.js +0 -181
  236. package/dist/esm/HeaderSearchInput.js.map +0 -1
  237. package/dist/esm/Input.d.ts +0 -22
  238. package/dist/esm/Input.js +0 -26
  239. package/dist/esm/Input.js.map +0 -1
  240. package/dist/esm/InputRow.d.ts +0 -7
  241. package/dist/esm/InputRow.js +0 -8
  242. package/dist/esm/InputRow.js.map +0 -1
  243. package/dist/esm/Loading.d.ts +0 -3
  244. package/dist/esm/Loading.js +0 -11
  245. package/dist/esm/Loading.js.map +0 -1
  246. package/dist/esm/MenuItem.d.ts +0 -9
  247. package/dist/esm/MenuItem.js +0 -8
  248. package/dist/esm/MenuItem.js.map +0 -1
  249. package/dist/esm/MenuSeparator.d.ts +0 -3
  250. package/dist/esm/MenuSeparator.js +0 -8
  251. package/dist/esm/MenuSeparator.js.map +0 -1
  252. package/dist/esm/Popup.d.ts +0 -14
  253. package/dist/esm/Popup.js +0 -78
  254. package/dist/esm/Popup.js.map +0 -1
  255. package/dist/esm/Scrollable.d.ts +0 -9
  256. package/dist/esm/Scrollable.js +0 -12
  257. package/dist/esm/Scrollable.js.map +0 -1
  258. package/dist/esm/Select.d.ts +0 -16
  259. package/dist/esm/Select.js +0 -16
  260. package/dist/esm/Select.js.map +0 -1
  261. package/dist/esm/SubMenu.d.ts +0 -7
  262. package/dist/esm/SubMenu.js +0 -38
  263. package/dist/esm/SubMenu.js.map +0 -1
  264. package/dist/esm/Tab.d.ts +0 -12
  265. package/dist/esm/Tab.js +0 -19
  266. package/dist/esm/Tab.js.map +0 -1
  267. package/dist/esm/TabList.d.ts +0 -10
  268. package/dist/esm/TabList.js +0 -23
  269. package/dist/esm/TabList.js.map +0 -1
  270. package/dist/esm/TabPanel.d.ts +0 -6
  271. package/dist/esm/TabPanel.js +0 -8
  272. package/dist/esm/TabPanel.js.map +0 -1
  273. package/dist/esm/TabSwitch.d.ts +0 -6
  274. package/dist/esm/TabSwitch.js +0 -16
  275. package/dist/esm/TabSwitch.js.map +0 -1
  276. package/dist/esm/TextArea.d.ts +0 -18
  277. package/dist/esm/TextArea.js +0 -16
  278. package/dist/esm/TextArea.js.map +0 -1
  279. package/dist/esm/TitleBar.d.ts +0 -6
  280. package/dist/esm/TitleBar.js +0 -8
  281. package/dist/esm/TitleBar.js.map +0 -1
  282. package/dist/esm/UploadButton.d.ts +0 -7
  283. package/dist/esm/UploadButton.js.map +0 -1
  284. package/dist/esm/stories/Autocomplete.stories.d.ts +0 -9
  285. package/dist/esm/stories/Button.stories.d.ts +0 -9
  286. package/dist/esm/stories/Dialog.stories.d.ts +0 -5
  287. package/dist/esm/stories/Header.stories.d.ts +0 -8
  288. package/dist/esm/stories/Input.stories.d.ts +0 -6
  289. package/dist/esm/stories/Loading.stories.d.ts +0 -5
  290. package/dist/esm/stories/Select.stories.d.ts +0 -6
  291. package/dist/esm/stories/Tabs.stories.d.ts +0 -6
package/dist/cjs/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@medplum/core'), require('react'), require('react-router-dom')) :
3
- typeof define === 'function' && define.amd ? define(['exports', '@medplum/core', 'react', 'react-router-dom'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.medplum = global.medplum || {}, global.medplum.ui = {}), global.medplum.core, global.React, global.ReactRouterDOM));
5
- })(this, (function (exports, core, React, reactRouterDom) { 'use strict';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@medplum/core'), require('react'), require('@mantine/core'), require('@tabler/icons'), require('react-router-dom')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', '@medplum/core', 'react', '@mantine/core', '@tabler/icons', 'react-router-dom'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.medplum = global.medplum || {}, global.medplum.ui = {}), global.medplum.core, global.React, global.mantine.core, global.tabler.icons, global.ReactRouterDOM));
5
+ })(this, (function (exports, core, React, core$1, icons, reactRouterDom) { 'use strict';
6
6
 
7
7
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
8
 
@@ -16,65 +16,6 @@
16
16
  return React__default["default"].createElement(React__default["default"].Fragment, null, core.formatAddress(address));
17
17
  }
18
18
 
19
- function getIssuesForExpression(outcome, expression) {
20
- var _a;
21
- return (_a = outcome === null || outcome === void 0 ? void 0 : outcome.issue) === null || _a === void 0 ? void 0 : _a.filter((issue) => { var _a; return isExpressionMatch((_a = issue.expression) === null || _a === void 0 ? void 0 : _a[0], expression); });
22
- }
23
- function isExpressionMatch(expr1, expr2) {
24
- // Expression can be either "fieldName" or "resourceType.fieldName"
25
- if (expr1 === expr2) {
26
- return true;
27
- }
28
- if (!expr1 || !expr2) {
29
- return false;
30
- }
31
- const dot1 = expr1.indexOf('.');
32
- if (dot1 >= 0 && expr1.substring(dot1 + 1) === expr2) {
33
- return true;
34
- }
35
- const dot2 = expr2.indexOf('.');
36
- if (dot2 >= 0 && expr2.substring(dot2 + 1) === expr1) {
37
- return true;
38
- }
39
- return false;
40
- }
41
-
42
- function Input(props) {
43
- const className = 'medplum-input';
44
- const issues = getIssuesForExpression(props.outcome, props.name);
45
- const invalid = issues && issues.length > 0;
46
- return (React__default["default"].createElement("input", { id: props.name, name: props.name, type: getInputType(props.type), size: props.size, step: props.step, className: className, style: props.style, defaultValue: props.defaultValue || '', required: props.required, autoCapitalize: props.autoCapitalize, autoComplete: props.autoComplete, autoFocus: props.autoFocus, ref: props.inputRef, "aria-invalid": invalid, "aria-describedby": invalid ? props.name + '-errors' : '', placeholder: props.placeholder, "data-testid": props.testid, disabled: props.disabled, onChange: (e) => {
47
- if (props.onChange) {
48
- props.onChange(e.currentTarget.value);
49
- }
50
- } }));
51
- }
52
- /**
53
- * Returns the input type for the requested type.
54
- * JSDOM does not support many of the valid <input> type attributes.
55
- * For example, it won't fire change events for <input type="datetime-local">.
56
- * @param requestedType The optional type as requested by the parent component.
57
- */
58
- function getInputType(requestedType) {
59
- const result = requestedType || 'text';
60
- return result;
61
- }
62
-
63
- function InputRow(props) {
64
- return (React__default["default"].createElement("div", { className: "medplum-input-row", style: { justifyContent: props.justifyContent } }, props.children));
65
- }
66
-
67
- function Select(props) {
68
- const className = 'medplum-select';
69
- const issues = getIssuesForExpression(props.outcome, props.name);
70
- const invalid = issues && issues.length > 0;
71
- return (React__default["default"].createElement("select", { id: props.name, name: props.name, className: className, defaultValue: props.defaultValue || '', required: props.required, autoFocus: props.autoFocus, ref: props.inputRef, style: props.style, "aria-invalid": invalid, "aria-describedby": invalid ? props.name + '-errors' : '', "data-testid": props.testid, onChange: (e) => {
72
- if (props.onChange) {
73
- props.onChange(e.currentTarget.value);
74
- }
75
- } }, props.children));
76
- }
77
-
78
19
  function getLine(address, index) {
79
20
  return address && address.line && address.line.length > index ? address.line[index] : '';
80
21
  }
@@ -117,24 +58,14 @@
117
58
  function setPostalCode(postalCode) {
118
59
  setValueWrapper(Object.assign(Object.assign({}, valueRef.current), { postalCode }));
119
60
  }
120
- return (React__default["default"].createElement(InputRow, null,
121
- React__default["default"].createElement(Select, { testid: "address-use", defaultValue: value === null || value === void 0 ? void 0 : value.use, onChange: setUse },
122
- React__default["default"].createElement("option", null),
123
- React__default["default"].createElement("option", null, "home"),
124
- React__default["default"].createElement("option", null, "mobile"),
125
- React__default["default"].createElement("option", null, "old"),
126
- React__default["default"].createElement("option", null, "temp"),
127
- React__default["default"].createElement("option", null, "work")),
128
- React__default["default"].createElement(Select, { testid: "address-type", defaultValue: value === null || value === void 0 ? void 0 : value.type, onChange: setType },
129
- React__default["default"].createElement("option", null),
130
- React__default["default"].createElement("option", null, "postal"),
131
- React__default["default"].createElement("option", null, "physical"),
132
- React__default["default"].createElement("option", null, "both")),
133
- React__default["default"].createElement(Input, { placeholder: "Line 1", defaultValue: getLine(value, 0), onChange: setLine1 }),
134
- React__default["default"].createElement(Input, { placeholder: "Line 2", defaultValue: getLine(value, 1), onChange: setLine2 }),
135
- React__default["default"].createElement(Input, { placeholder: "City", defaultValue: value.city, onChange: setCity }),
136
- React__default["default"].createElement(Input, { placeholder: "State", defaultValue: value.state, onChange: setState }),
137
- React__default["default"].createElement(Input, { placeholder: "Postal Code", defaultValue: value.postalCode, onChange: setPostalCode })));
61
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
62
+ React__default["default"].createElement(core$1.NativeSelect, { "data-testid": "address-use", defaultValue: value === null || value === void 0 ? void 0 : value.use, onChange: (e) => setUse(e.currentTarget.value), data: ['', 'home', 'work', 'temp', 'old', 'billing'] }),
63
+ React__default["default"].createElement(core$1.NativeSelect, { "data-testid": "address-type", defaultValue: value === null || value === void 0 ? void 0 : value.type, onChange: (e) => setType(e.currentTarget.value), data: ['', 'postal', 'physical', 'both'] }),
64
+ React__default["default"].createElement(core$1.TextInput, { placeholder: "Line 1", defaultValue: getLine(value, 0), onChange: (e) => setLine1(e.currentTarget.value) }),
65
+ React__default["default"].createElement(core$1.TextInput, { placeholder: "Line 2", defaultValue: getLine(value, 1), onChange: (e) => setLine2(e.currentTarget.value) }),
66
+ React__default["default"].createElement(core$1.TextInput, { placeholder: "City", defaultValue: value.city, onChange: (e) => setCity(e.currentTarget.value) }),
67
+ React__default["default"].createElement(core$1.TextInput, { placeholder: "State", defaultValue: value.state, onChange: (e) => setState(e.currentTarget.value) }),
68
+ React__default["default"].createElement(core$1.TextInput, { placeholder: "Postal Code", defaultValue: value.postalCode, onChange: (e) => setPostalCode(e.currentTarget.value) })));
138
69
  }
139
70
 
140
71
  function AttachmentDisplay(props) {
@@ -159,15 +90,6 @@
159
90
  React__default["default"].createElement(AttachmentDisplay, { value: v, maxWidth: props.maxWidth }))))));
160
91
  }
161
92
 
162
- function Button(props) {
163
- const className = 'medplum-button' +
164
- (props.primary || props.type === 'submit' ? ' medplum-button-primary' : '') +
165
- (props.danger ? ' medplum-button-danger' : '') +
166
- (props.borderless ? ' medplum-button-borderless' : '') +
167
- (props.size ? ' medplum-button-' + props.size : '');
168
- return (React__default["default"].createElement("button", { type: props.type || 'button', className: className, style: props.style, onClick: props.onClick, "aria-label": props.label, "data-testid": props.testid }, props.children));
169
- }
170
-
171
93
  const reactContext = React.createContext(undefined);
172
94
  /**
173
95
  * The MedplumProvider component provides Medplum context state.
@@ -246,9 +168,14 @@
246
168
  return el instanceof HTMLInputElement && el.type === 'checkbox';
247
169
  }
248
170
 
249
- function UploadButton(props) {
171
+ function AttachmentButton(props) {
250
172
  const medplum = useMedplum();
251
173
  const fileInputRef = React.useRef(null);
174
+ function onClick(e) {
175
+ var _a;
176
+ killEvent(e);
177
+ (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
178
+ }
252
179
  function onFileChange(e) {
253
180
  killEvent(e);
254
181
  const files = e.target.files;
@@ -287,11 +214,7 @@
287
214
  }
288
215
  return (React__default["default"].createElement(React__default["default"].Fragment, null,
289
216
  React__default["default"].createElement("input", { type: "file", "data-testid": "upload-file-input", style: { display: 'none' }, ref: fileInputRef, onChange: (e) => onFileChange(e) }),
290
- React__default["default"].createElement(Button, { testid: "upload-button", onClick: (e) => {
291
- var _a;
292
- killEvent(e);
293
- (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
294
- } }, props.children || 'Upload...')));
217
+ props.children({ onClick })));
295
218
  }
296
219
 
297
220
  function AttachmentArrayInput(props) {
@@ -307,25 +230,27 @@
307
230
  }
308
231
  return (React__default["default"].createElement("table", { style: { width: '100%' } },
309
232
  React__default["default"].createElement("colgroup", null,
310
- React__default["default"].createElement("col", { width: "90%" }),
311
- React__default["default"].createElement("col", { width: "10%" })),
233
+ React__default["default"].createElement("col", { width: "97%" }),
234
+ React__default["default"].createElement("col", { width: "3%" })),
312
235
  React__default["default"].createElement("tbody", null,
313
236
  values.map((v, index) => (React__default["default"].createElement("tr", { key: `${index}-${values.length}` },
314
237
  React__default["default"].createElement("td", null,
315
238
  React__default["default"].createElement(AttachmentDisplay, { value: v, maxWidth: 200 })),
316
239
  React__default["default"].createElement("td", { className: "medplum-right" },
317
- React__default["default"].createElement(Button, { onClick: (e) => {
240
+ React__default["default"].createElement(core$1.ActionIcon, { title: "Remove", size: "sm", onClick: (e) => {
318
241
  killEvent(e);
319
242
  const copy = values.slice();
320
243
  copy.splice(index, 1);
321
244
  setValuesWrapper(copy);
322
- } }, "Remove"))))),
245
+ } },
246
+ React__default["default"].createElement(icons.IconCircleMinus, null)))))),
323
247
  React__default["default"].createElement("tr", null,
324
248
  React__default["default"].createElement("td", null),
325
249
  React__default["default"].createElement("td", { className: "medplum-right" },
326
- React__default["default"].createElement(UploadButton, { onUpload: (attachment) => {
250
+ React__default["default"].createElement(AttachmentButton, { onUpload: (attachment) => {
327
251
  setValuesWrapper([...valuesRef.current, attachment]);
328
- } }))))));
252
+ } }, (props) => (React__default["default"].createElement(core$1.ActionIcon, Object.assign({}, props, { title: "Add", size: "sm", color: "green" }),
253
+ React__default["default"].createElement(icons.IconCloudUpload, { size: 16 })))))))));
329
254
  }
330
255
 
331
256
  function AttachmentInput(props) {
@@ -339,12 +264,12 @@
339
264
  if (value) {
340
265
  return (React__default["default"].createElement(React__default["default"].Fragment, null,
341
266
  React__default["default"].createElement(AttachmentDisplay, { value: value, maxWidth: 200 }),
342
- React__default["default"].createElement(Button, { onClick: (e) => {
267
+ React__default["default"].createElement(core$1.Button, { onClick: (e) => {
343
268
  killEvent(e);
344
269
  setValueWrapper(undefined);
345
270
  } }, "Remove")));
346
271
  }
347
- return React__default["default"].createElement(UploadButton, { onUpload: setValueWrapper });
272
+ return (React__default["default"].createElement(AttachmentButton, { onUpload: setValueWrapper }, (props) => React__default["default"].createElement(core$1.Button, Object.assign({}, props), "Upload...")));
348
273
  }
349
274
 
350
275
  function Document(props) {
@@ -367,6 +292,18 @@
367
292
  PERFORMANCE OF THIS SOFTWARE.
368
293
  ***************************************************************************** */
369
294
 
295
+ function __rest(s, e) {
296
+ var t = {};
297
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
298
+ t[p] = s[p];
299
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
300
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
301
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
302
+ t[p[i]] = s[p[i]];
303
+ }
304
+ return t;
305
+ }
306
+
370
307
  function __awaiter(thisArg, _arguments, P, generator) {
371
308
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
372
309
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -434,27 +371,41 @@
434
371
  } }, props.children));
435
372
  }
436
373
 
437
- function FormSection(props) {
438
- const issues = getIssuesForExpression(props.outcome, props.htmlFor);
439
- const invalid = issues && issues.length > 0;
440
- return (React__default["default"].createElement("fieldset", { className: "medplum-form-section" },
441
- props.title && React__default["default"].createElement("label", { htmlFor: props.htmlFor }, props.title),
442
- props.description && React__default["default"].createElement("p", null, props.description),
443
- props.children,
444
- invalid && (React__default["default"].createElement("div", { id: props.htmlFor + '-errors', className: "medplum-input-error" }, issues === null || issues === void 0 ? void 0 : issues.map((issue) => {
445
- var _a, _b;
446
- return (React__default["default"].createElement("div", { "data-testid": "text-field-error", key: (_a = issue.details) === null || _a === void 0 ? void 0 : _a.text }, (_b = issue.details) === null || _b === void 0 ? void 0 : _b.text));
447
- })))));
448
- }
449
-
450
374
  function Logo(props) {
451
375
  return (React__default["default"].createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 491 491", style: { width: props.size, height: props.size } },
452
376
  React__default["default"].createElement("title", null, "Medplum Logo"),
453
377
  React__default["default"].createElement("path", { fill: props.fill || '#ad7136', d: "M282 67c6-16 16-29 29-40L289 0c-22 17-37 41-43 68l17 23 19-24z" }),
454
- React__default["default"].createElement("path", { fill: props.fill || '#654b87', d: "M311 63c-17 0-33 4-48 11-16-7-32-11-49-11-87 0-158 96-158 214s71 214 158 214c17 0 33-4 49-11 15 7 31 11 48 11 87 0 158-96 158-214S398 63 311 63z" }),
455
- React__default["default"].createElement("path", { fill: props.fill || '#463068', d: "M231 489l-17 2c-87 0-158-96-158-214S127 63 214 63l17 1c-39 12-70 102-70 213s31 201 70 212z" }),
456
- React__default["default"].createElement("path", { fill: props.fill || '#70d65b', d: "M207 220a176 176 0 01-177 43A176 176 0 01251 43l1 5c17 59 2 125-45 172z" }),
457
- React__default["default"].createElement("path", { fill: props.fill || '#58b741', d: "M252 48A421 421 0 0057 270l-27-7A176 176 0 01251 43l1 5z" })));
378
+ React__default["default"].createElement("path", { fill: props.fill || '#946af9', d: "M311 63c-17 0-33 4-48 11-16-7-32-11-49-11-87 0-158 96-158 214s71 214 158 214c17 0 33-4 49-11 15 7 31 11 48 11 87 0 158-96 158-214S398 63 311 63z" }),
379
+ React__default["default"].createElement("path", { fill: props.fill || '#7857c5', d: "M231 489l-17 2c-87 0-158-96-158-214S127 63 214 63l17 1c-39 12-70 102-70 213s31 201 70 212z" }),
380
+ React__default["default"].createElement("path", { fill: props.fill || '#40bc26', d: "M207 220a176 176 0 01-177 43A176 176 0 01251 43l1 5c17 59 2 125-45 172z" }),
381
+ React__default["default"].createElement("path", { fill: props.fill || '#33961e', d: "M252 48A421 421 0 0057 270l-27-7A176 176 0 01251 43l1 5z" })));
382
+ }
383
+
384
+ function getErrorsForInput(outcome, expression) {
385
+ var _a, _b, _c;
386
+ return (_c = (_b = (_a = outcome === null || outcome === void 0 ? void 0 : outcome.issue) === null || _a === void 0 ? void 0 : _a.filter((issue) => { var _a; return isExpressionMatch((_a = issue.expression) === null || _a === void 0 ? void 0 : _a[0], expression); })) === null || _b === void 0 ? void 0 : _b.map((issue) => { var _a; return (_a = issue.details) === null || _a === void 0 ? void 0 : _a.text; })) === null || _c === void 0 ? void 0 : _c.join('\n');
387
+ }
388
+ function getIssuesForExpression(outcome, expression) {
389
+ var _a;
390
+ return (_a = outcome === null || outcome === void 0 ? void 0 : outcome.issue) === null || _a === void 0 ? void 0 : _a.filter((issue) => { var _a; return isExpressionMatch((_a = issue.expression) === null || _a === void 0 ? void 0 : _a[0], expression); });
391
+ }
392
+ function isExpressionMatch(expr1, expr2) {
393
+ // Expression can be either "fieldName" or "resourceType.fieldName"
394
+ if (expr1 === expr2) {
395
+ return true;
396
+ }
397
+ if (!expr1 || !expr2) {
398
+ return false;
399
+ }
400
+ const dot1 = expr1.indexOf('.');
401
+ if (dot1 >= 0 && expr1.substring(dot1 + 1) === expr2) {
402
+ return true;
403
+ }
404
+ const dot2 = expr2.indexOf('.');
405
+ if (dot2 >= 0 && expr2.substring(dot2 + 1) === expr1) {
406
+ return true;
407
+ }
408
+ return false;
458
409
  }
459
410
 
460
411
  function NewProjectForm(props) {
@@ -474,18 +425,16 @@
474
425
  React__default["default"].createElement("div", { className: "medplum-center" },
475
426
  React__default["default"].createElement(Logo, { size: 32 }),
476
427
  React__default["default"].createElement("h1", null, "Create project")),
477
- React__default["default"].createElement(FormSection, { title: "Project Name", htmlFor: "projectName", outcome: outcome },
478
- React__default["default"].createElement(Input, { name: "projectName", type: "text", testid: "projectName", placeholder: "My Project", required: true, outcome: outcome })),
479
- React__default["default"].createElement("p", { style: { fontSize: '12px', color: '#888' } },
480
- "By clicking submit you agree to the Medplum ",
481
- React__default["default"].createElement("a", { href: "https://www.medplum.com/privacy" }, "Privacy\u00A0Policy"),
482
- ' and ',
483
- React__default["default"].createElement("a", { href: "https://www.medplum.com/terms" }, "Terms\u00A0of\u00A0Service"),
484
- "."),
485
- React__default["default"].createElement("div", { className: "medplum-signin-buttons" },
486
- React__default["default"].createElement("div", null),
487
- React__default["default"].createElement("div", null,
488
- React__default["default"].createElement(Button, { type: "submit", testid: "submit" }, "Create project")))));
428
+ React__default["default"].createElement(core$1.Stack, { spacing: "xl" },
429
+ React__default["default"].createElement(core$1.TextInput, { name: "projectName", label: "Project Name", placeholder: "My Project", required: true, autoFocus: true, error: getErrorsForInput(outcome, 'firstName') }),
430
+ React__default["default"].createElement(core$1.Text, { color: "dimmed", size: "xs" },
431
+ "By clicking submit you agree to the Medplum ",
432
+ React__default["default"].createElement("a", { href: "https://www.medplum.com/privacy" }, "Privacy\u00A0Policy"),
433
+ ' and ',
434
+ React__default["default"].createElement("a", { href: "https://www.medplum.com/terms" }, "Terms\u00A0of\u00A0Service"),
435
+ ".")),
436
+ React__default["default"].createElement(core$1.Group, { position: "right", mt: "xl", noWrap: true },
437
+ React__default["default"].createElement(core$1.Button, { type: "submit" }, "Create project"))));
489
438
  }
490
439
 
491
440
  /**
@@ -602,7 +551,7 @@
602
551
  return (React__default["default"].createElement("div", { "data-testid": "text-field-error", key: (_a = issue.details) === null || _a === void 0 ? void 0 : _a.text }, (_b = issue.details) === null || _b === void 0 ? void 0 : _b.text));
603
552
  }))),
604
553
  googleClientId && (React__default["default"].createElement(React__default["default"].Fragment, null,
605
- React__default["default"].createElement("div", { className: "medplum-signin-google-container" },
554
+ React__default["default"].createElement(core$1.Group, { position: "center", p: "xl", style: { height: 70 } },
606
555
  React__default["default"].createElement(GoogleButton, { googleClientId: googleClientId, handleGoogleCredential: (response) => __awaiter(this, void 0, void 0, function* () {
607
556
  try {
608
557
  props.handleAuthResponse(yield medplum.startGoogleLogin({
@@ -615,34 +564,28 @@
615
564
  setOutcome(err);
616
565
  }
617
566
  }) })),
618
- React__default["default"].createElement("div", { className: "medplum-signin-separator" }, "or"))),
619
- React__default["default"].createElement(FormSection, { title: "First Name", htmlFor: "firstName", outcome: outcome },
620
- React__default["default"].createElement(Input, { name: "firstName", type: "text", testid: "firstName", placeholder: "First name", required: true, autoFocus: true, outcome: outcome })),
621
- React__default["default"].createElement(FormSection, { title: "Last Name", htmlFor: "lastName", outcome: outcome },
622
- React__default["default"].createElement(Input, { name: "lastName", type: "text", testid: "lastName", placeholder: "Last name", required: true, outcome: outcome })),
623
- React__default["default"].createElement(FormSection, { title: "Email", htmlFor: "email", outcome: outcome },
624
- React__default["default"].createElement(Input, { name: "email", type: "email", testid: "email", placeholder: "name@domain.com", required: true, outcome: outcome })),
625
- React__default["default"].createElement(FormSection, { title: "Password", htmlFor: "password", outcome: outcome },
626
- React__default["default"].createElement(Input, { name: "password", type: "password", testid: "password", autoComplete: "off", required: true, outcome: outcome })),
627
- React__default["default"].createElement("p", { style: { fontSize: '12px', color: '#888' } },
628
- "By clicking submit you agree to the Medplum ",
629
- React__default["default"].createElement("a", { href: "https://www.medplum.com/privacy" }, "Privacy\u00A0Policy"),
630
- ' and ',
631
- React__default["default"].createElement("a", { href: "https://www.medplum.com/terms" }, "Terms\u00A0of\u00A0Service"),
632
- "."),
633
- React__default["default"].createElement("p", { style: { fontSize: '12px', color: '#888' } },
634
- "This site is protected by reCAPTCHA and the Google",
635
- ' ',
636
- React__default["default"].createElement("a", { href: "https://policies.google.com/privacy" }, "Privacy\u00A0Policy"),
637
- ' and ',
638
- React__default["default"].createElement("a", { href: "https://policies.google.com/terms" }, "Terms\u00A0of\u00A0Service"),
639
- " apply."),
640
- React__default["default"].createElement("div", { className: "medplum-signin-buttons" },
641
- React__default["default"].createElement("div", null,
642
- React__default["default"].createElement("input", { type: "checkbox", id: "remember", name: "remember", value: "true" }),
643
- React__default["default"].createElement("label", { htmlFor: "remember" }, "Remember me")),
644
- React__default["default"].createElement("div", null,
645
- React__default["default"].createElement(Button, { type: "submit", testid: "submit" }, "Create account")))));
567
+ React__default["default"].createElement(core$1.Divider, { label: "or", labelPosition: "center", my: "lg" }))),
568
+ React__default["default"].createElement(core$1.Stack, { spacing: "xl" },
569
+ React__default["default"].createElement(core$1.TextInput, { name: "firstName", type: "text", label: "First name", placeholder: "First name", required: true, autoFocus: true, error: getErrorsForInput(outcome, 'firstName') }),
570
+ React__default["default"].createElement(core$1.TextInput, { name: "lastName", type: "text", label: "Last name", placeholder: "Last name", required: true, error: getErrorsForInput(outcome, 'lastName') }),
571
+ React__default["default"].createElement(core$1.TextInput, { name: "email", type: "email", label: "Email", placeholder: "name@domain.com", required: true, error: getErrorsForInput(outcome, 'email') }),
572
+ React__default["default"].createElement(core$1.PasswordInput, { name: "password", label: "Password", autoComplete: "off", required: true, error: getErrorsForInput(outcome, 'password') }),
573
+ React__default["default"].createElement(core$1.Text, { color: "dimmed", size: "xs" },
574
+ "By clicking submit you agree to the Medplum ",
575
+ React__default["default"].createElement("a", { href: "https://www.medplum.com/privacy" }, "Privacy\u00A0Policy"),
576
+ ' and ',
577
+ React__default["default"].createElement("a", { href: "https://www.medplum.com/terms" }, "Terms\u00A0of\u00A0Service"),
578
+ "."),
579
+ React__default["default"].createElement(core$1.Text, { color: "dimmed", size: "xs" },
580
+ "This site is protected by reCAPTCHA and the Google",
581
+ ' ',
582
+ React__default["default"].createElement("a", { href: "https://policies.google.com/privacy" }, "Privacy\u00A0Policy"),
583
+ ' and ',
584
+ React__default["default"].createElement("a", { href: "https://policies.google.com/terms" }, "Terms\u00A0of\u00A0Service"),
585
+ " apply.")),
586
+ React__default["default"].createElement(core$1.Group, { position: "apart", mt: "xl", noWrap: true },
587
+ React__default["default"].createElement(core$1.Checkbox, { name: "remember", label: "Remember me", size: "xs" }),
588
+ React__default["default"].createElement(core$1.Button, { type: "submit" }, "Create account"))));
646
589
  }
647
590
 
648
591
  function RegisterForm(props) {
@@ -676,49 +619,6 @@
676
619
  login && type === 'project' && React__default["default"].createElement(NewProjectForm, { login: login, handleAuthResponse: handleAuthResponse })));
677
620
  }
678
621
 
679
- function MedplumLink(props) {
680
- const navigate = reactRouterDom.useNavigate();
681
- let href = getHref(props.to);
682
- if (props.suffix) {
683
- href += '/' + props.suffix;
684
- }
685
- return (React__default["default"].createElement("a", { href: href, id: props.id, "aria-label": props.label, "data-testid": props.testid || 'link', className: props.className, onClick: (e) => {
686
- killEvent(e);
687
- if (props.onClick) {
688
- props.onClick();
689
- }
690
- else if (props.to) {
691
- navigate(href);
692
- }
693
- } }, props.children));
694
- }
695
- function getHref(to) {
696
- if (to) {
697
- if (typeof to === 'string') {
698
- return getStringHref(to);
699
- }
700
- else if ('resourceType' in to) {
701
- return getResourceHref(to);
702
- }
703
- else if ('reference' in to) {
704
- return getReferenceHref(to);
705
- }
706
- }
707
- return '#';
708
- }
709
- function getStringHref(to) {
710
- if (to.startsWith('http://') || to.startsWith('https://') || to.startsWith('/')) {
711
- return to;
712
- }
713
- return '/' + to;
714
- }
715
- function getResourceHref(to) {
716
- return `/${to.resourceType}/${to.id}`;
717
- }
718
- function getReferenceHref(to) {
719
- return `/${to.reference}`;
720
- }
721
-
722
622
  function AuthenticationForm(props) {
723
623
  const medplum = useMedplum();
724
624
  const googleClientId = getGoogleClientId(props.googleClientId);
@@ -753,7 +653,7 @@
753
653
  return (React__default["default"].createElement("div", { "data-testid": "text-field-error", key: (_a = issue.details) === null || _a === void 0 ? void 0 : _a.text }, (_b = issue.details) === null || _b === void 0 ? void 0 : _b.text));
754
654
  }))),
755
655
  googleClientId && (React__default["default"].createElement(React__default["default"].Fragment, null,
756
- React__default["default"].createElement("div", { className: "medplum-signin-google-container" },
656
+ React__default["default"].createElement(core$1.Group, { position: "center", p: "xl", style: { height: 70 } },
757
657
  React__default["default"].createElement(GoogleButton, { googleClientId: googleClientId, handleGoogleCredential: (response) => {
758
658
  startPkce()
759
659
  .then(() => medplum.startGoogleLogin({
@@ -769,108 +669,26 @@
769
669
  .then(props.handleAuthResponse)
770
670
  .catch(setOutcome);
771
671
  } })),
772
- React__default["default"].createElement("div", { className: "medplum-signin-separator" }, "or"))),
773
- React__default["default"].createElement(FormSection, { title: "Email", htmlFor: "email", outcome: outcome },
774
- React__default["default"].createElement(Input, { name: "email", type: "email", testid: "email", required: true, autoFocus: true, outcome: outcome })),
775
- React__default["default"].createElement(FormSection, { title: "Password", htmlFor: "password", outcome: outcome },
776
- React__default["default"].createElement(Input, { name: "password", type: "password", testid: "password", autoComplete: "off", required: true, outcome: outcome })),
777
- React__default["default"].createElement("div", { className: "medplum-signin-buttons" },
778
- (props.onForgotPassword || props.onRegister) && (React__default["default"].createElement("div", null,
779
- props.onForgotPassword && (React__default["default"].createElement(MedplumLink, { testid: "forgotpassword", onClick: props.onForgotPassword }, "Forgot password")),
780
- props.onRegister && (React__default["default"].createElement(MedplumLink, { testid: "register", onClick: props.onRegister }, "Register")))),
781
- React__default["default"].createElement("div", null,
782
- React__default["default"].createElement("input", { type: "checkbox", id: "remember", name: "remember", value: "true" }),
783
- React__default["default"].createElement("label", { htmlFor: "remember" }, "Remember me")),
784
- React__default["default"].createElement("div", null,
785
- React__default["default"].createElement(Button, { type: "submit", testid: "submit" }, "Sign in")))));
786
- }
787
-
788
- const system = {
789
- resourceType: 'Device',
790
- id: 'system',
791
- deviceName: [
792
- {
793
- name: 'System',
794
- },
795
- ],
796
- };
797
- /**
798
- * React Hook to use a FHIR reference.
799
- * Handles the complexity of resolving references and caching resources.
800
- * @param value The resource or reference to resource.
801
- * @returns The resolved resource.
802
- */
803
- function useResource(value) {
804
- const medplum = useMedplum();
805
- const [resource, setResource] = React.useState(getInitialResource(medplum, value));
806
- React.useEffect(() => {
807
- let subscribed = true;
808
- if (!resource && value && 'reference' in value && value.reference) {
809
- medplum
810
- .readReference(value)
811
- .then((r) => {
812
- if (subscribed) {
813
- setResource(r);
814
- }
815
- })
816
- .catch(() => setResource(undefined));
817
- }
818
- return (() => (subscribed = false));
819
- }, [medplum, resource, value]);
820
- return resource;
821
- }
822
- /**
823
- * Returns the initial resource value based on the input value.
824
- * If the input value is a resource, returns the resource.
825
- * If the input value is a reference to system, returns the system resource.
826
- * If the input value is a reference to a resource available in the cache, returns the resource.
827
- * Otherwise, returns undefined.
828
- * @param medplum The medplum client.
829
- * @param value The resource or reference to resource.
830
- * @returns An initial resource if available; undefined otherwise.
831
- */
832
- function getInitialResource(medplum, value) {
833
- if (!value) {
834
- return undefined;
835
- }
836
- if ('resourceType' in value) {
837
- return value;
838
- }
839
- if ('reference' in value) {
840
- if (value.reference === 'system') {
841
- return system;
842
- }
843
- return medplum.getCachedReference(value);
844
- }
845
- return undefined;
846
- }
847
-
848
- function Avatar(props) {
849
- var _a, _b;
850
- const resource = useResource(props.value);
851
- const className = props.size ? 'medplum-avatar ' + props.size : 'medplum-avatar';
852
- const text = resource ? core.getDisplayString(resource) : (_a = props.alt) !== null && _a !== void 0 ? _a : '';
853
- const initials = text && getInitials(text);
854
- const imageUrl = (_b = (resource && core.getImageSrc(resource))) !== null && _b !== void 0 ? _b : props.src;
855
- const innerContent = imageUrl ? React__default["default"].createElement("img", { src: imageUrl, alt: text }) : initials;
856
- return (React__default["default"].createElement("div", { className: className, style: { backgroundColor: props.color }, "data-testid": "avatar" }, props.link && resource ? React__default["default"].createElement(MedplumLink, { to: resource }, innerContent) : innerContent));
857
- }
858
- function getInitials(text) {
859
- return text
860
- .split(' ')
861
- .map((n) => n[0])
862
- .join('');
672
+ React__default["default"].createElement(core$1.Divider, { label: "or", labelPosition: "center", my: "lg" }))),
673
+ React__default["default"].createElement(core$1.Stack, { spacing: "xl" },
674
+ React__default["default"].createElement(core$1.TextInput, { name: "email", type: "email", label: "Email", placeholder: "name@domain.com", required: true, autoFocus: true, error: getErrorsForInput(outcome, 'email') }),
675
+ React__default["default"].createElement(core$1.PasswordInput, { name: "password", type: "password", label: "Password", autoComplete: "off", required: true, error: getErrorsForInput(outcome, 'password') })),
676
+ React__default["default"].createElement(core$1.Group, { position: "apart", mt: "xl", noWrap: true },
677
+ props.onForgotPassword && (React__default["default"].createElement(core$1.Anchor, { component: "button", type: "button", color: "dimmed", onClick: props.onForgotPassword, size: "xs" }, "Forgot password")),
678
+ props.onRegister && (React__default["default"].createElement(core$1.Anchor, { component: "button", type: "button", color: "dimmed", onClick: props.onRegister, size: "xs" }, "Register")),
679
+ React__default["default"].createElement(core$1.Checkbox, { name: "remember", label: "Remember me", size: "xs" }),
680
+ React__default["default"].createElement(core$1.Button, { type: "submit" }, "Sign in"))));
863
681
  }
864
682
 
865
683
  function ChooseProfileForm(props) {
866
684
  const medplum = useMedplum();
867
- return (React__default["default"].createElement("div", null,
685
+ return (React__default["default"].createElement(core$1.Stack, null,
868
686
  React__default["default"].createElement("div", { className: "medplum-center" },
869
687
  React__default["default"].createElement(Logo, { size: 32 }),
870
- React__default["default"].createElement("h1", null, "Choose profile")),
688
+ React__default["default"].createElement(core$1.Text, { size: "lg", weight: 500 }, "Choose profile")),
871
689
  props.memberships.map((membership) => {
872
- var _a, _b, _c;
873
- return (React__default["default"].createElement("div", { className: "medplum-nav-menu-profile", key: membership.id, onClick: () => {
690
+ var _a, _b;
691
+ return (React__default["default"].createElement(core$1.UnstyledButton, { key: membership.id, onClick: () => {
874
692
  medplum
875
693
  .post('auth/profile', {
876
694
  login: props.login,
@@ -879,11 +697,11 @@
879
697
  .then(props.handleAuthResponse)
880
698
  .catch(console.log);
881
699
  } },
882
- React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-icon" },
883
- React__default["default"].createElement(Avatar, { alt: (_a = membership.profile) === null || _a === void 0 ? void 0 : _a.display })),
884
- React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-label" }, (_b = membership.profile) === null || _b === void 0 ? void 0 :
885
- _b.display,
886
- React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-help-text" }, (_c = membership.project) === null || _c === void 0 ? void 0 : _c.display))));
700
+ React__default["default"].createElement(core$1.Group, null,
701
+ React__default["default"].createElement(core$1.Avatar, { radius: "xl" }),
702
+ React__default["default"].createElement("div", { style: { flex: 1 } },
703
+ React__default["default"].createElement(core$1.Text, { size: "sm", weight: 500 }, (_a = membership.profile) === null || _a === void 0 ? void 0 : _a.display),
704
+ React__default["default"].createElement(core$1.Text, { color: "dimmed", size: "xs" }, (_b = membership.project) === null || _b === void 0 ? void 0 : _b.display)))));
887
705
  })));
888
706
  }
889
707
 
@@ -930,282 +748,6 @@
930
748
  })()));
931
749
  }
932
750
 
933
- function Autocomplete(props) {
934
- var _a, _b;
935
- const inputRef = React.useRef(null);
936
- const [focused, setFocused] = React.useState(false);
937
- const [lastValue, setLastValue] = React.useState(undefined);
938
- const [timer, setTimer] = React.useState();
939
- const [dropDownVisible, setDropDownVisible] = React.useState(false);
940
- const [values, setValues] = React.useState((_a = props.defaultValue) !== null && _a !== void 0 ? _a : []);
941
- const [options, setOptions] = React.useState([]);
942
- const [selectedIndex, setSelectedIndex] = React.useState(-1);
943
- const [abortController, setAbortController] = React.useState();
944
- const [autoSubmit, setAutoSubmit] = React.useState();
945
- const lastValueRef = React.useRef();
946
- lastValueRef.current = lastValue;
947
- const timerRef = React.useRef();
948
- timerRef.current = timer;
949
- const abortControllerRef = React.useRef();
950
- abortControllerRef.current = abortController;
951
- const autoSubmitRef = React.useRef();
952
- autoSubmitRef.current = autoSubmit;
953
- React.useEffect(() => {
954
- return () => {
955
- if (abortControllerRef.current) {
956
- abortControllerRef.current.abort();
957
- }
958
- };
959
- }, []);
960
- React.useEffect(() => {
961
- var _a;
962
- setValues((_a = props.defaultValue) !== null && _a !== void 0 ? _a : []);
963
- }, [props.defaultValue]);
964
- function setValuesWrapper(newValues) {
965
- setValues(newValues);
966
- if (props.onChange) {
967
- props.onChange(newValues);
968
- }
969
- }
970
- /**
971
- * Adds an option to the list of selected options.
972
- * @param option The option.
973
- */
974
- function addOption(option) {
975
- const inputElement = inputRef.current;
976
- inputElement.value = '';
977
- const newValues = props.multiple ? [...values, option] : [option];
978
- setFocused(true);
979
- setDropDownVisible(false);
980
- setLastValue('');
981
- setOptions([]);
982
- setSelectedIndex(-1);
983
- setValuesWrapper(newValues);
984
- }
985
- function handleClick() {
986
- var _a;
987
- (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
988
- }
989
- function handleFocus() {
990
- setFocused(true);
991
- if (props.loadOnFocus) {
992
- handleInput();
993
- }
994
- }
995
- function handleBlur() {
996
- tryAddOption();
997
- setFocused(false);
998
- dismissOnDelay();
999
- }
1000
- /**
1001
- * Handles an input event.
1002
- * Clears existing timers.
1003
- * Schedules a timer to execute the search after a short delay.
1004
- */
1005
- function handleInput() {
1006
- if (abortControllerRef.current) {
1007
- abortControllerRef.current.abort();
1008
- setAbortController(undefined);
1009
- }
1010
- if (timerRef.current !== undefined) {
1011
- window.clearTimeout(timerRef.current);
1012
- }
1013
- const newTimer = window.setTimeout(() => handleTimer(), 100);
1014
- setTimer(newTimer);
1015
- }
1016
- function handleKeyDown(e) {
1017
- switch (e.key) {
1018
- case 'Enter':
1019
- case 'Tab':
1020
- handleSelectKey(e);
1021
- break;
1022
- case 'ArrowUp':
1023
- moveSelection(-1);
1024
- killEvent(e);
1025
- break;
1026
- case 'ArrowDown':
1027
- moveSelection(1);
1028
- killEvent(e);
1029
- break;
1030
- case 'Backspace':
1031
- handleBackspaceKey(e);
1032
- break;
1033
- case ',':
1034
- case ';':
1035
- handleSeparatorKey(e);
1036
- }
1037
- }
1038
- /**
1039
- * Handles the "enter" or "tab" keys. The enter key logic is:
1040
- * Try to add an option with tryAddOption. On success, cancel event.
1041
- * Otherwise, let the browser handle the enter key normally.
1042
- *
1043
- * @param e The key down event.
1044
- */
1045
- function handleSelectKey(e) {
1046
- var _a;
1047
- if (!timerRef.current && !abortControllerRef.current && tryAddOption()) {
1048
- killEvent(e);
1049
- (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1050
- }
1051
- else {
1052
- // The user pressed enter, but we don't have results yet.
1053
- // We need to wait for the results to come in.
1054
- setAutoSubmit(true);
1055
- }
1056
- }
1057
- /**
1058
- * Handles the "backspace" key. The backspace key logic is:
1059
- * If the input is empty and there is at least one item, delete the last item.
1060
- * Otherwise, let the browser handle the backspace key normally.
1061
- *
1062
- * @param e The key down event.
1063
- */
1064
- function handleBackspaceKey(e) {
1065
- var _a;
1066
- if ((_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.value) {
1067
- // If there is still text in the input,
1068
- // then handle backspace as normal.
1069
- return;
1070
- }
1071
- if (values.length > 0) {
1072
- // If there are selected items,
1073
- // then delete the last item.
1074
- killEvent(e);
1075
- setValuesWrapper(values.slice(0, values.length - 1));
1076
- }
1077
- }
1078
- /**
1079
- * Handles a "separator" key (comma, semicolon, others?).
1080
- *
1081
- * The separator key logic is:
1082
- * If the drop down is visible and something is selected, choose that.
1083
- * If the drop down is visible but nothing is selected, choose the first.
1084
- * If there is content in the input, use that as a "gray" option.
1085
- * Otherwise, ignore.
1086
- *
1087
- * @param e The key down event.
1088
- */
1089
- function handleSeparatorKey(e) {
1090
- var _a;
1091
- tryAddOption();
1092
- killEvent(e);
1093
- (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1094
- }
1095
- /**
1096
- * Tries to capture the existing input as an option.
1097
- *
1098
- * @return True if captured an option; false otherwise.
1099
- */
1100
- function tryAddOption() {
1101
- var _a;
1102
- let option;
1103
- if (selectedIndex >= 0 && selectedIndex < options.length) {
1104
- // Currently highlighted row
1105
- option = options[selectedIndex];
1106
- }
1107
- else if (selectedIndex === -1 && options.length > 0) {
1108
- // Default to first row
1109
- option = options[0];
1110
- }
1111
- else if (props.buildUnstructured && ((_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.value)) {
1112
- // Build semi-structured item
1113
- option = props.buildUnstructured(inputRef.current.value);
1114
- }
1115
- if (!option) {
1116
- return false;
1117
- }
1118
- addOption(option);
1119
- return true;
1120
- }
1121
- /**
1122
- * Handles a timer tick event.
1123
- * If the contents of the input have changed, sends xhr to the server
1124
- * for updated contents.
1125
- */
1126
- function handleTimer() {
1127
- var _a, _b;
1128
- setTimer(undefined);
1129
- const value = ((_b = (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.trim()) || '';
1130
- if (value === lastValueRef.current) {
1131
- // Nothing has changed, move on
1132
- return;
1133
- }
1134
- setLastValue(value);
1135
- const newAbortController = new AbortController();
1136
- setAbortController(newAbortController);
1137
- props
1138
- .loadOptions(value, newAbortController.signal)
1139
- .then((newOptions) => {
1140
- if (!newAbortController.signal.aborted) {
1141
- setDropDownVisible(newOptions.length > 0);
1142
- setOptions(newOptions);
1143
- setAbortController(undefined);
1144
- if (autoSubmitRef.current) {
1145
- addOption(newOptions[0]);
1146
- setAutoSubmit(false);
1147
- }
1148
- }
1149
- })
1150
- .catch(console.log);
1151
- }
1152
- /**
1153
- * Moves the selected row.
1154
- * @param delta The amount to move the selection, up is negative.
1155
- */
1156
- function moveSelection(delta) {
1157
- let index = selectedIndex + delta;
1158
- if (index < 0) {
1159
- index = 0;
1160
- }
1161
- else if (index >= options.length) {
1162
- index = options.length - 1;
1163
- }
1164
- setSelectedIndex(index);
1165
- }
1166
- /**
1167
- * Handles a hover event.
1168
- * @param _e The mouse event.
1169
- * @param index The drop down option index.
1170
- */
1171
- function handleDropDownHover(_e, index) {
1172
- setSelectedIndex(index);
1173
- }
1174
- /**
1175
- * Handles a click event.
1176
- * @param e The mouse event.
1177
- * @param option The drop down option.
1178
- */
1179
- function handleDropDownClick(e, option) {
1180
- killEvent(e);
1181
- addOption(option);
1182
- }
1183
- /**
1184
- * Dismisses the drop down menu after a slight delay.
1185
- */
1186
- function dismissOnDelay() {
1187
- window.setTimeout(() => {
1188
- setDropDownVisible(false);
1189
- }, 200);
1190
- }
1191
- const baseClassName = (_b = props.className) !== null && _b !== void 0 ? _b : 'medplum-autocomplete-container';
1192
- return (React__default["default"].createElement("div", { "data-testid": "autocomplete", className: baseClassName + (focused ? ' focused' : ''), onClick: () => handleClick() },
1193
- React__default["default"].createElement("ul", { onClick: () => handleClick() },
1194
- values.map((value) => (React__default["default"].createElement("li", { key: props.getId(value), "data-testid": "selected", className: "medplum-autocomplete-item choice" }, props.getDisplay(value)))),
1195
- React__default["default"].createElement("li", { className: "medplum-autocomplete-item" },
1196
- React__default["default"].createElement("input", { type: "text", autoFocus: props.autofocus, placeholder: values.length === 0 ? props.placeholder : undefined, autoComplete: "off", autoCapitalize: "off", spellCheck: "true", onFocus: () => handleFocus(), onBlur: () => handleBlur(), onChange: () => handleInput(), onInput: () => handleInput(), onKeyDown: (e) => handleKeyDown(e), ref: inputRef, "data-testid": "input-element" }))),
1197
- dropDownVisible && (React__default["default"].createElement("div", { className: "medplum-autocomplete", "data-testid": "dropdown" },
1198
- options.map((option, index) => (React__default["default"].createElement("div", { key: props.getId(option), className: index === selectedIndex
1199
- ? 'medplum-autocomplete-row medplum-autocomplete-active'
1200
- : 'medplum-autocomplete-row', onMouseOver: (e) => handleDropDownHover(e, index), onClick: (e) => handleDropDownClick(e, option) },
1201
- props.getIcon && React__default["default"].createElement("div", { className: "medplum-autocomplete-icon" }, props.getIcon(option)),
1202
- React__default["default"].createElement("div", { className: "medplum-autocomplete-label" },
1203
- props.getDisplay(option),
1204
- props.getHelpText && React__default["default"].createElement("div", { className: "medplum-autocomplete-help-text" }, props.getHelpText(option)))))),
1205
- props.onCreateNew && (React__default["default"].createElement("div", { className: "medplum-autocomplete-row", onClick: props.onCreateNew },
1206
- React__default["default"].createElement("div", { className: "medplum-autocomplete-label" }, "Create new...")))))));
1207
- }
1208
-
1209
751
  function CheckboxFormSection(props) {
1210
752
  return (React__default["default"].createElement("div", { className: "medplum-checkbox-form-section" },
1211
753
  React__default["default"].createElement("div", { className: "medplum-checkbox-form-section-checkbox-container" }, props.children),
@@ -1224,6 +766,79 @@
1224
766
  'modifierExtension',
1225
767
  ];
1226
768
 
769
+ function FormSection(props) {
770
+ const issues = getIssuesForExpression(props.outcome, props.htmlFor);
771
+ const invalid = issues && issues.length > 0;
772
+ return (React__default["default"].createElement("fieldset", { className: "medplum-form-section" },
773
+ props.title && React__default["default"].createElement("label", { htmlFor: props.htmlFor }, props.title),
774
+ props.description && React__default["default"].createElement("p", null, props.description),
775
+ props.children,
776
+ invalid && (React__default["default"].createElement("div", { id: props.htmlFor + '-errors', className: "medplum-input-error" }, issues === null || issues === void 0 ? void 0 : issues.map((issue) => {
777
+ var _a, _b;
778
+ return (React__default["default"].createElement("div", { "data-testid": "text-field-error", key: (_a = issue.details) === null || _a === void 0 ? void 0 : _a.text }, (_b = issue.details) === null || _b === void 0 ? void 0 : _b.text));
779
+ })))));
780
+ }
781
+
782
+ const system = {
783
+ resourceType: 'Device',
784
+ id: 'system',
785
+ deviceName: [
786
+ {
787
+ name: 'System',
788
+ },
789
+ ],
790
+ };
791
+ /**
792
+ * React Hook to use a FHIR reference.
793
+ * Handles the complexity of resolving references and caching resources.
794
+ * @param value The resource or reference to resource.
795
+ * @returns The resolved resource.
796
+ */
797
+ function useResource(value) {
798
+ const medplum = useMedplum();
799
+ const [resource, setResource] = React.useState(getInitialResource(medplum, value));
800
+ React.useEffect(() => {
801
+ let subscribed = true;
802
+ if (!resource && value && 'reference' in value && value.reference) {
803
+ medplum
804
+ .readReference(value)
805
+ .then((r) => {
806
+ if (subscribed) {
807
+ setResource(r);
808
+ }
809
+ })
810
+ .catch(() => setResource(undefined));
811
+ }
812
+ return (() => (subscribed = false));
813
+ }, [medplum, resource, value]);
814
+ return resource;
815
+ }
816
+ /**
817
+ * Returns the initial resource value based on the input value.
818
+ * If the input value is a resource, returns the resource.
819
+ * If the input value is a reference to system, returns the system resource.
820
+ * If the input value is a reference to a resource available in the cache, returns the resource.
821
+ * Otherwise, returns undefined.
822
+ * @param medplum The medplum client.
823
+ * @param value The resource or reference to resource.
824
+ * @returns An initial resource if available; undefined otherwise.
825
+ */
826
+ function getInitialResource(medplum, value) {
827
+ if (!value) {
828
+ return undefined;
829
+ }
830
+ if ('resourceType' in value) {
831
+ return value;
832
+ }
833
+ if ('reference' in value) {
834
+ if (value.reference === 'system') {
835
+ return system;
836
+ }
837
+ return medplum.getCachedReference(value);
838
+ }
839
+ return undefined;
840
+ }
841
+
1227
842
  function ResourceForm(props) {
1228
843
  const medplum = useMedplum();
1229
844
  const defaultValue = useResource(props.defaultValue);
@@ -1244,15 +859,16 @@
1244
859
  props.onSubmit(value);
1245
860
  }
1246
861
  } },
1247
- React__default["default"].createElement(FormSection, { title: "Resource Type" },
1248
- React__default["default"].createElement(Input, { name: "resourceType", defaultValue: value.resourceType, disabled: true })),
1249
- React__default["default"].createElement(FormSection, { title: "ID" },
1250
- React__default["default"].createElement(Input, { name: "id", defaultValue: value.id, disabled: true })),
862
+ React__default["default"].createElement(FormSection, { title: "Resource Type", htmlFor: "resourceType", outcome: props.outcome },
863
+ React__default["default"].createElement(core$1.TextInput, { name: "resourceType", defaultValue: value.resourceType, disabled: true })),
864
+ React__default["default"].createElement(FormSection, { title: "ID", htmlFor: "id", outcome: props.outcome },
865
+ React__default["default"].createElement(core$1.TextInput, { name: "id", defaultValue: value.id, disabled: true })),
1251
866
  React__default["default"].createElement(BackboneElementInput, { typeName: value.resourceType, defaultValue: value, outcome: props.outcome, onChange: setValue }),
1252
- React__default["default"].createElement(Button, { type: "submit", size: "large" }, "OK"),
1253
- props.onDelete && (React__default["default"].createElement(Button, { type: "button", size: "large", onClick: () => {
1254
- props.onDelete(value);
1255
- } }, "Delete"))));
867
+ React__default["default"].createElement(core$1.Group, null,
868
+ React__default["default"].createElement(core$1.Button, { type: "submit" }, "OK"),
869
+ props.onDelete && (React__default["default"].createElement(core$1.Button, { variant: "outline", color: "red", type: "button", onClick: () => {
870
+ props.onDelete(value);
871
+ } }, "Delete")))));
1256
872
  }
1257
873
  function setPropertyValue(obj, key, propName, elementDefinition, value) {
1258
874
  const types = elementDefinition.type;
@@ -1437,6 +1053,49 @@
1437
1053
  React__default["default"].createElement(QuantityDisplay, { value: value.denominator })));
1438
1054
  }
1439
1055
 
1056
+ function MedplumLink(props) {
1057
+ const navigate = reactRouterDom.useNavigate();
1058
+ let href = getHref(props.to);
1059
+ if (props.suffix) {
1060
+ href += '/' + props.suffix;
1061
+ }
1062
+ return (React__default["default"].createElement("a", { href: href, id: props.id, "aria-label": props.label, "data-testid": props.testid || 'link', className: props.className, onClick: (e) => {
1063
+ killEvent(e);
1064
+ if (props.onClick) {
1065
+ props.onClick();
1066
+ }
1067
+ else if (props.to) {
1068
+ navigate(href);
1069
+ }
1070
+ } }, props.children));
1071
+ }
1072
+ function getHref(to) {
1073
+ if (to) {
1074
+ if (typeof to === 'string') {
1075
+ return getStringHref(to);
1076
+ }
1077
+ else if ('resourceType' in to) {
1078
+ return getResourceHref(to);
1079
+ }
1080
+ else if ('reference' in to) {
1081
+ return getReferenceHref(to);
1082
+ }
1083
+ }
1084
+ return '#';
1085
+ }
1086
+ function getStringHref(to) {
1087
+ if (to.startsWith('http://') || to.startsWith('https://') || to.startsWith('/')) {
1088
+ return to;
1089
+ }
1090
+ return '/' + to;
1091
+ }
1092
+ function getResourceHref(to) {
1093
+ return `/${to.resourceType}/${to.id}`;
1094
+ }
1095
+ function getReferenceHref(to) {
1096
+ return `/${to.reference}`;
1097
+ }
1098
+
1440
1099
  function ReferenceDisplay(props) {
1441
1100
  if (!props.value) {
1442
1101
  return null;
@@ -1566,35 +1225,85 @@
1566
1225
  props.onChange(newValue);
1567
1226
  }
1568
1227
  }
1569
- return (React__default["default"].createElement(Input, { name: props.name, type: "text", placeholder: "Annotation text", defaultValue: value.text, onChange: setText }));
1228
+ return (React__default["default"].createElement(core$1.TextInput, { name: props.name, placeholder: "Annotation text", defaultValue: value.text, onChange: (e) => setText(e.currentTarget.value) }));
1570
1229
  }
1571
1230
 
1572
- function Checkbox(props) {
1573
- const className = 'medplum-checkbox';
1574
- return (React__default["default"].createElement("input", { id: props.name, name: props.name, className: className, type: "checkbox", value: "true", defaultChecked: !!props.defaultValue, required: props.required, ref: props.inputRef, "data-testid": props.testid, disabled: props.disabled, onChange: (e) => {
1575
- if (props.onChange) {
1576
- props.onChange(e.currentTarget.checked);
1231
+ function valueSetElementToAutocompleteItem(element) {
1232
+ return {
1233
+ value: element.code,
1234
+ label: getDisplay(element),
1235
+ element,
1236
+ };
1237
+ }
1238
+ function ValueSetAutocomplete(props) {
1239
+ const medplum = useMedplum();
1240
+ const { property, defaultValue } = props;
1241
+ const [textValues, setTextValues] = React.useState(defaultValue ? [defaultValue.code] : []);
1242
+ const [data, setData] = React.useState(defaultValue ? [valueSetElementToAutocompleteItem(defaultValue)] : []);
1243
+ const dataRef = React.useRef();
1244
+ dataRef.current = data;
1245
+ const loadValues = React.useCallback((input) => __awaiter(this, void 0, void 0, function* () {
1246
+ var _a, _b;
1247
+ const system = (_a = property.binding) === null || _a === void 0 ? void 0 : _a.valueSet;
1248
+ const valueSet = yield medplum.searchValueSet(system, input);
1249
+ const valueSetElements = (_b = valueSet.expansion) === null || _b === void 0 ? void 0 : _b.contains;
1250
+ const newData = [...dataRef.current];
1251
+ for (const valueSetElement of valueSetElements) {
1252
+ if (!newData.some((item) => item.value === valueSetElement.code)) {
1253
+ newData.push(valueSetElementToAutocompleteItem(valueSetElement));
1577
1254
  }
1578
- } }));
1255
+ }
1256
+ setData(newData);
1257
+ }), [medplum, property, dataRef]);
1258
+ function handleChange(values) {
1259
+ setTextValues(values);
1260
+ const textValue = values[0];
1261
+ let currentItem = undefined;
1262
+ if (textValue) {
1263
+ currentItem = dataRef.current.find((item) => item.value === values[0]);
1264
+ if (!currentItem) {
1265
+ const newElement = { code: textValue, display: textValue };
1266
+ currentItem = valueSetElementToAutocompleteItem(newElement);
1267
+ setData([...dataRef.current, currentItem]);
1268
+ }
1269
+ }
1270
+ if (props.onChange) {
1271
+ props.onChange(currentItem === null || currentItem === void 0 ? void 0 : currentItem.element);
1272
+ }
1273
+ }
1274
+ React.useEffect(() => {
1275
+ loadValues('').catch(console.log);
1276
+ }, [loadValues]);
1277
+ return (React__default["default"].createElement(core$1.MultiSelect, { data: data, placeholder: props.placeholder, searchable: true, creatable: true, clearable: true, value: textValues, filter: (value, selected, item) => {
1278
+ var _a, _b;
1279
+ return !!(textValues.length === 0 &&
1280
+ !selected &&
1281
+ (((_a = item.element.display) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(value.toLowerCase().trim())) ||
1282
+ ((_b = item.element.code) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes(value.toLowerCase().trim()))));
1283
+ }, onChange: handleChange, getCreateLabel: (query) => `+ Create ${query}`, onCreate: (query) => valueSetElementToAutocompleteItem({ code: query, display: query }) }));
1284
+ }
1285
+ function getDisplay(item) {
1286
+ return item.display || item.code || '';
1579
1287
  }
1580
1288
 
1581
1289
  function CodeableConceptInput(props) {
1582
- const medplum = useMedplum();
1583
- let defaultValue = undefined;
1584
- if (props.defaultValue) {
1585
- defaultValue = [props.defaultValue];
1290
+ const [value, setValue] = React.useState(props.defaultValue);
1291
+ function handleChange(newValue) {
1292
+ const newConcept = newValue && valueSetElementToCodeableConcept(newValue);
1293
+ setValue(newConcept);
1294
+ if (props.onChange) {
1295
+ props.onChange(newConcept);
1296
+ }
1586
1297
  }
1587
- return (React__default["default"].createElement(Autocomplete, { loadOptions: (input) => {
1588
- var _a;
1589
- const system = (_a = props.property.binding) === null || _a === void 0 ? void 0 : _a.valueSet;
1590
- return medplum.searchValueSet(system, input).then((valueSet) => {
1591
- return valueSet.expansion.contains.map(valueSetElementToCodeableConcept);
1592
- });
1593
- }, buildUnstructured: buildUnstructured, getId: getId, getDisplay: getDisplay, name: props.name, defaultValue: defaultValue, loadOnFocus: true, onChange: (values) => {
1594
- if (props.onChange) {
1595
- props.onChange(values[0]);
1596
- }
1597
- } }));
1298
+ return (React__default["default"].createElement(ValueSetAutocomplete, { property: props.property, name: props.name, placeholder: props.placeholder, defaultValue: value && codeableConceptToValueSetElement(value), onChange: handleChange }));
1299
+ }
1300
+ function codeableConceptToValueSetElement(concept) {
1301
+ var _a, _b, _c, _d, _e, _f;
1302
+ return {
1303
+ system: (_b = (_a = concept.coding) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.system,
1304
+ code: (_d = (_c = concept.coding) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.code,
1305
+ display: (_f = (_e = concept.coding) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.display,
1306
+ };
1598
1307
  }
1599
1308
  function valueSetElementToCodeableConcept(element) {
1600
1309
  return {
@@ -1608,64 +1317,49 @@
1608
1317
  ],
1609
1318
  };
1610
1319
  }
1611
- function buildUnstructured(str) {
1612
- return { text: str };
1613
- }
1614
- function getId(concept) {
1615
- if (concept.coding && concept.coding.length > 0) {
1616
- return concept.coding[0].code;
1320
+
1321
+ function CodeInput(props) {
1322
+ const [value, setValue] = React.useState(props.defaultValue);
1323
+ function handleChange(newValue) {
1324
+ const newCode = valueSetElementToCode(newValue);
1325
+ setValue(newCode);
1326
+ if (props.onChange) {
1327
+ props.onChange(newCode);
1328
+ }
1617
1329
  }
1618
- return core.stringify(concept);
1330
+ return (React__default["default"].createElement(ValueSetAutocomplete, { property: props.property, name: props.name, placeholder: props.placeholder, defaultValue: codeToValueSetElement(value), onChange: handleChange }));
1619
1331
  }
1620
- function getDisplay(concept) {
1621
- var _a, _b, _c, _d, _e, _f;
1622
- const text = (_f = (_c = (_b = (_a = concept.coding) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.display) !== null && _c !== void 0 ? _c : (_e = (_d = concept.coding) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.code) !== null && _f !== void 0 ? _f : concept.text;
1623
- return React__default["default"].createElement(React__default["default"].Fragment, null, text);
1332
+ function codeToValueSetElement(code) {
1333
+ return code ? { code } : undefined;
1624
1334
  }
1625
-
1626
- const cachedDisplayValues = {};
1627
- function CodeInput(props) {
1628
- const medplum = useMedplum();
1629
- let defaultValue = undefined;
1630
- if (props.defaultValue) {
1631
- defaultValue = [props.defaultValue];
1632
- }
1633
- return (React__default["default"].createElement(Autocomplete, { loadOptions: (input) => {
1634
- var _a;
1635
- const system = (_a = props.property.binding) === null || _a === void 0 ? void 0 : _a.valueSet;
1636
- return medplum.searchValueSet(system, input).then((valueSet) => {
1637
- const contains = valueSet.expansion.contains;
1638
- contains.forEach((e) => (cachedDisplayValues[e.code] = e.display));
1639
- return contains.map((e) => e.code);
1640
- });
1641
- }, buildUnstructured: (str) => str, getId: (item) => item, getDisplay: (item) => React__default["default"].createElement(React__default["default"].Fragment, null, cachedDisplayValues[item] || item), name: props.name, defaultValue: defaultValue, loadOnFocus: true, onChange: (values) => {
1642
- if (props.onChange) {
1643
- props.onChange(values[0]);
1644
- }
1645
- } }));
1335
+ function valueSetElementToCode(element) {
1336
+ return element === null || element === void 0 ? void 0 : element.code;
1646
1337
  }
1647
1338
 
1648
1339
  function CodingInput(props) {
1649
- const medplum = useMedplum();
1650
- let defaultValue = undefined;
1651
- if (props.defaultValue) {
1652
- defaultValue = [props.defaultValue];
1340
+ const [value, setValue] = React.useState(props.defaultValue);
1341
+ function handleChange(newValue) {
1342
+ const newConcept = newValue && valueSetElementToCoding(newValue);
1343
+ setValue(newConcept);
1344
+ if (props.onChange) {
1345
+ props.onChange(newConcept);
1346
+ }
1653
1347
  }
1654
- return (React__default["default"].createElement(Autocomplete, { loadOptions: (input) => {
1655
- var _a;
1656
- const system = (_a = props.property.binding) === null || _a === void 0 ? void 0 : _a.valueSet;
1657
- return medplum.searchValueSet(system, input).then((valueSet) => {
1658
- return valueSet.expansion.contains.map((e) => ({
1659
- system: e.system,
1660
- code: e.code,
1661
- display: e.display,
1662
- }));
1663
- });
1664
- }, buildUnstructured: (str) => ({ code: str }), getId: (item) => item.code, getDisplay: (item) => React__default["default"].createElement(CodingDisplay, { value: item }), name: props.name, defaultValue: defaultValue, loadOnFocus: true, onChange: (values) => {
1665
- if (props.onChange) {
1666
- props.onChange(values[0]);
1667
- }
1668
- } }));
1348
+ return (React__default["default"].createElement(ValueSetAutocomplete, { property: props.property, name: props.name, placeholder: props.placeholder, defaultValue: value && codingToValueSetElement(value), onChange: handleChange }));
1349
+ }
1350
+ function codingToValueSetElement(coding) {
1351
+ return {
1352
+ system: coding.system,
1353
+ code: coding.code,
1354
+ display: coding.display,
1355
+ };
1356
+ }
1357
+ function valueSetElementToCoding(element) {
1358
+ return {
1359
+ system: element.system,
1360
+ code: element.code,
1361
+ display: element.display,
1362
+ };
1669
1363
  }
1670
1364
 
1671
1365
  function ContactPointInput(props) {
@@ -1702,24 +1396,10 @@
1702
1396
  }
1703
1397
  setContactPointWrapper(newValue);
1704
1398
  }
1705
- return (React__default["default"].createElement(InputRow, null,
1706
- React__default["default"].createElement(Select, { defaultValue: contactPoint === null || contactPoint === void 0 ? void 0 : contactPoint.system, onChange: setSystem, testid: "system" },
1707
- React__default["default"].createElement("option", null),
1708
- React__default["default"].createElement("option", null, "email"),
1709
- React__default["default"].createElement("option", null, "fax"),
1710
- React__default["default"].createElement("option", null, "pager"),
1711
- React__default["default"].createElement("option", null, "phone"),
1712
- React__default["default"].createElement("option", null, "other"),
1713
- React__default["default"].createElement("option", null, "sms"),
1714
- React__default["default"].createElement("option", null, "url")),
1715
- React__default["default"].createElement(Select, { defaultValue: contactPoint === null || contactPoint === void 0 ? void 0 : contactPoint.use, onChange: setUse, testid: "use" },
1716
- React__default["default"].createElement("option", null),
1717
- React__default["default"].createElement("option", null, "home"),
1718
- React__default["default"].createElement("option", null, "mobile"),
1719
- React__default["default"].createElement("option", null, "old"),
1720
- React__default["default"].createElement("option", null, "temp"),
1721
- React__default["default"].createElement("option", null, "work")),
1722
- React__default["default"].createElement(Input, { placeholder: "Value", defaultValue: contactPoint === null || contactPoint === void 0 ? void 0 : contactPoint.value, onChange: setValue })));
1399
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1400
+ React__default["default"].createElement(core$1.NativeSelect, { "data-testid": "system", defaultValue: contactPoint === null || contactPoint === void 0 ? void 0 : contactPoint.system, onChange: (e) => setSystem(e.currentTarget.value), data: ['', 'email', 'phone', 'fax', 'pager', 'sms', 'other'] }),
1401
+ React__default["default"].createElement(core$1.NativeSelect, { "data-testid": "use", defaultValue: contactPoint === null || contactPoint === void 0 ? void 0 : contactPoint.use, onChange: (e) => setUse(e.currentTarget.value), data: ['', 'home', 'work', 'temp', 'old', 'mobile'] }),
1402
+ React__default["default"].createElement(core$1.TextInput, { placeholder: "Value", defaultValue: contactPoint === null || contactPoint === void 0 ? void 0 : contactPoint.value, onChange: (e) => setValue(e.currentTarget.value) })));
1723
1403
  }
1724
1404
 
1725
1405
  function ContactDetailInput(props) {
@@ -1747,8 +1427,8 @@
1747
1427
  }
1748
1428
  setContactDetailWrapper(newValue);
1749
1429
  }
1750
- return (React__default["default"].createElement(InputRow, null,
1751
- React__default["default"].createElement(Input, { name: props.name + '-name', placeholder: "Name", style: { width: 180 }, defaultValue: contactPoint === null || contactPoint === void 0 ? void 0 : contactPoint.name, onChange: setName }),
1430
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1431
+ React__default["default"].createElement(core$1.TextInput, { "data-testid": props.name + '-name', name: props.name + '-name', placeholder: "Name", style: { width: 180 }, defaultValue: contactPoint === null || contactPoint === void 0 ? void 0 : contactPoint.name, onChange: (e) => setName(e.currentTarget.value) }),
1752
1432
  React__default["default"].createElement(ContactPointInput, { name: props.name + '-telecom', defaultValue: (_a = contactPoint === null || contactPoint === void 0 ? void 0 : contactPoint.telecom) === null || _a === void 0 ? void 0 : _a[0], onChange: setTelecom })));
1753
1433
  }
1754
1434
 
@@ -1761,11 +1441,12 @@
1761
1441
  * @returns The JSX element to render.
1762
1442
  */
1763
1443
  function DateTimeInput(props) {
1764
- return (React__default["default"].createElement(Input, Object.assign({}, props, { type: "datetime-local", defaultValue: convertIsoToLocal(props.defaultValue), onChange: (newValue) => {
1444
+ return (React__default["default"].createElement(core$1.TextInput, { id: props.name, name: props.name, "data-testid": props.name, placeholder: props.placeholder, type: getInputType(), defaultValue: convertIsoToLocal(props.defaultValue), error: getErrorsForInput(props.outcome, props.name), onChange: (e) => {
1765
1445
  if (props.onChange) {
1446
+ const newValue = e.currentTarget.value;
1766
1447
  props.onChange(convertLocalToIso(newValue));
1767
1448
  }
1768
- } })));
1449
+ } }));
1769
1450
  }
1770
1451
  /**
1771
1452
  * Converts an ISO-8601 date/time string to a local date/time string.
@@ -1805,20 +1486,17 @@
1805
1486
  }
1806
1487
  return date.toISOString();
1807
1488
  }
1808
-
1809
- function TextArea(props) {
1810
- const className = 'medplum-textarea' + (props.monospace ? ' monospace' : '');
1811
- const issues = getIssuesForExpression(props.outcome, props.name);
1812
- const invalid = issues && issues.length > 0;
1813
- return (React__default["default"].createElement("textarea", { id: props.name, name: props.name, className: className, defaultValue: props.defaultValue || '', required: props.required, autoComplete: props.autoComplete, autoFocus: props.autoFocus, ref: props.inputRef, "aria-invalid": invalid, "aria-describedby": invalid ? props.name + '-errors' : '', placeholder: props.placeholder, "data-testid": props.testid, style: props.style, onChange: (e) => {
1814
- if (props.onChange) {
1815
- props.onChange(e.currentTarget.value);
1816
- }
1817
- } }));
1489
+ /**
1490
+ * Returns the input type for the requested type.
1491
+ * JSDOM does not support many of the valid <input> type attributes.
1492
+ * For example, it won't fire change events for <input type="datetime-local">.
1493
+ */
1494
+ function getInputType() {
1495
+ return 'datetime-local';
1818
1496
  }
1819
1497
 
1820
1498
  function ExtensionInput(props) {
1821
- return (React__default["default"].createElement(TextArea, { testid: "extension-input", name: props.name, defaultValue: core.stringify(props.defaultValue), monospace: true, onChange: (newValue) => {
1499
+ return (React__default["default"].createElement(core$1.JsonInput, { id: props.name, name: props.name, "data-testid": "extension-input", defaultValue: core.stringify(props.defaultValue), onChange: (newValue) => {
1822
1500
  if (props.onChange) {
1823
1501
  props.onChange(JSON.parse(newValue));
1824
1502
  }
@@ -1851,20 +1529,12 @@
1851
1529
  function setSuffix(suffix) {
1852
1530
  setValueWrapper(Object.assign(Object.assign({}, valueRef.current), { suffix: suffix ? suffix.split(' ') : undefined }));
1853
1531
  }
1854
- return (React__default["default"].createElement(InputRow, null,
1855
- React__default["default"].createElement(Select, { defaultValue: value === null || value === void 0 ? void 0 : value.use, onChange: setUse, testid: "use" },
1856
- React__default["default"].createElement("option", null),
1857
- React__default["default"].createElement("option", null, "usual"),
1858
- React__default["default"].createElement("option", null, "official"),
1859
- React__default["default"].createElement("option", null, "temp"),
1860
- React__default["default"].createElement("option", null, "nickname"),
1861
- React__default["default"].createElement("option", null, "anonymous"),
1862
- React__default["default"].createElement("option", null, "old"),
1863
- React__default["default"].createElement("option", null, "maiden")),
1864
- React__default["default"].createElement(Input, { placeholder: "Prefix", defaultValue: (_a = value === null || value === void 0 ? void 0 : value.prefix) === null || _a === void 0 ? void 0 : _a.join(' '), onChange: setPrefix }),
1865
- React__default["default"].createElement(Input, { placeholder: "Given", defaultValue: (_b = value === null || value === void 0 ? void 0 : value.given) === null || _b === void 0 ? void 0 : _b.join(' '), onChange: setGiven }),
1866
- React__default["default"].createElement(Input, { placeholder: "Family", defaultValue: value === null || value === void 0 ? void 0 : value.family, onChange: setFamily }),
1867
- React__default["default"].createElement(Input, { placeholder: "Suffix", defaultValue: (_c = value === null || value === void 0 ? void 0 : value.suffix) === null || _c === void 0 ? void 0 : _c.join(' '), onChange: setSuffix })));
1532
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1533
+ React__default["default"].createElement(core$1.NativeSelect, { defaultValue: value === null || value === void 0 ? void 0 : value.use, "data-testid": "use", onChange: (e) => setUse(e.currentTarget.value), data: ['', 'temp', 'old', 'usual', 'official', 'nickname', 'anonymous', 'maiden'] }),
1534
+ React__default["default"].createElement(core$1.TextInput, { placeholder: "Prefix", defaultValue: (_a = value === null || value === void 0 ? void 0 : value.prefix) === null || _a === void 0 ? void 0 : _a.join(' '), onChange: (e) => setPrefix(e.currentTarget.value) }),
1535
+ React__default["default"].createElement(core$1.TextInput, { placeholder: "Given", defaultValue: (_b = value === null || value === void 0 ? void 0 : value.given) === null || _b === void 0 ? void 0 : _b.join(' '), onChange: (e) => setGiven(e.currentTarget.value) }),
1536
+ React__default["default"].createElement(core$1.TextInput, { placeholder: "Family", defaultValue: value === null || value === void 0 ? void 0 : value.family, onChange: (e) => setFamily(e.currentTarget.value) }),
1537
+ React__default["default"].createElement(core$1.TextInput, { placeholder: "Suffix", defaultValue: (_c = value === null || value === void 0 ? void 0 : value.suffix) === null || _c === void 0 ? void 0 : _c.join(' '), onChange: (e) => setSuffix(e.currentTarget.value) })));
1868
1538
  }
1869
1539
 
1870
1540
  function IdentifierInput(props) {
@@ -1875,9 +1545,9 @@
1875
1545
  props.onChange(newValue);
1876
1546
  }
1877
1547
  }
1878
- return (React__default["default"].createElement(InputRow, null,
1879
- React__default["default"].createElement(Input, { placeholder: "System", defaultValue: value === null || value === void 0 ? void 0 : value.system, onChange: (newValue) => setValueWrapper(Object.assign(Object.assign({}, value), { system: newValue })) }),
1880
- React__default["default"].createElement(Input, { placeholder: "Value", defaultValue: value === null || value === void 0 ? void 0 : value.value, onChange: (newValue) => setValueWrapper(Object.assign(Object.assign({}, value), { value: newValue })) })));
1548
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1549
+ React__default["default"].createElement(core$1.TextInput, { placeholder: "System", defaultValue: value === null || value === void 0 ? void 0 : value.system, onChange: (e) => setValueWrapper(Object.assign(Object.assign({}, value), { system: e.currentTarget.value })) }),
1550
+ React__default["default"].createElement(core$1.TextInput, { placeholder: "Value", defaultValue: value === null || value === void 0 ? void 0 : value.value, onChange: (e) => setValueWrapper(Object.assign(Object.assign({}, value), { value: e.currentTarget.value })) })));
1881
1551
  }
1882
1552
 
1883
1553
  function PeriodInput(props) {
@@ -1888,9 +1558,9 @@
1888
1558
  props.onChange(newValue);
1889
1559
  }
1890
1560
  }
1891
- return (React__default["default"].createElement(InputRow, null,
1892
- React__default["default"].createElement(Input, { type: "datetime-local", placeholder: "Start", defaultValue: value === null || value === void 0 ? void 0 : value.start, onChange: (newValue) => setValueWrapper(Object.assign(Object.assign({}, value), { start: newValue })) }),
1893
- React__default["default"].createElement(Input, { type: "datetime-local", placeholder: "End", defaultValue: value === null || value === void 0 ? void 0 : value.end, onChange: (newValue) => setValueWrapper(Object.assign(Object.assign({}, value), { end: newValue })) })));
1561
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1562
+ React__default["default"].createElement(DateTimeInput, { name: props.name + '.start', placeholder: "Start", defaultValue: value === null || value === void 0 ? void 0 : value.start, onChange: (newValue) => setValueWrapper(Object.assign(Object.assign({}, value), { start: newValue })) }),
1563
+ React__default["default"].createElement(DateTimeInput, { name: props.name + '.end', placeholder: "End", defaultValue: value === null || value === void 0 ? void 0 : value.end, onChange: (newValue) => setValueWrapper(Object.assign(Object.assign({}, value), { end: newValue })) })));
1894
1564
  }
1895
1565
 
1896
1566
  function QuantityInput(props) {
@@ -1902,15 +1572,10 @@
1902
1572
  props.onChange(newValue);
1903
1573
  }
1904
1574
  }
1905
- return (React__default["default"].createElement(InputRow, null,
1906
- React__default["default"].createElement(Select, { style: { width: 80 }, testid: props.name + '-comparator', defaultValue: value === null || value === void 0 ? void 0 : value.comparator, onChange: (newValue) => setValueWrapper(Object.assign(Object.assign({}, value), { comparator: newValue })) },
1907
- React__default["default"].createElement("option", null),
1908
- React__default["default"].createElement("option", null, "<"),
1909
- React__default["default"].createElement("option", null, "<="),
1910
- React__default["default"].createElement("option", null, ">="),
1911
- React__default["default"].createElement("option", null, ">")),
1912
- React__default["default"].createElement(Input, { name: props.name, type: "number", step: "any", placeholder: "Value", defaultValue: (_a = value === null || value === void 0 ? void 0 : value.value) === null || _a === void 0 ? void 0 : _a.toString(), onChange: (newValue) => setValueWrapper(Object.assign(Object.assign({}, value), { value: tryParseNumber(newValue) })) }),
1913
- React__default["default"].createElement(Input, { placeholder: "Unit", defaultValue: value === null || value === void 0 ? void 0 : value.unit, onChange: (newValue) => setValueWrapper(Object.assign(Object.assign({}, value), { unit: newValue })) })));
1575
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1576
+ React__default["default"].createElement(core$1.NativeSelect, { style: { width: 80 }, "data-testid": props.name + '-comparator', defaultValue: value === null || value === void 0 ? void 0 : value.comparator, data: ['', '<', '<=', '>=', '>'], onChange: (e) => setValueWrapper(Object.assign(Object.assign({}, value), { comparator: e.currentTarget.value })) }),
1577
+ React__default["default"].createElement(core$1.TextInput, { id: props.name, name: props.name, "data-testid": props.name, type: "number", step: "any", placeholder: "Value", defaultValue: (_a = value === null || value === void 0 ? void 0 : value.value) === null || _a === void 0 ? void 0 : _a.toString(), onChange: (e) => setValueWrapper(Object.assign(Object.assign({}, value), { value: tryParseNumber(e.currentTarget.value) })) }),
1578
+ React__default["default"].createElement(core$1.TextInput, { placeholder: "Unit", defaultValue: value === null || value === void 0 ? void 0 : value.unit, onChange: (e) => setValueWrapper(Object.assign(Object.assign({}, value), { unit: e.currentTarget.value })) })));
1914
1579
  }
1915
1580
  function tryParseNumber(str) {
1916
1581
  if (!str) {
@@ -1933,7 +1598,7 @@
1933
1598
  props.onChange(newValue);
1934
1599
  }
1935
1600
  }
1936
- return (React__default["default"].createElement(InputRow, null,
1601
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1937
1602
  React__default["default"].createElement(QuantityInput, { name: props.name + '-low', defaultValue: value === null || value === void 0 ? void 0 : value.low, onChange: (v) => setValueWrapper(Object.assign(Object.assign({}, value), { low: v })) }),
1938
1603
  React__default["default"].createElement(QuantityInput, { name: props.name + '-high', defaultValue: value === null || value === void 0 ? void 0 : value.high, onChange: (v) => setValueWrapper(Object.assign(Object.assign({}, value), { high: v })) })));
1939
1604
  }
@@ -1952,50 +1617,65 @@
1952
1617
  props.onChange(newValue);
1953
1618
  }
1954
1619
  }
1955
- return (React__default["default"].createElement(InputRow, null,
1620
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1956
1621
  React__default["default"].createElement(QuantityInput, { name: props.name + '-numerator', defaultValue: value === null || value === void 0 ? void 0 : value.numerator, onChange: (v) => setValueWrapper(Object.assign(Object.assign({}, value), { numerator: v })) }),
1957
1622
  React__default["default"].createElement(QuantityInput, { name: props.name + '-denominator', defaultValue: value === null || value === void 0 ? void 0 : value.denominator, onChange: (v) => setValueWrapper(Object.assign(Object.assign({}, value), { denominator: v })) })));
1958
1623
  }
1959
1624
 
1960
- function ResourceName(props) {
1625
+ function ResourceAvatar(props) {
1626
+ var _a, _b, _c;
1961
1627
  const resource = useResource(props.value);
1962
- if (!resource) {
1963
- return null;
1628
+ const text = resource ? core.getDisplayString(resource) : (_a = props.alt) !== null && _a !== void 0 ? _a : '';
1629
+ const imageUrl = (_b = (resource && core.getImageSrc(resource))) !== null && _b !== void 0 ? _b : props.src;
1630
+ const radius = (_c = props.radius) !== null && _c !== void 0 ? _c : 'xl';
1631
+ const avatarProps = Object.assign({}, props);
1632
+ delete avatarProps.value;
1633
+ delete avatarProps.link;
1634
+ if (props.link) {
1635
+ return (React__default["default"].createElement(MedplumLink, { to: resource },
1636
+ React__default["default"].createElement(core$1.Avatar, Object.assign({ src: imageUrl, alt: text, radius: radius }, avatarProps))));
1964
1637
  }
1965
- const text = core.getDisplayString(resource);
1966
- return props.link ? React__default["default"].createElement(MedplumLink, { to: resource }, text) : React__default["default"].createElement("span", null, text);
1638
+ return React__default["default"].createElement(core$1.Avatar, Object.assign({ src: imageUrl, alt: text, radius: radius }, avatarProps));
1967
1639
  }
1968
1640
 
1969
1641
  function ResourceInput(props) {
1970
1642
  const medplum = useMedplum();
1971
- const defaultResource = useResource(props.defaultValue);
1972
- const [value, setValue] = React.useState();
1973
- const resourceTypeRef = React.useRef(props.resourceType);
1974
- resourceTypeRef.current = props.resourceType;
1975
- React.useEffect(() => {
1976
- setValue(defaultResource);
1977
- }, [defaultResource]);
1978
- function setValueWrapper(newValue) {
1979
- setValue(newValue);
1643
+ const defaultValue = useResource(props.defaultValue);
1644
+ const [value, setValue] = React.useState(defaultValue ? core.getDisplayString(defaultValue) : '');
1645
+ const [loading, setLoading] = React.useState(false);
1646
+ const [data, setData] = React.useState([]);
1647
+ function loadValues(input) {
1648
+ return __awaiter(this, void 0, void 0, function* () {
1649
+ setLoading(true);
1650
+ const resources = yield medplum.searchResources(props.resourceType, 'name=' + encodeURIComponent(input) + '&_count=10');
1651
+ setData(resources.map((resource) => ({ value: core.getDisplayString(resource), resource })));
1652
+ setLoading(false);
1653
+ });
1654
+ }
1655
+ function handleChange(val) {
1656
+ return __awaiter(this, void 0, void 0, function* () {
1657
+ setValue(val);
1658
+ return loadValues(val);
1659
+ });
1660
+ }
1661
+ function handleSelect(item) {
1662
+ setValue(item.value);
1663
+ setData([]);
1980
1664
  if (props.onChange) {
1981
- props.onChange(newValue);
1665
+ props.onChange(item.resource);
1982
1666
  }
1983
1667
  }
1984
- return (React__default["default"].createElement(Autocomplete, { loadOptions: (input) => __awaiter(this, void 0, void 0, function* () {
1985
- return medplum
1986
- .search(resourceTypeRef.current, 'name=' + encodeURIComponent(input) + '&_count=10')
1987
- .then((bundle) => bundle.entry.map((entry) => entry.resource));
1988
- }), getId: (item) => {
1989
- return item.id;
1990
- }, getIcon: (item) => React__default["default"].createElement(Avatar, { value: item }), getDisplay: (item) => React__default["default"].createElement(ResourceName, { value: item }), getHelpText: (item) => {
1991
- if (item.resourceType === 'Patient' && item.birthDate) {
1992
- return 'DoB: ' + item.birthDate;
1993
- }
1994
- return undefined;
1995
- }, name: props.name, defaultValue: value ? [value] : undefined, className: props.className, placeholder: props.placeholder, loadOnFocus: props.loadOnFocus, onChange: (items) => {
1996
- setValueWrapper(items.length > 0 ? items[0] : undefined);
1997
- } }));
1668
+ return (React__default["default"].createElement(core$1.Autocomplete, { itemComponent: ItemComponent, value: value, data: data, placeholder: props.placeholder, onFocus: () => loadValues(value), onChange: handleChange, onItemSubmit: handleSelect, rightSection: loading ? React__default["default"].createElement(core$1.Loader, { size: 16 }) : null }));
1998
1669
  }
1670
+ const ItemComponent = React.forwardRef((_a, ref) => {
1671
+ var { value, resource } = _a, others = __rest(_a, ["value", "resource"]);
1672
+ return (React__default["default"].createElement("div", Object.assign({ ref: ref }, others),
1673
+ React__default["default"].createElement(core$1.Group, { noWrap: true },
1674
+ React__default["default"].createElement(ResourceAvatar, { value: resource }),
1675
+ React__default["default"].createElement("div", null,
1676
+ React__default["default"].createElement(core$1.Text, null, value),
1677
+ React__default["default"].createElement(core$1.Text, { size: "xs", color: "dimmed" }, resource.birthDate)))));
1678
+ });
1999
1679
 
2000
1680
  function ReferenceInput(props) {
2001
1681
  const targetTypes = props.targetTypes;
@@ -2012,9 +1692,9 @@
2012
1692
  props.onChange(newValue);
2013
1693
  }
2014
1694
  }
2015
- return (React__default["default"].createElement(InputRow, null,
2016
- targetTypes ? (React__default["default"].createElement(Select, { testid: "reference-input-resource-type-select", defaultValue: resourceType, onChange: setResourceType }, targetTypes.map((targetType) => (React__default["default"].createElement("option", { key: targetType, value: targetType }, targetType))))) : (React__default["default"].createElement(Input, { testid: "reference-input-resource-type-input", defaultValue: resourceType, onChange: setResourceType })),
2017
- React__default["default"].createElement(ResourceInput, { resourceType: resourceType, name: props.name + '-id', defaultValue: value, onChange: (item) => {
1695
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1696
+ targetTypes ? (React__default["default"].createElement(core$1.NativeSelect, { "data-testid": "reference-input-resource-type-select", defaultValue: resourceType, onChange: (e) => setResourceType(e.currentTarget.value), data: targetTypes })) : (React__default["default"].createElement(core$1.TextInput, { "data-testid": "reference-input-resource-type-input", defaultValue: resourceType, onChange: (e) => setResourceType(e.currentTarget.value) })),
1697
+ React__default["default"].createElement(ResourceInput, { resourceType: resourceType, name: props.name + '-id', placeholder: props.placeholder, defaultValue: value, onChange: (item) => {
2018
1698
  setValueHelper(item ? core.createReference(item) : undefined);
2019
1699
  } })));
2020
1700
  }
@@ -2042,8 +1722,8 @@
2042
1722
  }
2043
1723
  return (React__default["default"].createElement("table", { style: { width: '100%', borderCollapse: 'collapse' } },
2044
1724
  React__default["default"].createElement("colgroup", null,
2045
- React__default["default"].createElement("col", { width: "90%" }),
2046
- React__default["default"].createElement("col", { width: "10%" })),
1725
+ React__default["default"].createElement("col", { width: "97%" }),
1726
+ React__default["default"].createElement("col", { width: "3%" })),
2047
1727
  React__default["default"].createElement("tbody", null,
2048
1728
  values.map((v, index) => (React__default["default"].createElement("tr", { key: `${index}-${values.length}` },
2049
1729
  React__default["default"].createElement("td", null,
@@ -2053,58 +1733,23 @@
2053
1733
  setValuesWrapper(copy);
2054
1734
  } })),
2055
1735
  React__default["default"].createElement("td", { style: { textAlign: 'right' } },
2056
- React__default["default"].createElement(Button, { onClick: (e) => {
1736
+ React__default["default"].createElement(core$1.ActionIcon, { title: "Remove", size: "sm", onClick: (e) => {
2057
1737
  killEvent(e);
2058
1738
  const copy = [...valuesRef.current];
2059
1739
  copy.splice(index, 1);
2060
1740
  setValuesWrapper(copy);
2061
- } }, "Remove"))))),
1741
+ } },
1742
+ React__default["default"].createElement(icons.IconCircleMinus, null)))))),
2062
1743
  React__default["default"].createElement("tr", null,
2063
1744
  React__default["default"].createElement("td", null),
2064
1745
  React__default["default"].createElement("td", { style: { textAlign: 'right' } },
2065
- React__default["default"].createElement(Button, { onClick: (e) => {
1746
+ React__default["default"].createElement(core$1.ActionIcon, { title: "Add", size: "sm", color: "green", onClick: (e) => {
2066
1747
  killEvent(e);
2067
1748
  const copy = [...valuesRef.current];
2068
1749
  copy.push(undefined);
2069
1750
  setValuesWrapper(copy);
2070
- } }, "Add"))))));
2071
- }
2072
-
2073
- function Dialog(props) {
2074
- const [x, setX] = React.useState(100);
2075
- const [y, setY] = React.useState(100);
2076
- if (!props.visible) {
2077
- return null;
2078
- }
2079
- function handleMouseDown(downEvent) {
2080
- killEvent(downEvent);
2081
- const dragX = downEvent.clientX - x;
2082
- const dragY = downEvent.clientY - y;
2083
- function handleMouseMove(moveEvent) {
2084
- killEvent(moveEvent);
2085
- setX(moveEvent.clientX - dragX);
2086
- setY(moveEvent.clientY - dragY);
2087
- }
2088
- function handleMouseUp(upEvent) {
2089
- killEvent(upEvent);
2090
- document.removeEventListener('mouseup', handleMouseUp, true);
2091
- document.removeEventListener('mousemove', handleMouseMove, true);
2092
- }
2093
- document.addEventListener('mouseup', handleMouseUp, true);
2094
- document.addEventListener('mousemove', handleMouseMove, true);
2095
- }
2096
- return (React__default["default"].createElement(React__default["default"].Fragment, null,
2097
- React__default["default"].createElement("div", { className: "modal-dialog-bg" }),
2098
- React__default["default"].createElement("div", { className: "modal-dialog", "data-testid": "dialog", tabIndex: 0, style: { left: x + 'px', top: y + 'px' } },
2099
- React__default["default"].createElement("div", { className: "modal-dialog-title", onMouseDown: (e) => handleMouseDown(e) },
2100
- React__default["default"].createElement("span", { className: "modal-dialog-title-text" }, props.title),
2101
- React__default["default"].createElement("span", { className: "modal-dialog-title-close", tabIndex: 0, onClick: props.onCancel },
2102
- React__default["default"].createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor" },
2103
- React__default["default"].createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" })))),
2104
- React__default["default"].createElement("div", { className: "modal-dialog-content" }, props.children),
2105
- React__default["default"].createElement("div", { className: "modal-dialog-buttons" },
2106
- React__default["default"].createElement(Button, { testid: "dialog-ok", onClick: props.onOk }, "OK"),
2107
- React__default["default"].createElement(Button, { testid: "dialog-cancel", onClick: props.onCancel }, "Cancel")))));
1751
+ } },
1752
+ React__default["default"].createElement(icons.IconCirclePlus, null)))))));
2108
1753
  }
2109
1754
 
2110
1755
  const daysOfWeek = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
@@ -2114,9 +1759,9 @@
2114
1759
  const valueRef = React.useRef();
2115
1760
  valueRef.current = value;
2116
1761
  return (React__default["default"].createElement(React__default["default"].Fragment, null,
2117
- React__default["default"].createElement(InputRow, null,
1762
+ React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
2118
1763
  React__default["default"].createElement("span", null, core.formatTiming(valueRef.current) || 'No repeat'),
2119
- React__default["default"].createElement(Button, { onClick: () => setOpen(true) }, "Edit")),
1764
+ React__default["default"].createElement(core$1.Button, { onClick: () => setOpen(true) }, "Edit")),
2120
1765
  React__default["default"].createElement(TimingEditorDialog, { visible: open, defaultValue: valueRef.current, onOk: (newValue) => {
2121
1766
  if (props.onChange) {
2122
1767
  props.onChange(newValue);
@@ -2166,22 +1811,24 @@
2166
1811
  setRepeat(Object.assign(Object.assign({}, (_c = valueRef.current) === null || _c === void 0 ? void 0 : _c.repeat), { dayOfWeek: existing.filter((d) => d !== day) }));
2167
1812
  }
2168
1813
  }
2169
- return (React__default["default"].createElement(Dialog, { title: "Timing", visible: props.visible, onOk: () => props.onOk(value), onCancel: () => props.onCancel() },
1814
+ return (React__default["default"].createElement(core$1.Modal, { title: "Timing", closeButtonLabel: "Close", opened: props.visible, onClose: () => props.onCancel() },
2170
1815
  React__default["default"].createElement("div", { style: { padding: '5px 20px', textAlign: 'left' } },
2171
1816
  React__default["default"].createElement(FormSection, { title: "Starts on", htmlFor: 'timing-dialog-start' },
2172
1817
  React__default["default"].createElement(DateTimeInput, { name: 'timing-dialog-start', onChange: (newValue) => setStart(newValue) })),
2173
1818
  React__default["default"].createElement(FormSection, { title: "Repeat every", htmlFor: 'timing-dialog-period' },
2174
- React__default["default"].createElement(InputRow, null,
2175
- React__default["default"].createElement(Input, { type: "number", step: 1, name: 'timing-dialog-period', defaultValue: (_a = value === null || value === void 0 ? void 0 : value.repeat) === null || _a === void 0 ? void 0 : _a.period, onChange: (newValue) => setPeriod(parseInt(newValue)) }),
2176
- React__default["default"].createElement(Select, { name: 'timing-dialog-periodUnit', defaultValue: (_b = value === null || value === void 0 ? void 0 : value.repeat) === null || _b === void 0 ? void 0 : _b.periodUnit, onChange: (newValue) => setPeriodUnit(newValue) },
2177
- React__default["default"].createElement("option", { value: "d" }, "day"),
2178
- React__default["default"].createElement("option", { value: "wk" }, "week"),
2179
- React__default["default"].createElement("option", { value: "mo" }, "month"),
2180
- React__default["default"].createElement("option", { value: "a" }, "year")))),
1819
+ React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1820
+ React__default["default"].createElement(core$1.TextInput, { type: "number", step: 1, id: "timing-dialog-period", name: "timing-dialog-period", defaultValue: (_a = value === null || value === void 0 ? void 0 : value.repeat) === null || _a === void 0 ? void 0 : _a.period, onChange: (e) => setPeriod(parseInt(e.currentTarget.value)) }),
1821
+ React__default["default"].createElement(core$1.NativeSelect, { id: "timing-dialog-periodUnit", name: "timing-dialog-periodUnit", defaultValue: (_b = value === null || value === void 0 ? void 0 : value.repeat) === null || _b === void 0 ? void 0 : _b.periodUnit, onChange: (e) => setPeriodUnit(e.currentTarget.value), data: [
1822
+ { label: 'day', value: 'd' },
1823
+ { label: 'week', value: 'wk' },
1824
+ { label: 'month', value: 'mo' },
1825
+ { label: 'year', value: 'a' },
1826
+ ] }))),
2181
1827
  React__default["default"].createElement(FormSection, { title: "Repeat on" },
2182
- React__default["default"].createElement(InputRow, null, daysOfWeek.map((day) => (React__default["default"].createElement(React__default["default"].Fragment, { key: day },
1828
+ React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true }, daysOfWeek.map((day) => (React__default["default"].createElement(React__default["default"].Fragment, { key: day },
2183
1829
  React__default["default"].createElement("label", { htmlFor: 'timing-dialog-repeat-' + day }, day.charAt(0).toUpperCase()),
2184
- React__default["default"].createElement(Checkbox, { name: 'timing-dialog-repeat-' + day, onChange: (newValue) => setDayOfWeek(day, newValue) })))))))));
1830
+ React__default["default"].createElement(core$1.Checkbox, { id: 'timing-dialog-repeat-' + day, name: 'timing-dialog-repeat-' + day, onChange: (e) => setDayOfWeek(day, e.currentTarget.checked) }))))))),
1831
+ React__default["default"].createElement(core$1.Button, { onClick: () => props.onOk(value) }, "OK")));
2185
1832
  }
2186
1833
 
2187
1834
  function ResourcePropertyInput(props) {
@@ -2214,10 +1861,13 @@
2214
1861
  initialPropertyType = propertyTypes[0];
2215
1862
  }
2216
1863
  const [selectedType, setSelectedType] = React.useState(initialPropertyType);
2217
- return (React__default["default"].createElement(InputRow, null,
2218
- React__default["default"].createElement(Select, { style: { width: '200px' }, defaultValue: selectedType === null || selectedType === void 0 ? void 0 : selectedType.code, onChange: (newValue) => {
2219
- setSelectedType(propertyTypes.find((type) => type.code === newValue));
2220
- } }, propertyTypes.map((type) => (React__default["default"].createElement("option", { key: type.code, value: type.code }, type.code)))),
1864
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1865
+ React__default["default"].createElement(core$1.NativeSelect, { style: { width: '200px' }, defaultValue: selectedType === null || selectedType === void 0 ? void 0 : selectedType.code, onChange: (e) => {
1866
+ setSelectedType(propertyTypes.find((type) => type.code === e.currentTarget.value));
1867
+ }, data: propertyTypes.map((type) => ({
1868
+ value: type.code,
1869
+ label: type.code,
1870
+ })) }),
2221
1871
  React__default["default"].createElement(ElementDefinitionTypeInput, Object.assign({}, props, { elementDefinitionType: selectedType, onChange: (newValue) => {
2222
1872
  if (props.onChange) {
2223
1873
  props.onChange(newValue, props.name.replace('[x]', core.capitalize(selectedType.code)));
@@ -2239,31 +1889,43 @@
2239
1889
  case core.PropertyType.time:
2240
1890
  case core.PropertyType.uri:
2241
1891
  case core.PropertyType.url:
2242
- return (React__default["default"].createElement(Input, { type: "text", name: name, testid: name, defaultValue: value, onChange: props.onChange, outcome: props.outcome }));
1892
+ return (React__default["default"].createElement(core$1.TextInput, { id: name, name: name, "data-testid": name, defaultValue: value, onChange: (e) => {
1893
+ if (props.onChange) {
1894
+ props.onChange(e.currentTarget.value);
1895
+ }
1896
+ }, error: getErrorsForInput(props.outcome, name) }));
2243
1897
  case core.PropertyType.date:
2244
- return (React__default["default"].createElement(Input, { type: "date", name: name, testid: name, defaultValue: value, onChange: props.onChange, outcome: props.outcome }));
1898
+ return (React__default["default"].createElement(core$1.TextInput, { type: "date", id: name, name: name, "data-testid": name, defaultValue: value, onChange: (e) => {
1899
+ if (props.onChange) {
1900
+ props.onChange(e.currentTarget.value);
1901
+ }
1902
+ }, error: getErrorsForInput(props.outcome, name) }));
2245
1903
  case core.PropertyType.dateTime:
2246
1904
  case core.PropertyType.instant:
2247
- return (React__default["default"].createElement(DateTimeInput, { type: "datetime-local", name: name, testid: name, defaultValue: value, onChange: props.onChange, outcome: props.outcome }));
1905
+ return React__default["default"].createElement(DateTimeInput, { name: name, defaultValue: value, onChange: props.onChange, outcome: props.outcome });
2248
1906
  case core.PropertyType.decimal:
2249
1907
  case core.PropertyType.integer:
2250
1908
  case core.PropertyType.positiveInt:
2251
1909
  case core.PropertyType.unsignedInt:
2252
- return (React__default["default"].createElement(Input, { type: "number", step: propertyType === core.PropertyType.decimal ? 'any' : 1, name: name, testid: name, defaultValue: value, onChange: (newValue) => {
1910
+ return (React__default["default"].createElement(core$1.TextInput, { type: "number", step: propertyType === core.PropertyType.decimal ? 'any' : '1', id: name, name: name, "data-testid": name, defaultValue: value, onChange: (e) => {
2253
1911
  if (props.onChange) {
2254
- props.onChange(parseFloat(newValue));
1912
+ props.onChange(e.currentTarget.valueAsNumber);
2255
1913
  }
2256
- }, outcome: props.outcome }));
1914
+ } }));
2257
1915
  case core.PropertyType.code:
2258
1916
  return React__default["default"].createElement(CodeInput, { property: property, name: name, defaultValue: value, onChange: props.onChange });
2259
1917
  case core.PropertyType.boolean:
2260
- return (React__default["default"].createElement(Checkbox, { name: name, testid: name, defaultValue: !!value, onChange: (newValue) => {
1918
+ return (React__default["default"].createElement(core$1.Checkbox, { id: name, name: name, "data-testid": name, defaultChecked: !!value, onChange: (e) => {
2261
1919
  if (props.onChange) {
2262
- props.onChange(newValue);
1920
+ props.onChange(e.currentTarget.checked);
2263
1921
  }
2264
1922
  } }));
2265
1923
  case core.PropertyType.markdown:
2266
- return React__default["default"].createElement(TextArea, { name: name, testid: name, defaultValue: value, onChange: props.onChange });
1924
+ return (React__default["default"].createElement(core$1.Textarea, { id: name, name: name, "data-testid": name, defaultValue: value, onChange: (e) => {
1925
+ if (props.onChange) {
1926
+ props.onChange(e.currentTarget.value);
1927
+ }
1928
+ } }));
2267
1929
  // 2.24.0.2 Complex Types
2268
1930
  // https://www.hl7.org/fhir/datatypes.html#complex
2269
1931
  case core.PropertyType.Address:
@@ -2347,10 +2009,18 @@
2347
2009
  })));
2348
2010
  }
2349
2011
 
2012
+ function ResourceName(props) {
2013
+ const resource = useResource(props.value);
2014
+ if (!resource) {
2015
+ return null;
2016
+ }
2017
+ const text = core.getDisplayString(resource);
2018
+ return props.link ? React__default["default"].createElement(MedplumLink, { to: resource }, text) : React__default["default"].createElement("span", null, text);
2019
+ }
2020
+
2350
2021
  function ResourceBadge(props) {
2351
- var _a;
2352
2022
  return (React__default["default"].createElement("div", { className: "medplum-resource-badge" },
2353
- React__default["default"].createElement(Avatar, { size: (_a = props.size) !== null && _a !== void 0 ? _a : 'small', value: props.value, link: props.link }),
2023
+ React__default["default"].createElement(ResourceAvatar, { size: 24, radius: 12, value: props.value, link: props.link }),
2354
2024
  React__default["default"].createElement(ResourceName, { value: props.value, link: props.link })));
2355
2025
  }
2356
2026
 
@@ -2396,7 +2066,7 @@
2396
2066
  }
2397
2067
  function ObservationTable(props) {
2398
2068
  var _a;
2399
- return (React__default["default"].createElement("table", { className: "medplum-table" },
2069
+ return (React__default["default"].createElement(core$1.Table, { withBorder: true, withColumnBorders: true },
2400
2070
  React__default["default"].createElement("thead", null,
2401
2071
  React__default["default"].createElement("tr", null,
2402
2072
  React__default["default"].createElement("th", null, "Test"),
@@ -2410,7 +2080,11 @@
2410
2080
  if (!observation) {
2411
2081
  return null;
2412
2082
  }
2413
- return (React__default["default"].createElement("tr", null,
2083
+ let className = undefined;
2084
+ if (isCritical(observation)) {
2085
+ className = 'medplum-critical';
2086
+ }
2087
+ return (React__default["default"].createElement("tr", { className: className },
2414
2088
  React__default["default"].createElement("td", null,
2415
2089
  React__default["default"].createElement(MedplumLink, { to: observation },
2416
2090
  React__default["default"].createElement(CodeableConceptDisplay, { value: observation.code }))),
@@ -2441,18 +2115,21 @@
2441
2115
  if (!range) {
2442
2116
  return null;
2443
2117
  }
2118
+ if (range.text) {
2119
+ return React__default["default"].createElement(React__default["default"].Fragment, null, range.text);
2120
+ }
2444
2121
  return React__default["default"].createElement(RangeDisplay, { value: range });
2445
2122
  }
2446
-
2447
- function Loading() {
2448
- return (React__default["default"].createElement("div", { role: "progressbar", "aria-busy": "true", className: "medplum-loading" },
2449
- React__default["default"].createElement("div", { className: "medplum-loading-container" },
2450
- React__default["default"].createElement("svg", { className: "medplum-loading-spinner", viewBox: "0 0 100 100" },
2451
- React__default["default"].createElement("circle", { cx: "50", cy: "50", r: "40" })))));
2452
- }
2453
-
2454
- function MenuItem(props) {
2455
- return (React__default["default"].createElement("div", { className: "medplum-menu-item", onClick: () => props.onClick(), "aria-label": props.label }, props.children));
2123
+ /**
2124
+ * Returns true if the observation is critical.
2125
+ * See: https://www.hl7.org/fhir/valueset-observation-interpretation.html
2126
+ * @param observation The FHIR observation.
2127
+ * @returns True if the FHIR observation is a critical value.
2128
+ */
2129
+ function isCritical(observation) {
2130
+ var _a, _b, _c, _d;
2131
+ const code = (_d = (_c = (_b = (_a = observation.interpretation) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.coding) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.code;
2132
+ return code === 'AA' || code === 'LL' || code === 'HH' || code === 'RR';
2456
2133
  }
2457
2134
 
2458
2135
  function ResourceDiffTable(props) {
@@ -2521,14 +2198,6 @@
2521
2198
  return (React__default["default"].createElement(BackboneElementDisplay, { value: { type: value.resourceType, value }, ignoreMissingValues: props.ignoreMissingValues }));
2522
2199
  }
2523
2200
 
2524
- function Scrollable(props) {
2525
- const containerHeight = props.height || '100%';
2526
- const contentHeight = props.height ? props.height + 25 : '100%';
2527
- const className = 'medplum-scrollable-content' + (props.className ? ` ${props.className}` : '');
2528
- return (React__default["default"].createElement("div", { className: "medplum-scrollable-container", style: { height: containerHeight } },
2529
- React__default["default"].createElement("div", { className: className, role: props.role, style: { height: contentHeight } }, props.children)));
2530
- }
2531
-
2532
2201
  /**
2533
2202
  * ErrorBoundary is a React component that handles errors in its child components.
2534
2203
  * See: https://reactjs.org/docs/error-boundaries.html
@@ -2552,112 +2221,33 @@
2552
2221
  }
2553
2222
  }
2554
2223
 
2555
- function Popup(props) {
2556
- const ref = React.useRef(null);
2557
- // Track browser URL location, and the location when the popup becomes visible
2558
- const location = reactRouterDom.useLocation();
2559
- const locationRef = React.useRef();
2560
- if (props.visible) {
2561
- if (locationRef.current === undefined) {
2562
- locationRef.current = location;
2563
- }
2564
- }
2565
- else {
2566
- locationRef.current = undefined;
2567
- }
2568
- const propsRef = React.useRef();
2569
- propsRef.current = props;
2570
- // Listen for clicks outside of the popup
2571
- // If the user clicks outside of the popup, close it
2572
- React.useEffect(() => {
2573
- function handleClick(e) {
2574
- var _a, _b;
2575
- if (((_a = propsRef.current) === null || _a === void 0 ? void 0 : _a.visible) &&
2576
- ((_b = propsRef.current) === null || _b === void 0 ? void 0 : _b.autoClose) &&
2577
- (ref === null || ref === void 0 ? void 0 : ref.current) &&
2578
- !ref.current.contains(e.target)) {
2579
- killEvent(e);
2580
- props.onClose();
2581
- }
2582
- }
2583
- function handleScroll(e) {
2584
- var _a;
2585
- if ((_a = propsRef.current) === null || _a === void 0 ? void 0 : _a.visible) {
2586
- killEvent(e);
2587
- }
2588
- }
2589
- document.addEventListener('click', handleClick, true);
2590
- window.addEventListener('wheel', handleScroll, { passive: false });
2591
- window.addEventListener('touchmove', handleScroll, true);
2592
- return () => {
2593
- document.removeEventListener('click', handleClick, true);
2594
- window.removeEventListener('wheel', handleScroll);
2595
- window.removeEventListener('touchmove', handleScroll, true);
2596
- };
2597
- }, [props]);
2598
- // Listen for changes in the location
2599
- // If the browser navigates to a new page, close the popup
2600
- React.useEffect(() => {
2601
- if (props.visible && location !== locationRef.current) {
2602
- props.onClose();
2603
- }
2604
- }, [location, props]);
2605
- const style = {
2606
- display: props.visible ? 'block' : 'none',
2607
- };
2608
- if (props.anchor) {
2609
- if (props.anchor.right + 250 < document.body.clientWidth) {
2610
- style.left = props.anchor.right + 'px';
2611
- }
2612
- else {
2613
- style.right = document.body.clientWidth - props.anchor.left + 'px';
2614
- }
2615
- if (props.anchor.top + 300 < document.body.clientHeight) {
2616
- style.top = props.anchor.top + 'px';
2617
- }
2618
- else {
2619
- style.bottom = document.body.clientHeight - props.anchor.top + 'px';
2620
- }
2621
- }
2622
- return (React__default["default"].createElement(React__default["default"].Fragment, null,
2623
- props.modal && (React__default["default"].createElement("div", { className: props.visible ? 'medplum-backdrop active' : 'medplum-backdrop', onClick: props.onClose })),
2624
- React__default["default"].createElement("div", { ref: ref, className: 'medplum-popup ' + (props.visible ? props.activeClassName : props.inactiveClassName), style: style, "data-testid": "popup" }, props.children)));
2625
- }
2626
-
2627
2224
  function Timeline(props) {
2628
2225
  return React__default["default"].createElement("main", { className: "medplum-document medplum-timeline" }, props.children);
2629
2226
  }
2630
2227
  function TimelineItem(props) {
2631
2228
  var _a, _b, _c;
2632
- const [popupAnchor, setPopupAnchor] = React.useState();
2633
2229
  const author = (_a = props.profile) !== null && _a !== void 0 ? _a : (_b = props.resource.meta) === null || _b === void 0 ? void 0 : _b.author;
2634
2230
  return (React__default["default"].createElement("article", { className: props.className || 'medplum-timeline-item', "data-testid": "timeline-item" },
2635
2231
  React__default["default"].createElement("div", { className: "medplum-timeline-item-header" },
2636
2232
  React__default["default"].createElement("div", { className: "medplum-timeline-item-avatar" },
2637
- React__default["default"].createElement(Avatar, { value: author, link: true, size: "medium" })),
2233
+ React__default["default"].createElement(ResourceAvatar, { value: author, link: true, size: "md" })),
2638
2234
  React__default["default"].createElement("div", { className: "medplum-timeline-item-title" },
2639
2235
  React__default["default"].createElement(ResourceName, { value: author, link: true }),
2640
2236
  React__default["default"].createElement("div", { className: "medplum-timeline-item-subtitle" },
2641
2237
  React__default["default"].createElement(MedplumLink, { to: props.resource }, core.formatDateTime((_c = props.resource.meta) === null || _c === void 0 ? void 0 : _c.lastUpdated)),
2642
2238
  React__default["default"].createElement("span", null, "\u00B7"),
2643
2239
  React__default["default"].createElement(MedplumLink, { to: props.resource }, props.resource.resourceType))),
2644
- props.popupMenuItems && (React__default["default"].createElement("div", { className: "medplum-timeline-item-actions" },
2645
- React__default["default"].createElement("a", { href: "#", "aria-label": `Actions for ${core.getReferenceString(props.resource)}`, onClick: (e) => {
2646
- killEvent(e);
2647
- const el = e.currentTarget;
2648
- const rect = el.getBoundingClientRect();
2649
- setPopupAnchor(rect);
2650
- } },
2651
- React__default["default"].createElement("svg", { fill: "currentColor", viewBox: "0 0 20 20" },
2652
- React__default["default"].createElement("g", { transform: "translate(-446 -350)" },
2653
- React__default["default"].createElement("path", { d: "M458 360a2 2 0 1 1-4 0 2 2 0 0 1 4 0m6 0a2 2 0 1 1-4 0 2 2 0 0 1 4 0m-12 0a2 2 0 1 1-4 0 2 2 0 0 1 4 0" }))))))),
2240
+ props.popupMenuItems && (React__default["default"].createElement(core$1.Menu, { position: "bottom-end", shadow: "md", width: 200 },
2241
+ React__default["default"].createElement(core$1.Menu.Target, null,
2242
+ React__default["default"].createElement(core$1.ActionIcon, { radius: "xl", "aria-label": `Actions for ${core.getReferenceString(props.resource)}` },
2243
+ React__default["default"].createElement(icons.IconDots, null))),
2244
+ props.popupMenuItems))),
2654
2245
  React__default["default"].createElement(ErrorBoundary, null,
2655
2246
  props.padding && React__default["default"].createElement("div", { style: { padding: '2px 16px 16px 16px' } }, props.children),
2656
2247
  !props.padding && React__default["default"].createElement(React__default["default"].Fragment, null, props.children)),
2657
2248
  props.socialEnabled && (React__default["default"].createElement("div", { className: "medplum-timeline-item-footer" },
2658
- React__default["default"].createElement(Button, { borderless: true }, "Like"),
2659
- React__default["default"].createElement(Button, { borderless: true }, "Comment"))),
2660
- props.popupMenuItems && (React__default["default"].createElement(Popup, { visible: !!popupAnchor, anchor: popupAnchor, autoClose: true, onClose: () => setPopupAnchor(undefined) }, props.popupMenuItems))));
2249
+ React__default["default"].createElement(core$1.Button, { variant: "subtle" }, "Like"),
2250
+ React__default["default"].createElement(core$1.Button, { variant: "subtle" }, "Comment")))));
2661
2251
  }
2662
2252
 
2663
2253
  /**
@@ -2822,7 +2412,7 @@
2822
2412
  navigate(`/${version.resourceType}/${version.id}/_history/${(_a = version.meta) === null || _a === void 0 ? void 0 : _a.versionId}`);
2823
2413
  }
2824
2414
  if (!resource || !history) {
2825
- return React__default["default"].createElement(Loading, null);
2415
+ return React__default["default"].createElement(core$1.Loader, null);
2826
2416
  }
2827
2417
  return (React__default["default"].createElement(Timeline, null,
2828
2418
  props.createCommunication && (React__default["default"].createElement("article", { className: "medplum-timeline-item" },
@@ -2835,9 +2425,13 @@
2835
2425
  input.focus();
2836
2426
  }
2837
2427
  } },
2838
- React__default["default"].createElement(Input, { name: "text", testid: "timeline-input", inputRef: inputRef }),
2839
- React__default["default"].createElement(Button, { type: "submit" }, "Comment"),
2840
- React__default["default"].createElement(UploadButton, { onUpload: createMedia }))))),
2428
+ React__default["default"].createElement(core$1.Group, { spacing: "xs", noWrap: true, style: { width: '100%' } },
2429
+ React__default["default"].createElement(ResourceAvatar, { value: sender }),
2430
+ React__default["default"].createElement(core$1.TextInput, { name: "text", ref: inputRef, placeholder: "Add comment", style: { width: '100%', maxWidth: 300 } }),
2431
+ React__default["default"].createElement(core$1.ActionIcon, { type: "submit", radius: "xl", color: "blue", variant: "filled" },
2432
+ React__default["default"].createElement(icons.IconMessage, { size: 16 })),
2433
+ React__default["default"].createElement(AttachmentButton, { onUpload: createMedia }, (props) => (React__default["default"].createElement(core$1.ActionIcon, Object.assign({}, props, { radius: "xl", color: "blue", variant: "filled" }),
2434
+ React__default["default"].createElement(icons.IconCloudUpload, { size: 16 }))))))))),
2841
2435
  items.map((item) => {
2842
2436
  var _a;
2843
2437
  if (item.resourceType === resource.resourceType && item.id === resource.id) {
@@ -2860,12 +2454,16 @@
2860
2454
  })));
2861
2455
  }
2862
2456
  function TimelineItemPopupMenu(props) {
2863
- return (React__default["default"].createElement(React__default["default"].Fragment, null,
2864
- props.onPin && (React__default["default"].createElement(MenuItem, { onClick: () => props.onPin(props.resource), label: `Pin ${core.getReferenceString(props.resource)}` }, "Pin")),
2865
- props.onUnpin && (React__default["default"].createElement(MenuItem, { onClick: () => props.onUnpin(props.resource), label: `Unpin ${core.getReferenceString(props.resource)}` }, "Unpin")),
2866
- props.onDetails && (React__default["default"].createElement(MenuItem, { onClick: () => props.onDetails(props.resource), label: `Details ${core.getReferenceString(props.resource)}` }, "Details")),
2867
- props.onEdit && (React__default["default"].createElement(MenuItem, { onClick: () => props.onEdit(props.resource), label: `Edit ${core.getReferenceString(props.resource)}` }, "Edit")),
2868
- props.onDelete && (React__default["default"].createElement(MenuItem, { onClick: () => props.onDelete(props.resource), label: `Delete ${core.getReferenceString(props.resource)}` }, "Delete"))));
2457
+ return (React__default["default"].createElement(core$1.Menu.Dropdown, null,
2458
+ React__default["default"].createElement(core$1.Menu.Label, null, "Resource"),
2459
+ props.onPin && (React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconPin, { size: 14 }), onClick: () => props.onPin(props.resource), "aria-label": `Pin ${core.getReferenceString(props.resource)}` }, "Pin")),
2460
+ props.onUnpin && (React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconPinnedOff, { size: 14 }), onClick: () => props.onUnpin(props.resource), "aria-label": `Unpin ${core.getReferenceString(props.resource)}` }, "Unpin")),
2461
+ props.onDetails && (React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconListDetails, { size: 14 }), onClick: () => props.onDetails(props.resource), "aria-label": `Details ${core.getReferenceString(props.resource)}` }, "Details")),
2462
+ props.onEdit && (React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconEdit, { size: 14 }), onClick: () => props.onEdit(props.resource), "aria-label": `Edit ${core.getReferenceString(props.resource)}` }, "Edit")),
2463
+ props.onDelete && (React__default["default"].createElement(React__default["default"].Fragment, null,
2464
+ React__default["default"].createElement(core$1.Menu.Divider, null),
2465
+ React__default["default"].createElement(core$1.Menu.Label, null, "Danger zone"),
2466
+ React__default["default"].createElement(core$1.Menu.Item, { color: "red", icon: React__default["default"].createElement(icons.IconTrash, { size: 14 }), onClick: () => props.onDelete(props.resource), "aria-label": `Delete ${core.getReferenceString(props.resource)}` }, "Delete")))));
2869
2467
  }
2870
2468
  function HistoryTimelineItem(props) {
2871
2469
  const previous = getPrevious(props.history, props.resource);
@@ -2906,7 +2504,7 @@
2906
2504
  }
2907
2505
  function AuditEventTimelineItem(props) {
2908
2506
  return (React__default["default"].createElement(TimelineItem, { resource: props.resource, padding: true, popupMenuItems: React__default["default"].createElement(TimelineItemPopupMenu, Object.assign({}, props)) },
2909
- React__default["default"].createElement(Scrollable, null,
2507
+ React__default["default"].createElement(core$1.ScrollArea, null,
2910
2508
  React__default["default"].createElement("pre", null, props.resource.outcomeDesc))));
2911
2509
  }
2912
2510
  function DiagnosticReportTimelineItem(props) {
@@ -2961,6 +2559,7 @@
2961
2559
  ],
2962
2560
  }), createCommunication: (resource, sender, text) => ({
2963
2561
  resourceType: 'Communication',
2562
+ status: 'completed',
2964
2563
  encounter: core.createReference(resource),
2965
2564
  subject: resource.subject,
2966
2565
  sender: core.createReference(sender),
@@ -2968,6 +2567,7 @@
2968
2567
  payload: [{ contentString: text }],
2969
2568
  }), createMedia: (resource, operator, content) => ({
2970
2569
  resourceType: 'Media',
2570
+ status: 'completed',
2971
2571
  encounter: core.createReference(resource),
2972
2572
  subject: resource.subject,
2973
2573
  operator: core.createReference(operator),
@@ -3396,17 +2996,16 @@
3396
2996
  return Object.assign(Object.assign({}, definition), { offset, name: undefined });
3397
2997
  }
3398
2998
  /**
3399
- * Moves the page forward or backward.
3400
- *
3401
- * @param {number} delta The delta to the page number.
3402
- * @return {boolean} True if the page actually moved; false otherwise.
2999
+ * Creates a new search request with the search offset at the specified page.
3000
+ * @param definition The search definition.
3001
+ * @param page The new page number
3002
+ * @return The new search definition.
3403
3003
  */
3404
- function movePage(definition, delta) {
3405
- var _a, _b;
3406
- const count = (_a = definition.count) !== null && _a !== void 0 ? _a : 20;
3407
- const currOffset = (_b = definition.offset) !== null && _b !== void 0 ? _b : 0;
3408
- const newOffset = currOffset + delta * count;
3409
- return setOffset(definition, Math.max(newOffset, 0));
3004
+ function setPage(definition, page) {
3005
+ var _a;
3006
+ const count = (_a = definition.count) !== null && _a !== void 0 ? _a : core.DEFAULT_SEARCH_COUNT;
3007
+ const newOffset = (page - 1) * count;
3008
+ return setOffset(definition, newOffset);
3410
3009
  }
3411
3010
  /**
3412
3011
  * Sorts the search by the specified key, and optional direction.
@@ -3697,7 +3296,7 @@
3697
3296
  const available = getFieldsList(typeDef)
3698
3297
  .filter((field) => !(selected === null || selected === void 0 ? void 0 : selected.includes(field)))
3699
3298
  .sort();
3700
- return (React__default["default"].createElement(Dialog, { title: "Fields", visible: props.visible, onOk: () => props.onOk(state.search), onCancel: props.onCancel },
3299
+ return (React__default["default"].createElement(core$1.Modal, { title: "Fields", closeButtonLabel: "Close", opened: props.visible, onClose: props.onCancel },
3701
3300
  React__default["default"].createElement("div", null,
3702
3301
  React__default["default"].createElement("table", { style: { margin: 'auto' } },
3703
3302
  React__default["default"].createElement("thead", null,
@@ -3713,13 +3312,14 @@
3713
3312
  React__default["default"].createElement("tfoot", null,
3714
3313
  React__default["default"].createElement("tr", null,
3715
3314
  React__default["default"].createElement("td", { align: "center" },
3716
- React__default["default"].createElement(Button, { size: "small", onClick: onAddField }, "Add")),
3315
+ React__default["default"].createElement(core$1.Button, { compact: true, variant: "outline", onClick: onAddField }, "Add")),
3717
3316
  React__default["default"].createElement("td", { align: "center" },
3718
- React__default["default"].createElement(Button, { size: "small", onClick: onRemoveField }, "Remove")),
3317
+ React__default["default"].createElement(core$1.Button, { compact: true, variant: "outline", onClick: onRemoveField }, "Remove")),
3719
3318
  React__default["default"].createElement("td", { align: "center" },
3720
- React__default["default"].createElement(Button, { size: "small", onClick: onMoveUp }, "Up")),
3319
+ React__default["default"].createElement(core$1.Button, { compact: true, variant: "outline", onClick: onMoveUp }, "Up")),
3721
3320
  React__default["default"].createElement("td", { align: "center" },
3722
- React__default["default"].createElement(Button, { size: "small", onClick: onMoveDown }, "Down"))))))));
3321
+ React__default["default"].createElement(core$1.Button, { compact: true, variant: "outline", onClick: onMoveDown }, "Down")))))),
3322
+ React__default["default"].createElement(core$1.Button, { onClick: () => props.onOk(state.search) }, "OK")));
3723
3323
  }
3724
3324
  /**
3725
3325
  * Returns a list of fields/columns available for a type.
@@ -3781,13 +3381,13 @@
3781
3381
  }
3782
3382
  } }));
3783
3383
  case core.SearchParameterType.BOOLEAN:
3784
- return (React__default["default"].createElement(Checkbox, { name: name, testid: name, defaultValue: props.defaultValue === 'true', onChange: (newValue) => props.onChange(newValue.toString()) }));
3384
+ return (React__default["default"].createElement(core$1.Checkbox, { name: name, "data-testid": name, defaultChecked: props.defaultValue === 'true', onChange: (e) => props.onChange(e.currentTarget.checked.toString()) }));
3785
3385
  case core.SearchParameterType.DATE:
3786
- return React__default["default"].createElement(Input, { type: "date", testid: name, defaultValue: props.defaultValue, onChange: props.onChange });
3386
+ return (React__default["default"].createElement(core$1.TextInput, { type: "date", name: name, "data-testid": name, defaultValue: props.defaultValue, onChange: (e) => props.onChange(e.currentTarget.value) }));
3787
3387
  case core.SearchParameterType.DATETIME:
3788
- return React__default["default"].createElement(DateTimeInput, { testid: name, defaultValue: props.defaultValue, onChange: props.onChange });
3388
+ return React__default["default"].createElement(DateTimeInput, { name: name, defaultValue: props.defaultValue, onChange: props.onChange });
3789
3389
  case core.SearchParameterType.NUMBER:
3790
- return React__default["default"].createElement(Input, { type: "number", defaultValue: props.defaultValue, onChange: props.onChange });
3390
+ return (React__default["default"].createElement(core$1.TextInput, { type: "number", name: name, "data-testid": name, defaultValue: props.defaultValue, onChange: (e) => props.onChange(e.currentTarget.value) }));
3791
3391
  case core.SearchParameterType.QUANTITY:
3792
3392
  return (React__default["default"].createElement(QuantityInput, { name: name, defaultValue: tryParseQuantity(props.defaultValue), onChange: (newQuantity) => {
3793
3393
  if (newQuantity) {
@@ -3798,7 +3398,7 @@
3798
3398
  }
3799
3399
  } }));
3800
3400
  default:
3801
- return (React__default["default"].createElement(Input, { testid: name, defaultValue: props.defaultValue, autoFocus: props.autoFocus, onChange: props.onChange }));
3401
+ return (React__default["default"].createElement(core$1.TextInput, { name: name, "data-testid": name, defaultValue: props.defaultValue, autoFocus: props.autoFocus, onChange: (e) => props.onChange(e.currentTarget.value), placeholder: "Search value" }));
3802
3402
  }
3803
3403
  }
3804
3404
  function tryParseQuantity(value) {
@@ -3832,7 +3432,7 @@
3832
3432
  const resourceType = props.search.resourceType;
3833
3433
  const searchParams = core.globalSchema.types[resourceType].searchParams;
3834
3434
  const filters = search.filters || [];
3835
- return (React__default["default"].createElement(Dialog, { title: "Filters", visible: props.visible, onOk: () => props.onOk(searchRef.current), onCancel: props.onCancel },
3435
+ return (React__default["default"].createElement(core$1.Modal, { title: "Filters", closeButtonLabel: "Close", size: 900, opened: props.visible, onClose: props.onCancel },
3836
3436
  React__default["default"].createElement("div", { className: "medplum-filter-editor" },
3837
3437
  React__default["default"].createElement("table", { className: "medplum-filter-editor-table" },
3838
3438
  React__default["default"].createElement("colgroup", null,
@@ -3860,7 +3460,9 @@
3860
3460
  return (React__default["default"].createElement(FilterRowDisplay, { key: `filter-${index}-${filters.length}-display`, resourceType: resourceType, searchParams: searchParams, filter: filter, onEdit: () => setEditingIndex(index), onDelete: () => setSearch(deleteFilter(searchRef.current, index)) }));
3861
3461
  }
3862
3462
  }),
3863
- React__default["default"].createElement(FilterRowInput, { resourceType: resourceType, searchParams: searchParams, okText: "Add", onOk: onAddFilter }))))));
3463
+ React__default["default"].createElement(FilterRowInput, { resourceType: resourceType, searchParams: searchParams, okText: "Add", onOk: onAddFilter })))),
3464
+ React__default["default"].createElement(core$1.Group, { position: "right", mt: "xl" },
3465
+ React__default["default"].createElement(core$1.Button, { onClick: () => props.onOk(searchRef.current) }, "OK"))));
3864
3466
  }
3865
3467
  function FilterRowDisplay(props) {
3866
3468
  const { filter } = props;
@@ -3870,8 +3472,8 @@
3870
3472
  React__default["default"].createElement("td", null,
3871
3473
  React__default["default"].createElement(SearchFilterValueDisplay, { resourceType: props.resourceType, filter: filter })),
3872
3474
  React__default["default"].createElement("td", null,
3873
- React__default["default"].createElement(Button, { size: "small", onClick: props.onEdit }, "Edit"),
3874
- React__default["default"].createElement(Button, { size: "small", onClick: props.onDelete }, "Delete"))));
3475
+ React__default["default"].createElement(core$1.Button, { compact: true, variant: "outline", onClick: props.onEdit }, "Edit"),
3476
+ React__default["default"].createElement(core$1.Button, { compact: true, variant: "outline", onClick: props.onDelete }, "Delete"))));
3875
3477
  }
3876
3478
  function FilterRowInput(props) {
3877
3479
  var _a;
@@ -3891,19 +3493,15 @@
3891
3493
  const operators = searchParam && getSearchOperators(searchParam);
3892
3494
  return (React__default["default"].createElement("tr", null,
3893
3495
  React__default["default"].createElement("td", null,
3894
- React__default["default"].createElement(Select, { testid: "filter-field", defaultValue: valueRef.current.code, onChange: setFilterCode },
3895
- React__default["default"].createElement("option", { value: "" }),
3896
- Object.keys(props.searchParams).map((param) => (React__default["default"].createElement("option", { key: param, value: param }, buildFieldNameString(param)))))),
3897
- React__default["default"].createElement("td", null, operators && (React__default["default"].createElement(Select, { testid: "filter-operation", defaultValue: value.operator, onChange: setFilterOperator },
3898
- React__default["default"].createElement("option", { value: "" }),
3899
- operators.map((operator) => (React__default["default"].createElement("option", { key: operator, value: operator }, getOpString(operator))))))),
3496
+ React__default["default"].createElement(core$1.NativeSelect, { "data-testid": "filter-field", defaultValue: valueRef.current.code, onChange: (e) => setFilterCode(e.currentTarget.value), data: Object.keys(props.searchParams).map((param) => ({ value: param, label: buildFieldNameString(param) })) })),
3497
+ React__default["default"].createElement("td", null, operators && (React__default["default"].createElement(core$1.NativeSelect, { "data-testid": "filter-operation", defaultValue: value.operator, onChange: (e) => setFilterOperator(e.currentTarget.value), data: ['', ...operators.map((op) => ({ value: op, label: getOpString(op) }))] }))),
3900
3498
  React__default["default"].createElement("td", null, searchParam && value.operator && (React__default["default"].createElement(SearchFilterValueInput, { resourceType: props.resourceType, searchParam: searchParam, defaultValue: value.value, onChange: setFilterValue }))),
3901
3499
  React__default["default"].createElement("td", null,
3902
- value.code && value.operator && value.value && (React__default["default"].createElement(Button, { size: "small", onClick: () => {
3500
+ value.code && value.operator && value.value && (React__default["default"].createElement(core$1.Button, { compact: true, variant: "outline", onClick: () => {
3903
3501
  props.onOk(valueRef.current);
3904
3502
  setValue({});
3905
3503
  } }, props.okText)),
3906
- props.onCancel && (React__default["default"].createElement(Button, { size: "small", onClick: props.onCancel }, "Cancel")))));
3504
+ props.onCancel && (React__default["default"].createElement(core$1.Button, { compact: true, variant: "outline", onClick: props.onCancel }, "Cancel")))));
3907
3505
  }
3908
3506
 
3909
3507
  function SearchFilterValueDialog(props) {
@@ -3915,47 +3513,11 @@
3915
3513
  function onOk() {
3916
3514
  props.onOk(Object.assign(Object.assign({}, props.filter), { value }));
3917
3515
  }
3918
- return (React__default["default"].createElement(Dialog, { title: props.title, visible: props.visible, onOk: onOk, onCancel: props.onCancel },
3516
+ return (React__default["default"].createElement(core$1.Modal, { title: props.title, size: "xl", opened: props.visible, onClose: props.onCancel },
3919
3517
  React__default["default"].createElement("div", { style: { width: 500 } },
3920
3518
  React__default["default"].createElement(Form, { onSubmit: onOk },
3921
- React__default["default"].createElement(SearchFilterValueInput, { resourceType: props.resourceType, searchParam: props.searchParam, defaultValue: value, autoFocus: true, onChange: setValue })))));
3922
- }
3923
-
3924
- function MenuSeparator() {
3925
- return React__default["default"].createElement("div", { className: "medplum-menu-separator" });
3926
- }
3927
-
3928
- function SubMenu(props) {
3929
- const [hover, setHover] = React.useState(false);
3930
- const [visible, setVisible] = React.useState(false);
3931
- const [anchor, setAnchor] = React.useState(undefined);
3932
- const menuItemRef = React.useRef(null);
3933
- const hoverRef = React.useRef(false);
3934
- hoverRef.current = hover;
3935
- const visibleRef = React.useRef(false);
3936
- visibleRef.current = visible;
3937
- function show() {
3938
- const el = menuItemRef.current;
3939
- if (el) {
3940
- setAnchor(el.getBoundingClientRect());
3941
- setVisible(true);
3942
- }
3943
- }
3944
- React.useEffect(() => {
3945
- const timerId = window.setInterval(() => {
3946
- if (!visibleRef.current && hoverRef.current) {
3947
- show();
3948
- }
3949
- else if (visibleRef.current && !hoverRef.current) {
3950
- setVisible(false);
3951
- }
3952
- }, 150);
3953
- return () => window.clearInterval(timerId);
3954
- }, []);
3955
- return (React__default["default"].createElement("div", { ref: menuItemRef, className: "medplum-menu-item medplum-submenu-item", onClick: () => show(), onMouseOver: () => setHover(true), onMouseLeave: () => setHover(false) },
3956
- props.title,
3957
- React__default["default"].createElement("span", { className: "medplum-submenu-arrow" }, '\u25BA'),
3958
- React__default["default"].createElement(Popup, { visible: visible, anchor: anchor, autoClose: true, onClose: () => setVisible(false) }, props.children)));
3519
+ React__default["default"].createElement(SearchFilterValueInput, { resourceType: props.resourceType, searchParam: props.searchParam, defaultValue: value, autoFocus: true, onChange: setValue }))),
3520
+ React__default["default"].createElement(core$1.Button, { onClick: onOk }, "OK")));
3959
3521
  }
3960
3522
 
3961
3523
  function SearchPopupMenu(props) {
@@ -3974,15 +3536,12 @@
3974
3536
  function onChange(definition) {
3975
3537
  props.onChange(definition);
3976
3538
  }
3977
- const anchor = { left: props.x, right: props.x, top: props.y, bottom: props.y };
3978
3539
  // If there is only one search parameter, then show it directly
3979
3540
  if (props.searchParams.length === 1) {
3980
- return (React__default["default"].createElement(Popup, { visible: props.visible, anchor: anchor, autoClose: true, onClose: props.onClose },
3981
- React__default["default"].createElement(SearchParameterSubMenu, { search: props.search, searchParam: props.searchParams[0], onSort: onSort, onPrompt: onPrompt, onChange: onChange, onClear: onClear })));
3541
+ return (React__default["default"].createElement(SearchParameterSubMenu, { search: props.search, searchParam: props.searchParams[0], onSort: onSort, onPrompt: onPrompt, onChange: onChange, onClear: onClear }));
3982
3542
  }
3983
3543
  // Otherwise, show a menu, with each search parameter as a sub menu
3984
- return (React__default["default"].createElement(Popup, { visible: props.visible, anchor: anchor, autoClose: true, onClose: props.onClose }, props.searchParams.map((searchParam) => (React__default["default"].createElement(SubMenu, { key: searchParam.code, title: buildFieldNameString(searchParam.code) },
3985
- React__default["default"].createElement(SearchParameterSubMenu, { search: props.search, searchParam: searchParam, onSort: onSort, onPrompt: onPrompt, onChange: onChange, onClear: onClear }))))));
3544
+ return (React__default["default"].createElement(core$1.Menu.Dropdown, null, props.searchParams.map((searchParam) => (React__default["default"].createElement(core$1.Menu.Item, { key: searchParam.code }, buildFieldNameString(searchParam.code))))));
3986
3545
  }
3987
3546
  function SearchParameterSubMenu(props) {
3988
3547
  switch (props.searchParam.type) {
@@ -4006,85 +3565,72 @@
4006
3565
  function DateFilterSubMenu(props) {
4007
3566
  const { searchParam } = props;
4008
3567
  const code = searchParam.code;
4009
- return (React__default["default"].createElement(React__default["default"].Fragment, null,
4010
- React__default["default"].createElement(MenuItem, { onClick: () => props.onSort(searchParam, false) }, "Sort Oldest to Newest"),
4011
- React__default["default"].createElement(MenuItem, { onClick: () => props.onSort(searchParam, true) }, "Sort Newest to Oldest"),
4012
- React__default["default"].createElement(MenuSeparator, null),
4013
- React__default["default"].createElement(MenuItem, { onClick: () => props.onPrompt(searchParam, core.Operator.EQUALS) }, "Equals..."),
4014
- React__default["default"].createElement(MenuItem, { onClick: () => props.onPrompt(searchParam, core.Operator.NOT_EQUALS) }, "Does not equal..."),
4015
- React__default["default"].createElement(MenuSeparator, null),
4016
- React__default["default"].createElement(MenuItem, { onClick: () => props.onPrompt(searchParam, core.Operator.ENDS_BEFORE) }, "Before..."),
4017
- React__default["default"].createElement(MenuItem, { onClick: () => props.onPrompt(searchParam, core.Operator.STARTS_AFTER) }, "After..."),
4018
- React__default["default"].createElement(MenuItem, { onClick: () => props.onPrompt(searchParam, core.Operator.EQUALS) }, "Between..."),
4019
- React__default["default"].createElement(MenuSeparator, null),
4020
- React__default["default"].createElement(MenuItem, { onClick: () => props.onChange(addTomorrowFilter(props.search, code)) }, "Tomorrow"),
4021
- React__default["default"].createElement(MenuItem, { onClick: () => props.onChange(addTodayFilter(props.search, code)) }, "Today"),
4022
- React__default["default"].createElement(MenuItem, { onClick: () => props.onChange(addYesterdayFilter(props.search, code)) }, "Yesterday"),
4023
- React__default["default"].createElement(MenuSeparator, null),
4024
- React__default["default"].createElement(MenuItem, { onClick: () => props.onChange(addNextMonthFilter(props.search, code)) }, "Next Month"),
4025
- React__default["default"].createElement(MenuItem, { onClick: () => props.onChange(addThisMonthFilter(props.search, code)) }, "This Month"),
4026
- React__default["default"].createElement(MenuItem, { onClick: () => props.onChange(addLastMonthFilter(props.search, code)) }, "Last Month"),
4027
- React__default["default"].createElement(MenuSeparator, null),
4028
- React__default["default"].createElement(MenuItem, { onClick: () => props.onChange(addYearToDateFilter(props.search, code)) }, "Year to date"),
4029
- React__default["default"].createElement(MenuSeparator, null),
4030
- React__default["default"].createElement(MenuItem, { onClick: () => props.onChange(addMissingFilter(props.search, code)) }, "Missing"),
4031
- React__default["default"].createElement(MenuItem, { onClick: () => props.onChange(addMissingFilter(props.search, code, false)) }, "Not missing"),
4032
- React__default["default"].createElement(MenuSeparator, null),
4033
- React__default["default"].createElement(MenuItem, { onClick: () => props.onClear(searchParam) }, "Clear filters")));
3568
+ return (React__default["default"].createElement(core$1.Menu.Dropdown, null,
3569
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconSortAscending, { size: 14 }), onClick: () => props.onSort(searchParam, false) }, "Sort Oldest to Newest"),
3570
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconSortDescending, { size: 14 }), onClick: () => props.onSort(searchParam, true) }, "Sort Newest to Oldest"),
3571
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3572
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconEqual, { size: 14 }), onClick: () => props.onPrompt(searchParam, core.Operator.EQUALS) }, "Equals..."),
3573
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconEqualNot, { size: 14 }), onClick: () => props.onPrompt(searchParam, core.Operator.NOT_EQUALS) }, "Does not equal..."),
3574
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3575
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconMathLower, { size: 14 }), onClick: () => props.onPrompt(searchParam, core.Operator.ENDS_BEFORE) }, "Before..."),
3576
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconMathGreater, { size: 14 }), onClick: () => props.onPrompt(searchParam, core.Operator.STARTS_AFTER) }, "After..."),
3577
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconBracketsContain, { size: 14 }), onClick: () => props.onPrompt(searchParam, core.Operator.EQUALS) }, "Between..."),
3578
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3579
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconCalendar, { size: 14 }), onClick: () => props.onChange(addTomorrowFilter(props.search, code)) }, "Tomorrow"),
3580
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconCalendar, { size: 14 }), onClick: () => props.onChange(addTodayFilter(props.search, code)) }, "Today"),
3581
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconCalendar, { size: 14 }), onClick: () => props.onChange(addYesterdayFilter(props.search, code)) }, "Yesterday"),
3582
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3583
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconCalendar, { size: 14 }), onClick: () => props.onChange(addNextMonthFilter(props.search, code)) }, "Next Month"),
3584
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconCalendar, { size: 14 }), onClick: () => props.onChange(addThisMonthFilter(props.search, code)) }, "This Month"),
3585
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconCalendar, { size: 14 }), onClick: () => props.onChange(addLastMonthFilter(props.search, code)) }, "Last Month"),
3586
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3587
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconCalendar, { size: 14 }), onClick: () => props.onChange(addYearToDateFilter(props.search, code)) }, "Year to date"),
3588
+ React__default["default"].createElement(CommonMenuItems, Object.assign({}, props))));
4034
3589
  }
4035
3590
  function NumericFilterSubMenu(props) {
4036
3591
  const { searchParam } = props;
4037
- const code = searchParam.code;
4038
- return (React__default["default"].createElement(React__default["default"].Fragment, null,
4039
- React__default["default"].createElement(MenuItem, { onClick: () => props.onSort(searchParam, false) }, "Sort Smallest to Largest"),
4040
- React__default["default"].createElement(MenuItem, { onClick: () => props.onSort(searchParam, true) }, "Sort Largest to Smallest"),
4041
- React__default["default"].createElement(MenuSeparator, null),
4042
- React__default["default"].createElement(MenuItem, { onClick: () => props.onPrompt(searchParam, core.Operator.EQUALS) }, "Equals..."),
4043
- React__default["default"].createElement(MenuItem, { onClick: () => props.onPrompt(searchParam, core.Operator.NOT_EQUALS) }, "Does not equal..."),
4044
- React__default["default"].createElement(MenuSeparator, null),
4045
- React__default["default"].createElement(MenuItem, { onClick: () => props.onPrompt(searchParam, core.Operator.GREATER_THAN) }, "Greater than..."),
4046
- React__default["default"].createElement(MenuItem, { onClick: () => props.onPrompt(searchParam, core.Operator.GREATER_THAN_OR_EQUALS) }, "Greater than or equal to..."),
4047
- React__default["default"].createElement(MenuItem, { onClick: () => props.onPrompt(searchParam, core.Operator.LESS_THAN) }, "Less than..."),
4048
- React__default["default"].createElement(MenuItem, { onClick: () => props.onPrompt(searchParam, core.Operator.LESS_THAN_OR_EQUALS) }, "Less than or equal to..."),
4049
- React__default["default"].createElement(MenuSeparator, null),
4050
- React__default["default"].createElement(MenuItem, { onClick: () => props.onChange(addMissingFilter(props.search, code)) }, "Missing"),
4051
- React__default["default"].createElement(MenuItem, { onClick: () => props.onChange(addMissingFilter(props.search, code, false)) }, "Not missing"),
4052
- React__default["default"].createElement(MenuSeparator, null),
4053
- React__default["default"].createElement(MenuItem, { onClick: () => props.onClear(searchParam) }, "Clear filters")));
3592
+ return (React__default["default"].createElement(core$1.Menu.Dropdown, null,
3593
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconSortAscending, { size: 14 }), onClick: () => props.onSort(searchParam, false) }, "Sort Smallest to Largest"),
3594
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconSortDescending, { size: 14 }), onClick: () => props.onSort(searchParam, true) }, "Sort Largest to Smallest"),
3595
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3596
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconEqual, { size: 14 }), onClick: () => props.onPrompt(searchParam, core.Operator.EQUALS) }, "Equals..."),
3597
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconEqualNot, { size: 14 }), onClick: () => props.onPrompt(searchParam, core.Operator.NOT_EQUALS) }, "Does not equal..."),
3598
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3599
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconMathGreater, { size: 14 }), onClick: () => props.onPrompt(searchParam, core.Operator.GREATER_THAN) }, "Greater than..."),
3600
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconSettings, { size: 14 }), onClick: () => props.onPrompt(searchParam, core.Operator.GREATER_THAN_OR_EQUALS) }, "Greater than or equal to..."),
3601
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconMathLower, { size: 14 }), onClick: () => props.onPrompt(searchParam, core.Operator.LESS_THAN) }, "Less than..."),
3602
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconSettings, { size: 14 }), onClick: () => props.onPrompt(searchParam, core.Operator.LESS_THAN_OR_EQUALS) }, "Less than or equal to..."),
3603
+ React__default["default"].createElement(CommonMenuItems, Object.assign({}, props))));
4054
3604
  }
4055
3605
  function ReferenceFilterSubMenu(props) {
4056
3606
  const { searchParam } = props;
4057
- const code = searchParam.code;
4058
- return (React__default["default"].createElement(React__default["default"].Fragment, null,
4059
- React__default["default"].createElement(MenuItem, { onClick: () => props.onPrompt(searchParam, core.Operator.EQUALS) }, "Equals..."),
4060
- React__default["default"].createElement(MenuItem, { onClick: () => props.onPrompt(searchParam, core.Operator.NOT) }, "Does not equal..."),
4061
- React__default["default"].createElement(MenuSeparator, null),
4062
- React__default["default"].createElement(MenuItem, { onClick: () => props.onChange(addMissingFilter(props.search, code)) }, "Missing"),
4063
- React__default["default"].createElement(MenuItem, { onClick: () => props.onChange(addMissingFilter(props.search, code, false)) }, "Not missing"),
4064
- React__default["default"].createElement(MenuSeparator, null),
4065
- React__default["default"].createElement(MenuItem, { onClick: () => props.onClear(searchParam) }, "Clear filters")));
3607
+ return (React__default["default"].createElement(core$1.Menu.Dropdown, null,
3608
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconEqual, { size: 14 }), onClick: () => props.onPrompt(searchParam, core.Operator.EQUALS) }, "Equals..."),
3609
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconEqualNot, { size: 14 }), onClick: () => props.onPrompt(searchParam, core.Operator.NOT) }, "Does not equal..."),
3610
+ React__default["default"].createElement(CommonMenuItems, Object.assign({}, props))));
4066
3611
  }
4067
3612
  function TextFilterSubMenu(props) {
3613
+ const { searchParam } = props;
3614
+ return (React__default["default"].createElement(core$1.Menu.Dropdown, null,
3615
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconSortAscending, { size: 14 }), onClick: () => props.onSort(searchParam, false) }, "Sort A to Z"),
3616
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconSortDescending, { size: 14 }), onClick: () => props.onSort(searchParam, true) }, "Sort Z to A"),
3617
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3618
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconEqual, { size: 14 }), onClick: () => props.onPrompt(searchParam, core.Operator.EQUALS) }, "Equals..."),
3619
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconEqualNot, { size: 14 }), onClick: () => props.onPrompt(searchParam, core.Operator.NOT) }, "Does not equal..."),
3620
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3621
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconBucket, { size: 14 }), onClick: () => props.onPrompt(searchParam, core.Operator.CONTAINS) }, "Contains..."),
3622
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconBucketOff, { size: 14 }), onClick: () => props.onPrompt(searchParam, core.Operator.EQUALS) }, "Does not contain..."),
3623
+ React__default["default"].createElement(CommonMenuItems, Object.assign({}, props))));
3624
+ }
3625
+ function CommonMenuItems(props) {
4068
3626
  const { searchParam } = props;
4069
3627
  const code = searchParam.code;
4070
3628
  return (React__default["default"].createElement(React__default["default"].Fragment, null,
4071
- React__default["default"].createElement(MenuItem, { onClick: () => props.onSort(searchParam, false) }, "Sort A to Z"),
4072
- React__default["default"].createElement(MenuItem, { onClick: () => props.onSort(searchParam, true) }, "Sort Z to A"),
4073
- React__default["default"].createElement(MenuSeparator, null),
4074
- React__default["default"].createElement(MenuItem, { onClick: () => props.onPrompt(searchParam, core.Operator.EQUALS) }, "Equals..."),
4075
- React__default["default"].createElement(MenuItem, { onClick: () => props.onPrompt(searchParam, core.Operator.NOT) }, "Does not equal..."),
4076
- React__default["default"].createElement(MenuSeparator, null),
4077
- React__default["default"].createElement(MenuItem, { onClick: () => props.onPrompt(searchParam, core.Operator.CONTAINS) }, "Contains..."),
4078
- React__default["default"].createElement(MenuItem, { onClick: () => props.onPrompt(searchParam, core.Operator.EQUALS) }, "Does not contain..."),
4079
- React__default["default"].createElement(MenuSeparator, null),
4080
- React__default["default"].createElement(MenuItem, { onClick: () => props.onChange(addMissingFilter(props.search, code)) }, "Missing"),
4081
- React__default["default"].createElement(MenuItem, { onClick: () => props.onChange(addMissingFilter(props.search, code, false)) }, "Not missing"),
4082
- React__default["default"].createElement(MenuSeparator, null),
4083
- React__default["default"].createElement(MenuItem, { onClick: () => props.onClear(searchParam) }, "Clear filters")));
4084
- }
4085
-
4086
- function TitleBar(props) {
4087
- return React__default["default"].createElement("div", { className: "medplum-title-bar" }, props.children);
3629
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3630
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconBleach, { size: 14 }), onClick: () => props.onChange(addMissingFilter(props.search, code)) }, "Missing"),
3631
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconBleachOff, { size: 14 }), onClick: () => props.onChange(addMissingFilter(props.search, code, false)) }, "Not missing"),
3632
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3633
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconX, { size: 14 }), onClick: () => props.onClear(searchParam) }, "Clear filters")));
4088
3634
  }
4089
3635
 
4090
3636
  class SearchChangeEvent extends Event {
@@ -4106,23 +3652,37 @@
4106
3652
  this.browserEvent = browserEvent;
4107
3653
  }
4108
3654
  }
3655
+ const useStyles = core$1.createStyles((theme) => ({
3656
+ th: {
3657
+ padding: '0 !important',
3658
+ },
3659
+ control: {
3660
+ width: '100%',
3661
+ padding: `${theme.spacing.xs}px ${theme.spacing.md}px`,
3662
+ '&:hover': {
3663
+ backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[0],
3664
+ },
3665
+ },
3666
+ icon: {
3667
+ width: 21,
3668
+ height: 21,
3669
+ borderRadius: 21,
3670
+ },
3671
+ }));
4109
3672
  /**
4110
3673
  * The SearchControl component represents the embeddable search table control.
4111
3674
  * It includes the table, rows, headers, sorting, etc.
4112
3675
  * It does not include the field editor, filter editor, pagination buttons.
4113
3676
  */
4114
3677
  function SearchControl(props) {
4115
- var _a, _b, _c, _d;
3678
+ var _a, _b;
3679
+ const { classes } = useStyles();
4116
3680
  const medplum = useMedplum();
4117
3681
  const [schemaLoaded, setSchemaLoaded] = React.useState(false);
4118
3682
  const [outcome, setOutcome] = React.useState();
4119
3683
  const { search, onLoad } = props;
4120
3684
  const [state, setState] = React.useState({
4121
3685
  selected: {},
4122
- popupVisible: false,
4123
- popupX: 0,
4124
- popupY: 0,
4125
- popupSearchParams: undefined,
4126
3686
  fieldEditorVisible: false,
4127
3687
  filterEditorVisible: false,
4128
3688
  filterDialogVisible: false,
@@ -4187,14 +3747,6 @@
4187
3747
  }
4188
3748
  return true;
4189
3749
  }
4190
- /**
4191
- * Handles a click on a column header cell.
4192
- * @param e The click event.
4193
- * @param key The field key.
4194
- */
4195
- function handleSortClick(e, searchParams) {
4196
- setState(Object.assign(Object.assign({}, stateRef.current), { popupVisible: true, popupX: e.clientX, popupY: e.clientY, popupSearchParams: searchParams }));
4197
- }
4198
3750
  /**
4199
3751
  * Emits a change event to the optional change listener.
4200
3752
  * @param newSearch The new search definition.
@@ -4215,6 +3767,10 @@
4215
3767
  // Ignore clicks on checkboxes
4216
3768
  return;
4217
3769
  }
3770
+ if (e.button === 2) {
3771
+ // Ignore right clicks
3772
+ return;
3773
+ }
4218
3774
  killEvent(e);
4219
3775
  if (e.button !== 1 && props.onClick) {
4220
3776
  props.onClick(new SearchClickEvent(resource, e));
@@ -4232,7 +3788,7 @@
4232
3788
  }, [medplum, props.search.resourceType]);
4233
3789
  const typeSchema = schemaLoaded && ((_a = core.globalSchema === null || core.globalSchema === void 0 ? void 0 : core.globalSchema.types) === null || _a === void 0 ? void 0 : _a[props.search.resourceType]);
4234
3790
  if (!typeSchema) {
4235
- return React__default["default"].createElement(Loading, null);
3791
+ return React__default["default"].createElement(core$1.Loader, null);
4236
3792
  }
4237
3793
  const checkboxColumn = props.checkboxesEnabled;
4238
3794
  const fields = getFieldDefinitions(search);
@@ -4240,41 +3796,45 @@
4240
3796
  const lastResult = state.searchResponse;
4241
3797
  const entries = lastResult === null || lastResult === void 0 ? void 0 : lastResult.entry;
4242
3798
  const resources = entries === null || entries === void 0 ? void 0 : entries.map((e) => e.resource);
4243
- const savedSearches = (_c = (_b = props.userConfig) === null || _b === void 0 ? void 0 : _b.search) === null || _c === void 0 ? void 0 : _c.filter((s) => { var _a; return (_a = s.criteria) === null || _a === void 0 ? void 0 : _a.startsWith(resourceType); });
4244
- return (React__default["default"].createElement("div", { className: "medplum-search-control", onContextMenu: (e) => killEvent(e), "data-testid": "search-control" },
4245
- !props.hideToolbar && (React__default["default"].createElement(TitleBar, null,
4246
- React__default["default"].createElement("div", null,
4247
- React__default["default"].createElement("h1", null,
4248
- React__default["default"].createElement("a", { href: `https://www.hl7.org/fhir/${resourceType.toLowerCase()}.html`, target: "_blank", rel: "noopener" }, resourceType)),
4249
- savedSearches && (React__default["default"].createElement(Select, { testid: "saved-search-select", style: { width: 80 }, onChange: (newValue) => {
4250
- emitSearchChange(core.parseSearchDefinition(newValue));
4251
- } },
4252
- React__default["default"].createElement("option", null),
4253
- savedSearches.map((s, index) => (React__default["default"].createElement("option", { key: `${index}-${savedSearches.length}`, value: s.criteria }, s.name))))),
4254
- React__default["default"].createElement(Button, { testid: "fields-button", size: "small", onClick: () => setState(Object.assign(Object.assign({}, stateRef.current), { fieldEditorVisible: true })) }, "Fields"),
4255
- React__default["default"].createElement(Button, { testid: "filters-button", size: "small", onClick: () => setState(Object.assign(Object.assign({}, stateRef.current), { filterEditorVisible: true })) }, "Filters"),
4256
- props.onNew && (React__default["default"].createElement(Button, { size: "small", onClick: props.onNew }, "New...")),
4257
- props.onExport && (React__default["default"].createElement(Button, { size: "small", onClick: props.onExport }, "Export...")),
4258
- props.onDelete && (React__default["default"].createElement(Button, { size: "small", onClick: () => props.onDelete(Object.keys(state.selected)) }, "Delete...")),
4259
- props.onBulk && (React__default["default"].createElement(Button, { size: "small", onClick: () => props.onBulk(Object.keys(state.selected)) }, "Bulk..."))),
4260
- lastResult && (React__default["default"].createElement("div", null,
3799
+ const buttonVariant = 'subtle';
3800
+ const buttonColor = 'gray';
3801
+ const iconSize = 16;
3802
+ const isMobile = window.innerWidth < 768;
3803
+ return (React__default["default"].createElement("div", { className: "medplum-search-control", "data-testid": "search-control" },
3804
+ !props.hideToolbar && (React__default["default"].createElement(core$1.Group, { position: "apart", mb: "xl" },
3805
+ React__default["default"].createElement(core$1.Group, { spacing: 2 },
3806
+ React__default["default"].createElement(core$1.Button, { compact: true, variant: buttonVariant, color: buttonColor, leftIcon: React__default["default"].createElement(icons.IconFilter, { size: iconSize }), onClick: () => setState(Object.assign(Object.assign({}, stateRef.current), { fieldEditorVisible: true })) }, "Fields"),
3807
+ React__default["default"].createElement(core$1.Button, { compact: true, variant: buttonVariant, color: buttonColor, leftIcon: React__default["default"].createElement(icons.IconColumns, { size: iconSize }), onClick: () => setState(Object.assign(Object.assign({}, stateRef.current), { filterEditorVisible: true })) }, "Filters"),
3808
+ props.onNew && (React__default["default"].createElement(core$1.Button, { compact: true, variant: buttonVariant, color: buttonColor, leftIcon: React__default["default"].createElement(icons.IconFilePlus, { size: iconSize }), onClick: props.onNew }, "New...")),
3809
+ !isMobile && props.onExport && (React__default["default"].createElement(core$1.Button, { compact: true, variant: buttonVariant, color: buttonColor, leftIcon: React__default["default"].createElement(icons.IconTableExport, { size: iconSize }), onClick: props.onExport }, "Export...")),
3810
+ !isMobile && props.onDelete && (React__default["default"].createElement(core$1.Button, { compact: true, variant: buttonVariant, color: buttonColor, leftIcon: React__default["default"].createElement(icons.IconTrash, { size: iconSize }), onClick: () => props.onDelete(Object.keys(state.selected)) }, "Delete...")),
3811
+ !isMobile && props.onBulk && (React__default["default"].createElement(core$1.Button, { compact: true, variant: buttonVariant, color: buttonColor, leftIcon: React__default["default"].createElement(icons.IconBoxMultiple, { size: iconSize }), onClick: () => props.onBulk(Object.keys(state.selected)) }, "Bulk..."))),
3812
+ lastResult && (React__default["default"].createElement(core$1.Group, { spacing: 2 },
4261
3813
  React__default["default"].createElement("span", { className: "medplum-search-summary" },
4262
3814
  getStart$1(search, lastResult.total),
4263
3815
  "-",
4264
3816
  getEnd$1(search, lastResult.total),
4265
3817
  " of",
4266
- ' ', (_d = lastResult.total) === null || _d === void 0 ? void 0 :
4267
- _d.toLocaleString()),
4268
- React__default["default"].createElement(Button, { testid: "prev-page-button", size: "small", onClick: () => emitSearchChange(movePage(search, -1)) }, "<<"),
4269
- React__default["default"].createElement(Button, { testid: "next-page-button", size: "small", onClick: () => emitSearchChange(movePage(search, 1)) }, ">>"))))),
4270
- React__default["default"].createElement("table", null,
3818
+ ' ', (_b = lastResult.total) === null || _b === void 0 ? void 0 :
3819
+ _b.toLocaleString()))))),
3820
+ React__default["default"].createElement(core$1.Table, null,
4271
3821
  React__default["default"].createElement("thead", null,
4272
3822
  React__default["default"].createElement("tr", null,
4273
3823
  checkboxColumn && (React__default["default"].createElement("th", { className: "medplum-search-icon-cell" },
4274
3824
  React__default["default"].createElement("input", { type: "checkbox", value: "checked", "aria-label": "all-checkbox", "data-testid": "all-checkbox", checked: isAllSelected(), onChange: (e) => handleAllCheckboxClick(e) }))),
4275
- fields.map((field) => (React__default["default"].createElement("th", { key: field.name, onClick: (e) => handleSortClick(e, field.searchParams) },
4276
- buildFieldNameString(field.name),
4277
- field.searchParams && React__default["default"].createElement(FilterIcon, null))))),
3825
+ fields.map((field) => (React__default["default"].createElement("th", { key: field.name },
3826
+ React__default["default"].createElement(core$1.Menu, { shadow: "md", width: 240, position: "bottom-end" },
3827
+ React__default["default"].createElement(core$1.Menu.Target, null,
3828
+ React__default["default"].createElement(core$1.UnstyledButton, { className: classes.control },
3829
+ React__default["default"].createElement(core$1.Group, { position: "apart", noWrap: true },
3830
+ React__default["default"].createElement(core$1.Text, { weight: 500, size: "sm" }, buildFieldNameString(field.name)),
3831
+ React__default["default"].createElement(core$1.Center, { className: classes.icon },
3832
+ React__default["default"].createElement(icons.IconAdjustmentsHorizontal, { size: 14, stroke: 1.5 }))))),
3833
+ React__default["default"].createElement(SearchPopupMenu, { search: props.search, searchParams: field.searchParams, onPrompt: (searchParam, filter) => {
3834
+ setState(Object.assign(Object.assign({}, stateRef.current), { filterDialogVisible: true, filterDialogSearchParam: searchParam, filterDialogFilter: filter }));
3835
+ }, onChange: (result) => {
3836
+ emitSearchChange(result);
3837
+ } })))))),
4278
3838
  !props.hideFilters && (React__default["default"].createElement("tr", null,
4279
3839
  checkboxColumn && React__default["default"].createElement("th", { className: "filters medplum-search-icon-cell" }),
4280
3840
  fields.map((field) => (React__default["default"].createElement("th", { key: field.name, className: "filters" }, field.searchParams && (React__default["default"].createElement(FilterDescription, { resourceType: resourceType, searchParams: field.searchParams, filters: props.search.filters })))))))),
@@ -4283,16 +3843,19 @@
4283
3843
  React__default["default"].createElement("input", { type: "checkbox", value: "checked", "data-testid": "row-checkbox", "aria-label": `Checkbox for ${resource.id}`, checked: !!state.selected[resource.id], onChange: (e) => handleSingleCheckboxClick(e, resource.id) }))),
4284
3844
  fields.map((field) => (React__default["default"].createElement("td", { key: field.name }, renderValue(resource, field))))))))),
4285
3845
  (resources === null || resources === void 0 ? void 0 : resources.length) === 0 && (React__default["default"].createElement("div", { "data-testid": "empty-search", className: "medplum-empty-search" }, "No results")),
3846
+ (lastResult === null || lastResult === void 0 ? void 0 : lastResult.total) !== undefined && lastResult.total > 0 && (React__default["default"].createElement(core$1.Center, { m: "md", p: "md" },
3847
+ React__default["default"].createElement(core$1.Pagination, { page: getPage(search), total: getTotalPages(search, lastResult.total), onChange: (newPage) => emitSearchChange(setPage(search, newPage)), getItemAriaLabel: (page) => {
3848
+ switch (page) {
3849
+ case 'prev':
3850
+ return 'Previous page';
3851
+ case 'next':
3852
+ return 'Next page';
3853
+ default:
3854
+ return undefined;
3855
+ }
3856
+ } }))),
4286
3857
  outcome && (React__default["default"].createElement("div", { "data-testid": "search-error", className: "medplum-empty-search" },
4287
3858
  React__default["default"].createElement("pre", { style: { textAlign: 'left' } }, JSON.stringify(outcome, undefined, 2)))),
4288
- React__default["default"].createElement(SearchPopupMenu, { search: props.search, visible: state.popupVisible, x: state.popupX, y: state.popupY, searchParams: state.popupSearchParams, onPrompt: (searchParam, filter) => {
4289
- setState(Object.assign(Object.assign({}, stateRef.current), { popupVisible: false, filterDialogVisible: true, filterDialogSearchParam: searchParam, filterDialogFilter: filter }));
4290
- }, onChange: (result) => {
4291
- emitSearchChange(result);
4292
- setState(Object.assign(Object.assign({}, stateRef.current), { popupVisible: false, popupSearchParams: undefined }));
4293
- }, onClose: () => {
4294
- setState(Object.assign(Object.assign({}, stateRef.current), { popupVisible: false, popupSearchParams: undefined }));
4295
- } }),
4296
3859
  React__default["default"].createElement(SearchFieldEditor, { search: props.search, visible: stateRef.current.fieldEditorVisible, onOk: (result) => {
4297
3860
  emitSearchChange(result);
4298
3861
  setState(Object.assign(Object.assign({}, stateRef.current), { fieldEditorVisible: false }));
@@ -4324,9 +3887,12 @@
4324
3887
  "\u00A0",
4325
3888
  React__default["default"].createElement(SearchFilterValueDisplay, { resourceType: props.resourceType, filter: filter }))))));
4326
3889
  }
4327
- function FilterIcon() {
4328
- return (React__default["default"].createElement("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-6 w-6", fill: "none", viewBox: "0 0 24 24", stroke: "rgba(0, 0, 0, 0.3)", strokeWidth: 2 },
4329
- React__default["default"].createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 6h16M4 12h16m-7 6h7" })));
3890
+ function getPage(search) {
3891
+ return Math.floor((search.offset || 0) / (search.count || core.DEFAULT_SEARCH_COUNT)) + 1;
3892
+ }
3893
+ function getTotalPages(search, total) {
3894
+ const pageSize = search.count || core.DEFAULT_SEARCH_COUNT;
3895
+ return Math.ceil(total / pageSize);
4330
3896
  }
4331
3897
  function getStart$1(search, total) {
4332
3898
  var _a;
@@ -4423,11 +3989,11 @@
4423
3989
  }, [medplum, props.resourceType]);
4424
3990
  const typeSchema = (_a = schema === null || schema === void 0 ? void 0 : schema.types) === null || _a === void 0 ? void 0 : _a[props.resourceType];
4425
3991
  if (!typeSchema) {
4426
- return React__default["default"].createElement(Loading, null);
3992
+ return React__default["default"].createElement(core$1.Loader, null);
4427
3993
  }
4428
3994
  const checkboxColumn = props.checkboxesEnabled;
4429
3995
  return (React__default["default"].createElement("div", { className: "medplum-search-control", onContextMenu: (e) => killEvent(e), "data-testid": "search-control" },
4430
- React__default["default"].createElement("table", null,
3996
+ React__default["default"].createElement(core$1.Table, null,
4431
3997
  React__default["default"].createElement("thead", null,
4432
3998
  React__default["default"].createElement("tr", null,
4433
3999
  checkboxColumn && (React__default["default"].createElement("th", { className: "medplum-search-icon-cell" },
@@ -4443,271 +4009,10 @@
4443
4009
  ((_e = (_d = response === null || response === void 0 ? void 0 : response.data) === null || _d === void 0 ? void 0 : _d.ResourceList) === null || _e === void 0 ? void 0 : _e.length) === 0 && (React__default["default"].createElement("div", { "data-testid": "empty-search", className: "medplum-empty-search" }, "No results")),
4444
4010
  outcome && (React__default["default"].createElement("div", { "data-testid": "search-error", className: "medplum-empty-search" },
4445
4011
  React__default["default"].createElement("pre", { style: { textAlign: 'left' } }, JSON.stringify(outcome, undefined, 2)))),
4446
- props.onBulk && (React__default["default"].createElement(Button, { size: "small", onClick: () => props.onBulk(Object.keys(selectedRef.current)) }, "Bulk..."))));
4012
+ props.onBulk && (React__default["default"].createElement(core$1.Button, { onClick: () => props.onBulk(Object.keys(selectedRef.current)) }, "Bulk..."))));
4447
4013
  }
4448
4014
  const MemoizedFhirPathTable = React__default["default"].memo(FhirPathTable);
4449
4015
 
4450
- function FooterLinks(props) {
4451
- return React__default["default"].createElement("div", { className: "medplum-footer" }, props.children);
4452
- }
4453
-
4454
- function HeaderSearchInput(props) {
4455
- const medplum = useMedplum();
4456
- return (React__default["default"].createElement(Autocomplete, { loadOptions: (input, signal) => __awaiter(this, void 0, void 0, function* () {
4457
- return getResourcesFromResponse((yield medplum.graphql(buildGraphQLQuery(input), undefined, undefined, { signal })), input);
4458
- }), getId: (item) => {
4459
- return item.id;
4460
- }, getIcon: (item) => React__default["default"].createElement(Avatar, { value: item }), getDisplay: (item) => React__default["default"].createElement(ResourceName, { value: item }), getHelpText: (item) => {
4461
- var _a;
4462
- if (item.resourceType === 'Patient' && item.birthDate) {
4463
- return 'DoB: ' + item.birthDate;
4464
- }
4465
- return (_a = item.subject) === null || _a === void 0 ? void 0 : _a.display;
4466
- }, name: props.name, className: props.className, placeholder: props.placeholder, onChange: (items) => props.onChange(items[0]) }));
4467
- }
4468
- function buildGraphQLQuery(input) {
4469
- const escaped = JSON.stringify(input);
4470
- if (core.isUUID(input)) {
4471
- return `{
4472
- Patients1: PatientList(_id: ${escaped}, _count: 1) {
4473
- resourceType
4474
- id
4475
- identifier {
4476
- system
4477
- value
4478
- }
4479
- name {
4480
- given
4481
- family
4482
- }
4483
- birthDate
4484
- }
4485
- ServiceRequestList(_id: ${escaped}, _count: 1) {
4486
- resourceType
4487
- id
4488
- identifier {
4489
- system
4490
- value
4491
- }
4492
- subject {
4493
- display
4494
- }
4495
- }
4496
- }`.replace(/\s+/g, ' ');
4497
- }
4498
- return `{
4499
- Patients1: PatientList(name: ${escaped}, _count: 5) {
4500
- resourceType
4501
- id
4502
- identifier {
4503
- system
4504
- value
4505
- }
4506
- name {
4507
- given
4508
- family
4509
- }
4510
- birthDate
4511
- }
4512
- Patients2: PatientList(identifier: ${escaped}, _count: 5) {
4513
- resourceType
4514
- id
4515
- identifier {
4516
- system
4517
- value
4518
- }
4519
- name {
4520
- given
4521
- family
4522
- }
4523
- birthDate
4524
- }
4525
- ServiceRequestList(identifier: ${escaped}, _count: 5) {
4526
- resourceType
4527
- id
4528
- identifier {
4529
- system
4530
- value
4531
- }
4532
- subject {
4533
- display
4534
- }
4535
- }
4536
- }`.replace(/\s+/g, ' ');
4537
- }
4538
- /**
4539
- * Returns a de-duped and sorted list of resources from the search response.
4540
- * The search request is actually 3+ separate searches, which can include duplicates.
4541
- * This function combines the results, de-dupes, and sorts by relevance.
4542
- * @param response The response from a search query.
4543
- * @param query The user entered search query.
4544
- * @returns The resources to display in the autocomplete.
4545
- */
4546
- function getResourcesFromResponse(response, query) {
4547
- const resources = [];
4548
- if (response.data.Patients1) {
4549
- resources.push(...response.data.Patients1);
4550
- }
4551
- if (response.data.Patients2) {
4552
- resources.push(...response.data.Patients2);
4553
- }
4554
- if (response.data.ServiceRequestList) {
4555
- resources.push(...response.data.ServiceRequestList);
4556
- }
4557
- return sortByRelevance(dedupeResources(resources), query).slice(0, 5);
4558
- }
4559
- /**
4560
- * Removes duplicate resources from an array by ID.
4561
- * @param resources The array of resources with possible duplicates.
4562
- * @returns The array of resources with no duplicates.
4563
- */
4564
- function dedupeResources(resources) {
4565
- const ids = new Set();
4566
- const result = [];
4567
- for (const resource of resources) {
4568
- if (!ids.has(resource.id)) {
4569
- ids.add(resource.id);
4570
- result.push(resource);
4571
- }
4572
- }
4573
- return result;
4574
- }
4575
- /**
4576
- * Sorts an array of resources by relevance.
4577
- * @param resources The candidate resources.
4578
- * @param query The user entered search string.
4579
- * @returns The sorted array of resources.
4580
- */
4581
- function sortByRelevance(resources, query) {
4582
- return resources.sort((a, b) => {
4583
- return getResourceScore(b, query) - getResourceScore(a, query);
4584
- });
4585
- }
4586
- /**
4587
- * Calculates a relevance score of a candidate resource.
4588
- * Higher scores are better.
4589
- * @param resource The candidate resource.
4590
- * @param query The user entered search string.
4591
- * @returns The relevance score of the candidate resource.
4592
- */
4593
- function getResourceScore(resource, query) {
4594
- let bestScore = 0;
4595
- if (resource.identifier) {
4596
- for (const identifier of resource.identifier) {
4597
- bestScore = Math.max(bestScore, getStringScore(identifier.value, query));
4598
- }
4599
- }
4600
- if (resource.resourceType === 'Patient' && resource.name) {
4601
- for (const name of resource.name) {
4602
- bestScore = Math.max(bestScore, getStringScore(core.formatHumanName(name), query));
4603
- }
4604
- }
4605
- return bestScore;
4606
- }
4607
- /**
4608
- * Calculates a relevance score of a candidate display string.
4609
- * Higher scores are better.
4610
- * @param str The candidate display string.
4611
- * @param query The user entered search string.
4612
- * @returns The relevance score of the candidate string.
4613
- */
4614
- function getStringScore(str, query) {
4615
- if (!str) {
4616
- return 0;
4617
- }
4618
- const index = str.toLowerCase().indexOf(query.toLowerCase());
4619
- if (index < 0) {
4620
- return 0;
4621
- }
4622
- return 100 - index;
4623
- }
4624
-
4625
- function Header(props) {
4626
- var _a, _b, _c, _d, _e, _f;
4627
- const navigate = reactRouterDom.useNavigate();
4628
- const location = reactRouterDom.useLocation();
4629
- const context = useMedplumContext();
4630
- const medplum = context.medplum;
4631
- const logins = medplum.getLogins();
4632
- const [userMenuVisible, setUserMenuVisible] = React.useState(false);
4633
- const [sidebarVisible, setSidebarVisible] = React.useState(false);
4634
- return (React__default["default"].createElement(React__default["default"].Fragment, null,
4635
- React__default["default"].createElement("header", { role: "banner", "data-testid": "header", style: { background: props.bgColor } },
4636
- React__default["default"].createElement("div", null,
4637
- React__default["default"].createElement(MedplumLink, { label: "Toggle sidebar", testid: "header-menu-button", onClick: () => setSidebarVisible(!sidebarVisible) },
4638
- React__default["default"].createElement("svg", { xmlns: "http://www.w3.org/2000/svg", style: { width: 20, height: 20, verticalAlign: 'text-top' }, viewBox: "0 0 20 20", fill: "currentColor" },
4639
- React__default["default"].createElement("path", { fillRule: "evenodd", 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", clipRule: "evenodd" }))),
4640
- React__default["default"].createElement(MedplumLink, { id: "medplum-header-logo", testid: "header-logo", onClick: props.onLogo }, props.title || 'Medplum'),
4641
- context.profile && (React__default["default"].createElement(HeaderSearchInput, { key: `header-input-${location.pathname}`, name: "search", className: "medplum-nav-search-container", placeholder: "Search", onChange: (resource) => navigate(`/${resource.resourceType}/${resource.id}`) }))),
4642
- context.profile && (React__default["default"].createElement("div", { className: "medplum-nav-menu-container" },
4643
- React__default["default"].createElement(MedplumLink, { testid: "header-profile-menu-button", onClick: () => setUserMenuVisible(true) },
4644
- React__default["default"].createElement(Avatar, { size: "small", color: "#f68d42", value: context.profile })),
4645
- React__default["default"].createElement(Popup, { visible: userMenuVisible, autoClose: true, activeClassName: "medplum-nav-menu-popover", onClose: () => setUserMenuVisible(false) },
4646
- React__default["default"].createElement("div", { className: "medplum-nav-menu" },
4647
- React__default["default"].createElement("div", { style: { margin: 'auto', padding: '8px' } },
4648
- React__default["default"].createElement(Avatar, { size: "large", value: context.profile })),
4649
- React__default["default"].createElement("div", { style: { margin: 'auto', padding: '8px' } },
4650
- React__default["default"].createElement("div", { style: { margin: '4px auto 4px auto', fontWeight: 'bold' } },
4651
- React__default["default"].createElement(HumanNameDisplay, { value: (_b = (_a = context.profile) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b[0] })),
4652
- React__default["default"].createElement("div", { style: { margin: '4px auto 4px auto' } }, (_d = (_c = medplum.getActiveLogin()) === null || _c === void 0 ? void 0 : _c.project) === null || _d === void 0 ? void 0 : _d.display),
4653
- React__default["default"].createElement(Button, { testid: "header-profile-link", onClick: () => {
4654
- setUserMenuVisible(false);
4655
- if (props.onProfile) {
4656
- props.onProfile();
4657
- }
4658
- } }, "Manage your account")),
4659
- logins.length > 1 && (React__default["default"].createElement("div", null,
4660
- React__default["default"].createElement("hr", null),
4661
- logins.map((login) => {
4662
- var _a, _b, _c, _d;
4663
- return ((_a = login.profile) === null || _a === void 0 ? void 0 : _a.reference) !== core.getReferenceString(context.profile) && (React__default["default"].createElement("div", { className: "medplum-nav-menu-profile", key: (_b = login.profile) === null || _b === void 0 ? void 0 : _b.reference, onClick: () => {
4664
- medplum
4665
- .setActiveLogin(login)
4666
- .then(() => {
4667
- setUserMenuVisible(false);
4668
- window.location.reload();
4669
- })
4670
- .catch(console.log);
4671
- } },
4672
- React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-icon" },
4673
- React__default["default"].createElement(Avatar, null)),
4674
- React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-label" }, (_c = login.profile) === null || _c === void 0 ? void 0 :
4675
- _c.display,
4676
- React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-help-text" }, (_d = login.project) === null || _d === void 0 ? void 0 : _d.display))));
4677
- }))),
4678
- React__default["default"].createElement("hr", null),
4679
- React__default["default"].createElement("div", { style: { margin: 'auto', padding: '8px' } },
4680
- React__default["default"].createElement(Button, { testid: "header-add-account-button", onClick: () => {
4681
- navigate('/signin');
4682
- } }, "Add another account")),
4683
- React__default["default"].createElement("hr", null),
4684
- React__default["default"].createElement("div", { style: { margin: 'auto', padding: '8px' } },
4685
- React__default["default"].createElement(Button, { testid: "header-signout-button", onClick: () => {
4686
- setUserMenuVisible(false);
4687
- if (props.onSignOut) {
4688
- props.onSignOut();
4689
- }
4690
- } }, "Sign out of all accounts")),
4691
- React__default["default"].createElement("hr", null),
4692
- React__default["default"].createElement("div", { style: { margin: 'auto', padding: '8px', fontSize: '12px' } },
4693
- React__default["default"].createElement("a", { href: "https://www.medplum.com/terms" }, "Terms"),
4694
- React__default["default"].createElement("a", { href: "https://www.medplum.com/privacy" }, "Privacy"))))))),
4695
- React__default["default"].createElement(Popup, { modal: true, autoClose: true, visible: sidebarVisible, activeClassName: "medplum-sidebar active", inactiveClassName: "medplum-sidebar", onClose: () => setSidebarVisible(false) }, (_f = (_e = props.config) === null || _e === void 0 ? void 0 : _e.menu) === null || _f === void 0 ? void 0 :
4696
- _f.map((menu, index) => {
4697
- var _a, _b, _c;
4698
- return (React__default["default"].createElement(React__default["default"].Fragment, { key: `menu-${index}-${(_b = (_a = props.config) === null || _a === void 0 ? void 0 : _a.menu) === null || _b === void 0 ? void 0 : _b.length}` },
4699
- React__default["default"].createElement("h5", null, menu.title),
4700
- React__default["default"].createElement("ul", null, (_c = menu.link) === null || _c === void 0 ? void 0 : _c.map((link) => (React__default["default"].createElement("li", { key: link.target },
4701
- React__default["default"].createElement(MedplumLink, { to: link.target }, link.name)))))));
4702
- }),
4703
- React__default["default"].createElement("h5", null, "Settings"),
4704
- React__default["default"].createElement("ul", null,
4705
- React__default["default"].createElement("li", null,
4706
- React__default["default"].createElement(MedplumLink, { to: context.profile }, "Profile")),
4707
- React__default["default"].createElement("li", null,
4708
- React__default["default"].createElement(MedplumLink, { to: "/changepassword" }, "Change password"))))));
4709
- }
4710
-
4711
4016
  const searches = [
4712
4017
  '$/_history',
4713
4018
  'Communication?subject=$',
@@ -4729,12 +4034,14 @@
4729
4034
  })),
4730
4035
  }), createCommunication: (resource, sender, text) => ({
4731
4036
  resourceType: 'Communication',
4037
+ status: 'completed',
4732
4038
  subject: core.createReference(resource),
4733
4039
  sender: core.createReference(sender),
4734
4040
  sent: new Date().toISOString(),
4735
4041
  payload: [{ contentString: text }],
4736
4042
  }), createMedia: (resource, operator, content) => ({
4737
4043
  resourceType: 'Media',
4044
+ status: 'completed',
4738
4045
  subject: core.createReference(resource),
4739
4046
  operator: core.createReference(operator),
4740
4047
  issued: new Date().toISOString(),
@@ -4777,10 +4084,9 @@
4777
4084
  }
4778
4085
  return (React__default["default"].createElement("div", { className: "medplum-questionnaire-builder" },
4779
4086
  React__default["default"].createElement(Form, { testid: "questionnaire-form", onSubmit: () => props.onSubmit(value) },
4780
- React__default["default"].createElement(FormSection, { title: "Plan Title", htmlFor: "title" },
4781
- React__default["default"].createElement(Input, { defaultValue: value.title, onChange: (newValue) => changeProperty('title', newValue) })),
4087
+ React__default["default"].createElement(core$1.TextInput, { label: "Plan Title", defaultValue: value.title, onChange: (e) => changeProperty('title', e.currentTarget.value) }),
4782
4088
  React__default["default"].createElement(ActionArrayBuilder, { actions: value.action || [], selectedKey: selectedKey, setSelectedKey: setSelectedKey, hoverKey: hoverKey, setHoverKey: setHoverKey, onChange: (x) => changeProperty('action', x) }),
4783
- React__default["default"].createElement(Button, { type: "submit", size: "large" }, "Save"))));
4089
+ React__default["default"].createElement(core$1.Button, { type: "submit" }, "Save"))));
4784
4090
  }
4785
4091
  function ActionArrayBuilder(props) {
4786
4092
  const actionsRef = React.useRef();
@@ -4852,17 +4158,9 @@
4852
4158
  props.onChange(Object.assign(Object.assign({}, action), { [property]: value }));
4853
4159
  }
4854
4160
  return (React__default["default"].createElement(React__default["default"].Fragment, null,
4855
- React__default["default"].createElement(FormSection, { title: "Title", htmlFor: `actionTitle-${action.id}` },
4856
- React__default["default"].createElement(Input, { name: `actionTitle-${action.id}`, defaultValue: action.title, onChange: (newValue) => changeProperty('title', newValue) })),
4857
- React__default["default"].createElement(FormSection, { title: "Description", htmlFor: `actionDescription-${action.id}` },
4858
- React__default["default"].createElement(Input, { name: `actionDescription-${action.id}`, defaultValue: action.description, onChange: (newValue) => changeProperty('description', newValue) })),
4859
- React__default["default"].createElement(FormSection, { title: "Type of Action", description: "The type of the action to be performed.", htmlFor: `actionType-${action.id}` },
4860
- React__default["default"].createElement(Select, { name: `actionType-${action.id}`, defaultValue: actionType, onChange: setActionType },
4861
- React__default["default"].createElement("option", null),
4862
- React__default["default"].createElement("option", { value: "appointment" }, "Appointment"),
4863
- React__default["default"].createElement("option", { value: "lab" }, "Lab"),
4864
- React__default["default"].createElement("option", { value: "questionnaire" }, "Questionnaire"),
4865
- React__default["default"].createElement("option", { value: "task" }, "Task"))),
4161
+ React__default["default"].createElement(core$1.TextInput, { name: `actionTitle-${action.id}`, label: "Title", defaultValue: action.title, onChange: (e) => changeProperty('title', e.currentTarget.value) }),
4162
+ React__default["default"].createElement(core$1.TextInput, { name: `actionDescription-${action.id}`, label: "Description", defaultValue: action.description, onChange: (e) => changeProperty('description', e.currentTarget.value) }),
4163
+ React__default["default"].createElement(core$1.NativeSelect, { label: "Type of Action", description: "The type of the action to be performed.", name: `actionType-${action.id}`, defaultValue: actionType, onChange: (e) => setActionType(e.currentTarget.value), data: ['', 'appointment', 'lab', 'questionnaire', 'task'] }),
4866
4164
  action.action && action.action.length > 0 && (React__default["default"].createElement(ActionArrayBuilder, { actions: action.action, selectedKey: props.selectedKey, setSelectedKey: props.setSelectedKey, hoverKey: props.hoverKey, setHoverKey: props.setHoverKey, onChange: (x) => changeProperty('action', x) })),
4867
4165
  (() => {
4868
4166
  switch (actionType) {
@@ -4878,23 +4176,23 @@
4878
4176
  return null;
4879
4177
  }
4880
4178
  })(),
4881
- React__default["default"].createElement(FormSection, { title: "Timing", description: "When the action should take place.", htmlFor: 'timing-' + action.id },
4882
- React__default["default"].createElement(ActionTimingInput, { name: 'timing-' + action.id, action: action, onChange: props.onChange }))));
4179
+ React__default["default"].createElement("p", null, "Timing"),
4180
+ React__default["default"].createElement("p", null, "When the action should take place."),
4181
+ React__default["default"].createElement(ActionTimingInput, { name: 'timing-' + action.id, action: action, onChange: props.onChange })));
4883
4182
  }
4884
4183
  function ActionResourceTypeBuilder(props) {
4885
4184
  const { id, definitionCanonical } = props.action;
4886
4185
  const reference = (definitionCanonical === null || definitionCanonical === void 0 ? void 0 : definitionCanonical.startsWith(props.resourceType + '/'))
4887
4186
  ? { reference: definitionCanonical }
4888
4187
  : undefined;
4889
- return (React__default["default"].createElement(FormSection, { title: props.title, description: props.description, htmlFor: id },
4890
- React__default["default"].createElement(ResourceInput, { name: id, resourceType: props.resourceType, defaultValue: reference, loadOnFocus: true, onChange: (newValue) => {
4891
- if (newValue) {
4892
- props.onChange(Object.assign(Object.assign({}, props.action), { definitionCanonical: core.getReferenceString(newValue) }));
4893
- }
4894
- else {
4895
- props.onChange(Object.assign(Object.assign({}, props.action), { definitionCanonical: undefined }));
4896
- }
4897
- } })));
4188
+ return (React__default["default"].createElement(ResourceInput, { name: id, resourceType: props.resourceType, defaultValue: reference, loadOnFocus: true, onChange: (newValue) => {
4189
+ if (newValue) {
4190
+ props.onChange(Object.assign(Object.assign({}, props.action), { definitionCanonical: core.getReferenceString(newValue) }));
4191
+ }
4192
+ else {
4193
+ props.onChange(Object.assign(Object.assign({}, props.action), { definitionCanonical: undefined }));
4194
+ }
4195
+ } }));
4898
4196
  }
4899
4197
  function ActionTimingInput(props) {
4900
4198
  const value = props.action;
@@ -5009,7 +4307,7 @@
5009
4307
  } },
5010
4308
  questionnaire.title && React__default["default"].createElement("h1", null, questionnaire.title),
5011
4309
  questionnaire.item && (React__default["default"].createElement(QuestionnaireFormItemArray, { items: questionnaire.item, answers: answers, onChange: setItems })),
5012
- React__default["default"].createElement(Button, { type: "submit", size: "large" }, props.submitButtonText || 'OK')));
4310
+ React__default["default"].createElement(core$1.Button, { type: "submit" }, props.submitButtonText || 'OK')));
5013
4311
  }
5014
4312
  function QuestionnaireFormItemArray(props) {
5015
4313
  const [responseItems, setResponseItems] = React.useState(buildInitialResponseItems(props.items));
@@ -5032,10 +4330,10 @@
5032
4330
  if (item.type === exports.QuestionnaireItemType.boolean) {
5033
4331
  const initial = item.initial && item.initial.length > 0 ? item.initial[0] : undefined;
5034
4332
  return (React__default["default"].createElement(CheckboxFormSection, { key: item.linkId, title: item.text, htmlFor: item.linkId },
5035
- React__default["default"].createElement(Checkbox, { name: item.linkId, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueBoolean, onChange: (newValue) => setResponseItem(index, {
4333
+ React__default["default"].createElement(core$1.Checkbox, { id: item.linkId, name: item.linkId, defaultChecked: initial === null || initial === void 0 ? void 0 : initial.valueBoolean, onChange: (e) => setResponseItem(index, {
5036
4334
  linkId: item.linkId,
5037
4335
  text: item.text,
5038
- answer: [{ valueBoolean: newValue }],
4336
+ answer: [{ valueBoolean: e.currentTarget.checked }],
5039
4337
  }) })));
5040
4338
  }
5041
4339
  return (React__default["default"].createElement(FormSection, { key: item.linkId, htmlFor: item.linkId, title: item.text || '' },
@@ -5073,23 +4371,22 @@
5073
4371
  React__default["default"].createElement("h3", null, item.text),
5074
4372
  item.item && (React__default["default"].createElement(QuestionnaireFormItemArray, { items: item.item, answers: props.answers, onChange: onChangeItem }))));
5075
4373
  case exports.QuestionnaireItemType.boolean:
5076
- return (React__default["default"].createElement(Checkbox, { name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueBoolean, onChange: (newValue) => onChangeAnswer({ valueBoolean: newValue }) }));
4374
+ return (React__default["default"].createElement(core$1.Checkbox, { id: name, name: name, defaultChecked: initial === null || initial === void 0 ? void 0 : initial.valueBoolean, onChange: (e) => onChangeAnswer({ valueBoolean: e.currentTarget.checked }) }));
5077
4375
  case exports.QuestionnaireItemType.decimal:
5078
- return (React__default["default"].createElement(Input, { type: "number", step: "any", name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueDecimal, onChange: (newValue) => onChangeAnswer({ valueDecimal: parseFloat(newValue) }) }));
4376
+ return (React__default["default"].createElement(core$1.TextInput, { type: "number", step: "any", id: name, name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueDecimal, onChange: (e) => onChangeAnswer({ valueDecimal: e.currentTarget.valueAsNumber }) }));
5079
4377
  case exports.QuestionnaireItemType.integer:
5080
- return (React__default["default"].createElement(Input, { type: "number", step: 1, name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueInteger, onChange: (newValue) => onChangeAnswer({ valueInteger: parseInt(newValue) }) }));
4378
+ return (React__default["default"].createElement(core$1.TextInput, { type: "number", step: 1, id: name, name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueInteger, onChange: (e) => onChangeAnswer({ valueInteger: e.currentTarget.valueAsNumber }) }));
5081
4379
  case exports.QuestionnaireItemType.date:
5082
- return (React__default["default"].createElement(Input, { type: "date", name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueDate, onChange: (newValue) => onChangeAnswer({ valueDate: newValue }) }));
4380
+ return (React__default["default"].createElement(core$1.TextInput, { type: "date", id: name, name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueDate, onChange: (e) => onChangeAnswer({ valueDate: e.currentTarget.value }) }));
5083
4381
  case exports.QuestionnaireItemType.dateTime:
5084
- return (React__default["default"].createElement(DateTimeInput, { type: "datetime-local", name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueDateTime, onChange: (newValue) => onChangeAnswer({ valueDateTime: newValue }) }));
4382
+ return (React__default["default"].createElement(DateTimeInput, { name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueDateTime, onChange: (newValue) => onChangeAnswer({ valueDateTime: newValue }) }));
5085
4383
  case exports.QuestionnaireItemType.time:
5086
- return (React__default["default"].createElement(Input, { type: "time", name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueTime, onChange: (newValue) => onChangeAnswer({ valueTime: newValue }) }));
4384
+ return (React__default["default"].createElement(core$1.TextInput, { type: "time", id: name, name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueTime, onChange: (e) => onChangeAnswer({ valueTime: e.currentTarget.value }) }));
5087
4385
  case exports.QuestionnaireItemType.string:
5088
- return (React__default["default"].createElement(Input, { type: "text", name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueString, onChange: (newValue) => onChangeAnswer({ valueString: newValue }) }));
5089
- case exports.QuestionnaireItemType.text:
5090
- return (React__default["default"].createElement(TextArea, { name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueString, onChange: (newValue) => onChangeAnswer({ valueString: newValue }) }));
5091
4386
  case exports.QuestionnaireItemType.url:
5092
- return (React__default["default"].createElement(Input, { type: "url", name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueUri, onChange: (newValue) => onChangeAnswer({ valueUri: newValue }) }));
4387
+ return (React__default["default"].createElement(core$1.TextInput, { id: name, name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueString, onChange: (e) => onChangeAnswer({ valueString: e.currentTarget.value }) }));
4388
+ case exports.QuestionnaireItemType.text:
4389
+ return (React__default["default"].createElement(core$1.Textarea, { id: name, name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueString, onChange: (e) => onChangeAnswer({ valueString: e.currentTarget.value }) }));
5093
4390
  case exports.QuestionnaireItemType.attachment:
5094
4391
  return (React__default["default"].createElement(AttachmentInput, { name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueAttachment, onChange: (newValue) => onChangeAnswer({ valueAttachment: newValue }) }));
5095
4392
  case exports.QuestionnaireItemType.reference:
@@ -5109,9 +4406,15 @@
5109
4406
  }
5110
4407
  function QuestionnaireChoiceDropDownInput(props) {
5111
4408
  const { name, item, initial } = props;
5112
- const valueElementDefinition = core.globalSchema.types['QuestionnaireItemAnswerOption'].properties['value[x]'];
5113
4409
  const initialValue = core.getTypedPropertyValue({ type: 'QuestionnaireItemInitial', value: initial }, 'value');
5114
- return (React__default["default"].createElement("select", { id: name, name: name, className: "medplum-select", onChange: (e) => {
4410
+ const data = [''];
4411
+ if (item.answerOption) {
4412
+ for (const option of item.answerOption) {
4413
+ const optionValue = core.getTypedPropertyValue({ type: 'QuestionnaireItemAnswerOption', value: option }, 'value');
4414
+ data.push(typedValueToString(optionValue));
4415
+ }
4416
+ }
4417
+ return (React__default["default"].createElement(core$1.NativeSelect, { id: name, name: name, className: "medplum-select", onChange: (e) => {
5115
4418
  const index = e.currentTarget.selectedIndex;
5116
4419
  if (index === 0) {
5117
4420
  props.onChangeAnswer({});
@@ -5121,15 +4424,19 @@
5121
4424
  const optionValue = core.getTypedPropertyValue({ type: 'QuestionnaireItemAnswerOption', value: option }, 'value');
5122
4425
  const propertyName = 'value' + core.capitalize(optionValue.type);
5123
4426
  props.onChangeAnswer({ [propertyName]: optionValue.value });
5124
- } },
5125
- React__default["default"].createElement("option", null),
5126
- item.answerOption &&
5127
- item.answerOption.map((option, index) => {
5128
- const optionValue = core.getTypedPropertyValue({ type: 'QuestionnaireItemAnswerOption', value: option }, 'value');
5129
- const optionName = `${name}-option-${index}`;
5130
- return (React__default["default"].createElement("option", { key: optionName, value: optionValue.value, selected: initialValue && core.stringify(optionValue) === core.stringify(initialValue) },
5131
- React__default["default"].createElement(ResourcePropertyDisplay, { property: valueElementDefinition, propertyType: optionValue.type, value: optionValue.value })));
5132
- })));
4427
+ }, defaultValue: typedValueToString(initialValue), data: data }));
4428
+ }
4429
+ function typedValueToString(typedValue) {
4430
+ if (!typedValue) {
4431
+ return undefined;
4432
+ }
4433
+ if (typedValue.type === 'CodeableConcept') {
4434
+ return typedValue.value.coding[0].display;
4435
+ }
4436
+ if (typedValue.type === 'Coding') {
4437
+ return typedValue.value.display;
4438
+ }
4439
+ return typedValue.value.toString();
5133
4440
  }
5134
4441
  function QuestionnaireChoiceRadioInput(props) {
5135
4442
  const { name, item, initial, onChangeAnswer } = props;
@@ -5243,7 +4550,7 @@
5243
4550
  return (React__default["default"].createElement("div", { className: "medplum-questionnaire-builder" },
5244
4551
  React__default["default"].createElement(Form, { testid: "questionnaire-form", onSubmit: () => props.onSubmit(value) },
5245
4552
  React__default["default"].createElement(ItemBuilder, { item: value, selectedKey: selectedKey, setSelectedKey: setSelectedKey, hoverKey: hoverKey, setHoverKey: setHoverKey, onChange: setValue }),
5246
- React__default["default"].createElement(Button, { type: "submit", size: "large" }, "Save"))));
4553
+ React__default["default"].createElement(core$1.Button, { type: "submit" }, "Save"))));
5247
4554
  }
5248
4555
  function ItemBuilder(props) {
5249
4556
  var _a;
@@ -5284,26 +4591,26 @@
5284
4591
  return (React__default["default"].createElement("div", { "data-testid": item.linkId, className: className, onClick: onClick, onMouseOver: onHover },
5285
4592
  editing ? (React__default["default"].createElement(React__default["default"].Fragment, null,
5286
4593
  isResource && (React__default["default"].createElement("div", null,
5287
- React__default["default"].createElement(Input, { defaultValue: resource.title, onChange: (newValue) => changeProperty('title', newValue) }))),
4594
+ React__default["default"].createElement(core$1.TextInput, { defaultValue: resource.title, onChange: (e) => changeProperty('title', e.currentTarget.value) }))),
5288
4595
  !isContainer && (React__default["default"].createElement("div", null,
5289
- React__default["default"].createElement(Select, { defaultValue: item.type, onChange: (newValue) => changeProperty('type', newValue) },
5290
- React__default["default"].createElement("option", { value: "display" }, "Display"),
5291
- React__default["default"].createElement("optgroup", { label: "Question" },
5292
- React__default["default"].createElement("option", { value: "boolean" }, "Boolean"),
5293
- React__default["default"].createElement("option", { value: "decimal" }, "Decimal"),
5294
- React__default["default"].createElement("option", { value: "integer" }, "Integer"),
5295
- React__default["default"].createElement("option", { value: "date" }, "Date"),
5296
- React__default["default"].createElement("option", { value: "dateTime" }, "Date/Time"),
5297
- React__default["default"].createElement("option", { value: "time" }, "Time"),
5298
- React__default["default"].createElement("option", { value: "string" }, "String"),
5299
- React__default["default"].createElement("option", { value: "text" }, "Text"),
5300
- React__default["default"].createElement("option", { value: "url" }, "URL"),
5301
- React__default["default"].createElement("option", { value: "choice" }, "Choice"),
5302
- React__default["default"].createElement("option", { value: "open-choice" }, "Open Choice"),
5303
- React__default["default"].createElement("option", { value: "attachment" }, "Attachment"),
5304
- React__default["default"].createElement("option", { value: "reference" }, "Reference"),
5305
- React__default["default"].createElement("option", { value: "quantity" }, "Quantity"))))),
5306
- !isResource && (React__default["default"].createElement(TextArea, { style: { width: '95%', height: '100px', minHeight: '100px', margin: '8px 4px 4px 4px' }, defaultValue: item.text, onChange: (newValue) => changeProperty('text', newValue) })),
4596
+ React__default["default"].createElement(core$1.NativeSelect, { defaultValue: item.type, onChange: (e) => changeProperty('type', e.currentTarget.value), data: [
4597
+ { value: 'display', label: 'Display' },
4598
+ { value: 'boolean', label: 'Boolean' },
4599
+ { value: 'decimal', label: 'Decimal' },
4600
+ { value: 'integer', label: 'Integer' },
4601
+ { value: 'date', label: 'Date' },
4602
+ { value: 'dateTime', label: 'Date/Time' },
4603
+ { value: 'time', label: 'Time' },
4604
+ { value: 'string', label: 'String' },
4605
+ { value: 'text', label: 'Text' },
4606
+ { value: 'url', label: 'URL' },
4607
+ { value: 'choice', label: 'Choice' },
4608
+ { value: 'open-choice', label: 'Open Choice' },
4609
+ { value: 'attachment', label: 'Attachment' },
4610
+ { value: 'reference', label: 'Reference' },
4611
+ { value: 'quantity', label: 'Quantity' },
4612
+ ] }))),
4613
+ !isResource && (React__default["default"].createElement(core$1.Textarea, { style: { width: '95%', height: '100px', minHeight: '100px', margin: '8px 4px 4px 4px' }, defaultValue: item.text, onChange: (e) => changeProperty('text', e.currentTarget.value) })),
5307
4614
  isChoiceQuestion(item) && (React__default["default"].createElement(AnswerBuilder, { options: item.answerOption, onChange: (newOptions) => changeProperty('answerOption', newOptions) })))) : (React__default["default"].createElement(React__default["default"].Fragment, null,
5308
4615
  resource.title && React__default["default"].createElement("h1", null, resource.title),
5309
4616
  item.text && React__default["default"].createElement("p", null, item.text),
@@ -5311,7 +4618,7 @@
5311
4618
  item.item &&
5312
4619
  item.item.map((i) => (React__default["default"].createElement("div", { key: i.id },
5313
4620
  React__default["default"].createElement(ItemBuilder, { item: i, selectedKey: props.selectedKey, setSelectedKey: props.setSelectedKey, hoverKey: props.hoverKey, setHoverKey: props.setHoverKey, onChange: changeItem, onRemove: () => removeItem(i) })))),
5314
- !isContainer && (React__default["default"].createElement("div", { className: "top-actions" }, editing ? (React__default["default"].createElement(Input, { defaultValue: item.linkId, onChange: (newValue) => changeProperty('linkId', newValue), size: 4 })) : (React__default["default"].createElement("div", null, linkId)))),
4621
+ !isContainer && (React__default["default"].createElement("div", { className: "top-actions" }, editing ? (React__default["default"].createElement(core$1.TextInput, { defaultValue: item.linkId, onChange: (e) => changeProperty('linkId', e.currentTarget.value) })) : (React__default["default"].createElement("div", null, linkId)))),
5315
4622
  React__default["default"].createElement("div", { className: "bottom-actions" },
5316
4623
  isContainer && (React__default["default"].createElement(React__default["default"].Fragment, null,
5317
4624
  React__default["default"].createElement("a", { href: "#", onClick: (e) => {
@@ -5421,8 +4728,61 @@
5421
4728
  return options.map((option) => (Object.assign(Object.assign({}, option), { id: option.id || generateId() })));
5422
4729
  }
5423
4730
 
4731
+ /*
4732
+ * Request status: https://hl7.org/fhir/valueset-request-status.html
4733
+ * draft, active, on-hold, revoked, completed, entered-in-error, unknown
4734
+ *
4735
+ * Publication status: https://hl7.org/fhir/valueset-publication-status.html
4736
+ * draft, active, retired, unknown
4737
+ *
4738
+ * Observation status: https://www.hl7.org/fhir/valueset-observation-status.html
4739
+ * registered, preliminary, final, amended, cancelled, entered-in-error, unknown
4740
+ *
4741
+ * DiagnosticReport status: https://hl7.org/fhir/valueset-diagnostic-report-status.html
4742
+ * registered, preliminary, final, amended, corrected, appended, cancelled, entered-in-error, unknown
4743
+ *
4744
+ * Task status: https://hl7.org/fhir/valueset-task-status.html
4745
+ * draft, requested, received, accepted, rejected, ready, cancelled, in-progress, on-hold, failed, completed, entered-in-error
4746
+ *
4747
+ * Appointment status: https://www.hl7.org/fhir/valueset-appointmentstatus.html
4748
+ * proposed, pending, booked, arrived, fulfilled, cancelled, noshow, entered-in-error, chcked-in, waitlist
4749
+ */
4750
+ const statusToColor = {
4751
+ draft: 'blue',
4752
+ active: 'blue',
4753
+ 'on-hold': 'yellow',
4754
+ revoked: 'red',
4755
+ completed: 'green',
4756
+ 'entered-in-error': 'red',
4757
+ unknown: 'gray',
4758
+ retired: 'gray',
4759
+ registered: 'blue',
4760
+ preliminary: 'blue',
4761
+ final: 'green',
4762
+ amended: 'yellow',
4763
+ cancelled: 'red',
4764
+ requested: 'blue',
4765
+ received: 'blue',
4766
+ accepted: 'blue',
4767
+ rejected: 'red',
4768
+ ready: 'blue',
4769
+ 'in-progress': 'blue',
4770
+ failed: 'red',
4771
+ proposed: 'blue',
4772
+ pending: 'blue',
4773
+ booked: 'blue',
4774
+ arrived: 'blue',
4775
+ fulfilled: 'green',
4776
+ noshow: 'red',
4777
+ 'checked-in': 'blue',
4778
+ waitlist: 'gray',
4779
+ routine: 'gray',
4780
+ urgent: 'red',
4781
+ asap: 'red',
4782
+ stat: 'red',
4783
+ };
5424
4784
  function StatusBadge(props) {
5425
- return React__default["default"].createElement("span", { className: `medplum-status medplum-status-${props.status}` }, props.status);
4785
+ return React__default["default"].createElement(core$1.Badge, { color: statusToColor[props.status] }, props.status);
5426
4786
  }
5427
4787
 
5428
4788
  function RequestGroupDisplay(props) {
@@ -5459,8 +4819,8 @@
5459
4819
  "Status: ",
5460
4820
  React__default["default"].createElement(StatusBadge, { status: (task === null || task === void 0 ? void 0 : task.status) || 'unknown' }))),
5461
4821
  React__default["default"].createElement("div", { className: "medplum-request-group-task-actions" },
5462
- taskInput && !taskOutput && React__default["default"].createElement(Button, { onClick: () => props.onStart(task, taskInput) }, "Start"),
5463
- taskInput && taskOutput && (React__default["default"].createElement(Button, { onClick: () => props.onEdit(task, taskInput, taskOutput) }, "Edit")))));
4822
+ taskInput && !taskOutput && React__default["default"].createElement(core$1.Button, { onClick: () => props.onStart(task, taskInput) }, "Start"),
4823
+ taskInput && taskOutput && (React__default["default"].createElement(core$1.Button, { onClick: () => props.onEdit(task, taskInput, taskOutput) }, "Edit")))));
5464
4824
  })));
5465
4825
  function buildBatchRequest(request) {
5466
4826
  var _a;
@@ -5692,8 +5052,8 @@
5692
5052
  React__default["default"].createElement("table", { className: "medplum-blame" },
5693
5053
  React__default["default"].createElement("tbody", null, table.map((row, index) => (React__default["default"].createElement("tr", { key: 'row-' + index, className: row.span > 0 ? 'start-row' : 'normal-row' },
5694
5054
  row.span > 0 && (React__default["default"].createElement("td", { className: "details", rowSpan: row.span },
5695
- React__default["default"].createElement(InputRow, { justifyContent: "space-between" },
5696
- React__default["default"].createElement(ResourceBadge, { value: row.meta.author, size: "xsmall", link: true }),
5055
+ React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
5056
+ React__default["default"].createElement(ResourceBadge, { value: row.meta.author, link: true }),
5697
5057
  React__default["default"].createElement(MedplumLink, { to: getVersionUrl$1(resource, row.meta.versionId) }, getTimeString(row.meta.lastUpdated))))),
5698
5058
  React__default["default"].createElement("td", { className: "line-number" }, index + 1),
5699
5059
  React__default["default"].createElement("td", { className: "line" },
@@ -5767,7 +5127,7 @@
5767
5127
  if (!value) {
5768
5128
  return React__default["default"].createElement("div", null, "Loading...");
5769
5129
  }
5770
- return (React__default["default"].createElement("table", { className: "medplum-table" },
5130
+ return (React__default["default"].createElement(core$1.Table, { withBorder: true, withColumnBorders: true },
5771
5131
  React__default["default"].createElement("thead", null,
5772
5132
  React__default["default"].createElement("tr", null,
5773
5133
  React__default["default"].createElement("th", null, "Author"),
@@ -5817,11 +5177,11 @@
5817
5177
  }
5818
5178
  const grid = React.useMemo(() => buildGrid(month, props.slots), [month, props.slots]);
5819
5179
  return (React__default["default"].createElement("div", null,
5820
- React__default["default"].createElement(InputRow, null,
5180
+ React__default["default"].createElement(core$1.Group, { position: "apart", spacing: "xs", grow: true, noWrap: true },
5821
5181
  React__default["default"].createElement("p", { style: { flex: 1 } }, getMonthString(month)),
5822
- React__default["default"].createElement("p", null,
5823
- React__default["default"].createElement(Button, { label: "Previous month", onClick: () => moveMonth(-1) }, "<"),
5824
- React__default["default"].createElement(Button, { label: "Next month", onClick: () => moveMonth(1) }, ">"))),
5182
+ React__default["default"].createElement(core$1.Group, { position: "right", spacing: "xs" },
5183
+ React__default["default"].createElement(core$1.Button, { variant: "outline", "aria-label": "Previous month", onClick: () => moveMonth(-1) }, "<"),
5184
+ React__default["default"].createElement(core$1.Button, { variant: "outline", "aria-label": "Next month", onClick: () => moveMonth(1) }, ">"))),
5825
5185
  React__default["default"].createElement("table", { className: "medplum-calendar-table" },
5826
5186
  React__default["default"].createElement("thead", null,
5827
5187
  React__default["default"].createElement("tr", null,
@@ -5832,7 +5192,7 @@
5832
5192
  React__default["default"].createElement("th", null, "THU"),
5833
5193
  React__default["default"].createElement("th", null, "FRI"),
5834
5194
  React__default["default"].createElement("th", null, "SAT"))),
5835
- React__default["default"].createElement("tbody", null, grid.map((week, weekIndex) => (React__default["default"].createElement("tr", { key: 'week-' + weekIndex }, week.map((day, dayIndex) => (React__default["default"].createElement("td", { key: 'day-' + dayIndex }, day && (React__default["default"].createElement("button", { disabled: !day.available, onClick: () => onClick(day.date) }, day.date.getDate()))))))))))));
5195
+ React__default["default"].createElement("tbody", null, grid.map((week, weekIndex) => (React__default["default"].createElement("tr", { key: 'week-' + weekIndex }, week.map((day, dayIndex) => (React__default["default"].createElement("td", { key: 'day-' + dayIndex }, day && (React__default["default"].createElement(core$1.Button, { disabled: !day.available, onClick: () => onClick(day.date) }, day.date.getDate()))))))))))));
5836
5196
  }
5837
5197
  function getStartMonth() {
5838
5198
  const result = new Date();
@@ -5922,8 +5282,8 @@
5922
5282
  const actor = (_a = schedule.actor) === null || _a === void 0 ? void 0 : _a[0];
5923
5283
  return (React__default["default"].createElement("div", { className: "medplum-calendar-container", "data-testid": "scheduler" },
5924
5284
  React__default["default"].createElement("div", { className: "medplum-calendar-info-pane" },
5925
- actor && React__default["default"].createElement(Avatar, { value: actor, size: "large" }),
5926
- actor && (React__default["default"].createElement("h1", null,
5285
+ actor && React__default["default"].createElement(ResourceAvatar, { value: actor, size: "xl" }),
5286
+ actor && (React__default["default"].createElement(core$1.Text, { size: "xl", weight: 500 },
5927
5287
  React__default["default"].createElement(ResourceName, { value: actor }))),
5928
5288
  React__default["default"].createElement("p", null, "1 hour"),
5929
5289
  date && React__default["default"].createElement("p", null, date.toLocaleDateString()),
@@ -5934,12 +5294,12 @@
5934
5294
  React__default["default"].createElement(CalendarInput, { slots: slots, onChangeMonth: setMonth, onClick: setDate }))),
5935
5295
  date && !slot && (React__default["default"].createElement("div", null,
5936
5296
  React__default["default"].createElement("h3", null, "Select time"),
5937
- slots.map((s) => {
5297
+ React__default["default"].createElement(core$1.Stack, null, slots.map((s) => {
5938
5298
  const slotStart = new Date(s.start);
5939
5299
  return (slotStart.getTime() > date.getTime() &&
5940
5300
  slotStart.getTime() < date.getTime() + 24 * 3600 * 1000 && (React__default["default"].createElement("div", { key: s.id },
5941
- React__default["default"].createElement(Button, { style: { width: 150 }, onClick: () => setSlot(s) }, formatTime(slotStart)))));
5942
- }))),
5301
+ React__default["default"].createElement(core$1.Button, { variant: "outline", style: { width: 150 }, onClick: () => setSlot(s) }, formatTime(slotStart)))));
5302
+ })))),
5943
5303
  date && slot && !response && (React__default["default"].createElement(QuestionnaireForm, { questionnaire: questionnaire, submitButtonText: 'Next', onSubmit: setResponse })),
5944
5304
  date && slot && response && (React__default["default"].createElement("div", null,
5945
5305
  React__default["default"].createElement("h3", null, "You're all set!"),
@@ -5990,6 +5350,7 @@
5990
5350
  ],
5991
5351
  }), createCommunication: (resource, sender, text) => ({
5992
5352
  resourceType: 'Communication',
5353
+ status: 'completed',
5993
5354
  basedOn: [core.createReference(resource)],
5994
5355
  subject: resource.subject,
5995
5356
  sender: core.createReference(sender),
@@ -5997,6 +5358,7 @@
5997
5358
  payload: [{ contentString: text }],
5998
5359
  }), createMedia: (resource, operator, content) => ({
5999
5360
  resourceType: 'Media',
5361
+ status: 'completed',
6000
5362
  basedOn: [core.createReference(resource)],
6001
5363
  subject: resource.subject,
6002
5364
  operator: core.createReference(operator),
@@ -6005,62 +5367,13 @@
6005
5367
  }) }));
6006
5368
  }
6007
5369
 
6008
- function Tab(props) {
6009
- let className = 'medplum-tab';
6010
- if (props.selected) {
6011
- className += ' selected';
6012
- }
6013
- function clickHandler(e) {
6014
- killEvent(e);
6015
- // The onClick prop is set by TabBar as parent component.
6016
- // Using Tab outside of a TabBar is unsupported.
6017
- props.onClick(props.name, e.button);
6018
- }
6019
- return (React__default["default"].createElement("a", { href: `#${props.name}`, role: "tab", "aria-selected": props.selected, className: className, onClick: clickHandler, onAuxClick: clickHandler }, props.label));
6020
- }
6021
-
6022
- function TabList(props) {
6023
- return (React__default["default"].createElement(Scrollable, { className: "medplum-surface", height: 50 },
6024
- React__default["default"].createElement("div", { role: "tablist", className: "medplum-tablist" },
6025
- React__default["default"].createElement("div", { className: "medplum-tablist-foreground" }, React__default["default"].Children.map(props.children, (child, tabIndex) => {
6026
- if (React__default["default"].isValidElement(child) && child.type === Tab) {
6027
- return React__default["default"].cloneElement(child, {
6028
- selected: child.props.name === props.value,
6029
- onClick: props.onChange,
6030
- tabIndex,
6031
- });
6032
- }
6033
- else {
6034
- return null;
6035
- }
6036
- })))));
6037
- }
6038
-
6039
- function TabPanel(props) {
6040
- return React__default["default"].createElement("div", { role: "tabpanel" }, props.children);
6041
- }
6042
-
6043
- function TabSwitch(props) {
6044
- return (React__default["default"].createElement(React__default["default"].Fragment, null, React__default["default"].Children.map(props.children, (child) => {
6045
- if (React__default["default"].isValidElement(child) && child.type === TabPanel && child.props.name === props.value) {
6046
- return child;
6047
- }
6048
- else {
6049
- return null;
6050
- }
6051
- })));
6052
- }
6053
-
6054
5370
  exports.AddressDisplay = AddressDisplay;
6055
5371
  exports.AddressInput = AddressInput;
6056
5372
  exports.AttachmentArrayDisplay = AttachmentArrayDisplay;
6057
5373
  exports.AttachmentArrayInput = AttachmentArrayInput;
5374
+ exports.AttachmentButton = AttachmentButton;
6058
5375
  exports.AttachmentInput = AttachmentInput;
6059
- exports.Autocomplete = Autocomplete;
6060
- exports.Avatar = Avatar;
6061
5376
  exports.BackboneElementInput = BackboneElementInput;
6062
- exports.Button = Button;
6063
- exports.Checkbox = Checkbox;
6064
5377
  exports.CheckboxFormSection = CheckboxFormSection;
6065
5378
  exports.CodeInput = CodeInput;
6066
5379
  exports.CodeableConceptDisplay = CodeableConceptDisplay;
@@ -6074,33 +5387,25 @@
6074
5387
  exports.DescriptionList = DescriptionList;
6075
5388
  exports.DescriptionListEntry = DescriptionListEntry;
6076
5389
  exports.DiagnosticReportDisplay = DiagnosticReportDisplay;
6077
- exports.Dialog = Dialog;
6078
5390
  exports.Document = Document;
6079
5391
  exports.ElementDefinitionInputSelector = ElementDefinitionInputSelector;
6080
5392
  exports.ElementDefinitionTypeInput = ElementDefinitionTypeInput;
6081
5393
  exports.EncounterTimeline = EncounterTimeline;
6082
5394
  exports.ErrorBoundary = ErrorBoundary;
6083
5395
  exports.FhirPathTable = FhirPathTable;
6084
- exports.FooterLinks = FooterLinks;
6085
5396
  exports.Form = Form;
6086
5397
  exports.FormSection = FormSection;
6087
- exports.Header = Header;
6088
5398
  exports.HumanNameDisplay = HumanNameDisplay;
6089
5399
  exports.HumanNameInput = HumanNameInput;
6090
5400
  exports.IdentifierInput = IdentifierInput;
6091
- exports.Input = Input;
6092
- exports.InputRow = InputRow;
6093
- exports.Loading = Loading;
6094
5401
  exports.Logo = Logo;
6095
5402
  exports.MedplumLink = MedplumLink;
6096
5403
  exports.MedplumProvider = MedplumProvider;
6097
5404
  exports.MemoizedFhirPathTable = MemoizedFhirPathTable;
6098
5405
  exports.MemoizedSearchControl = MemoizedSearchControl;
6099
- exports.MenuItem = MenuItem;
6100
5406
  exports.ObservationTable = ObservationTable;
6101
5407
  exports.PatientTimeline = PatientTimeline;
6102
5408
  exports.PlanDefinitionBuilder = PlanDefinitionBuilder;
6103
- exports.Popup = Popup;
6104
5409
  exports.QuestionnaireBuilder = QuestionnaireBuilder;
6105
5410
  exports.QuestionnaireForm = QuestionnaireForm;
6106
5411
  exports.QuestionnaireFormItem = QuestionnaireFormItem;
@@ -6111,6 +5416,7 @@
6111
5416
  exports.RequestGroupDisplay = RequestGroupDisplay;
6112
5417
  exports.ResourceArrayDisplay = ResourceArrayDisplay;
6113
5418
  exports.ResourceArrayInput = ResourceArrayInput;
5419
+ exports.ResourceAvatar = ResourceAvatar;
6114
5420
  exports.ResourceBadge = ResourceBadge;
6115
5421
  exports.ResourceBlame = ResourceBlame;
6116
5422
  exports.ResourceDiff = ResourceDiff;
@@ -6123,26 +5429,17 @@
6123
5429
  exports.ResourceTable = ResourceTable;
6124
5430
  exports.ResourceTimeline = ResourceTimeline;
6125
5431
  exports.Scheduler = Scheduler;
6126
- exports.Scrollable = Scrollable;
6127
5432
  exports.SearchChangeEvent = SearchChangeEvent;
6128
5433
  exports.SearchClickEvent = SearchClickEvent;
6129
5434
  exports.SearchControl = SearchControl;
6130
5435
  exports.SearchFieldEditor = SearchFieldEditor;
6131
5436
  exports.SearchFilterEditor = SearchFilterEditor;
6132
5437
  exports.SearchLoadEvent = SearchLoadEvent;
6133
- exports.Select = Select;
6134
5438
  exports.ServiceRequestTimeline = ServiceRequestTimeline;
6135
5439
  exports.SignInForm = SignInForm;
6136
5440
  exports.StatusBadge = StatusBadge;
6137
- exports.Tab = Tab;
6138
- exports.TabList = TabList;
6139
- exports.TabPanel = TabPanel;
6140
- exports.TabSwitch = TabSwitch;
6141
- exports.TextArea = TextArea;
6142
5441
  exports.Timeline = Timeline;
6143
5442
  exports.TimelineItem = TimelineItem;
6144
- exports.TitleBar = TitleBar;
6145
- exports.UploadButton = UploadButton;
6146
5443
  exports.addDateEqualsFilter = addDateEqualsFilter;
6147
5444
  exports.addDateFilter = addDateFilter;
6148
5445
  exports.addDateFilterBetween = addDateFilterBetween;
@@ -6164,6 +5461,8 @@
6164
5461
  exports.createScriptTag = createScriptTag;
6165
5462
  exports.deleteFilter = deleteFilter;
6166
5463
  exports.formatRangeString = formatRangeString;
5464
+ exports.getErrorsForInput = getErrorsForInput;
5465
+ exports.getIssuesForExpression = getIssuesForExpression;
6167
5466
  exports.getOpString = getOpString;
6168
5467
  exports.getRecaptcha = getRecaptcha;
6169
5468
  exports.getSearchOperators = getSearchOperators;
@@ -6175,11 +5474,11 @@
6175
5474
  exports.isChoiceQuestion = isChoiceQuestion;
6176
5475
  exports.isQuestionEnabled = isQuestionEnabled;
6177
5476
  exports.isSortDescending = isSortDescending;
6178
- exports.movePage = movePage;
6179
5477
  exports.parseForm = parseForm;
6180
5478
  exports.renderValue = renderValue;
6181
5479
  exports.setFilters = setFilters;
6182
5480
  exports.setOffset = setOffset;
5481
+ exports.setPage = setPage;
6183
5482
  exports.setPropertyValue = setPropertyValue;
6184
5483
  exports.setSort = setSort;
6185
5484
  exports.sortByDateAndPriority = sortByDateAndPriority;