@medplum/react 0.9.38 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) 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 +1 -0
  4. package/dist/cjs/CodingInput.d.ts +1 -0
  5. package/dist/cjs/DateTimeInput.d.ts +9 -2
  6. package/dist/cjs/ReferenceInput.d.ts +1 -0
  7. package/dist/cjs/ResourceAvatar.d.ts +8 -0
  8. package/dist/cjs/ResourceBadge.d.ts +0 -1
  9. package/dist/cjs/ResourceInput.d.ts +2 -3
  10. package/dist/cjs/SearchPopupMenu.d.ts +0 -4
  11. package/dist/cjs/SearchUtils.d.ts +5 -5
  12. package/dist/cjs/ValueSetAutocomplete.d.ts +10 -0
  13. package/dist/cjs/auth/RegisterForm.d.ts +0 -1
  14. package/dist/cjs/auth/SignInForm.d.ts +0 -1
  15. package/dist/cjs/defaulttheme.css +0 -51
  16. package/dist/cjs/index.d.ts +3 -14
  17. package/dist/cjs/index.js +793 -1493
  18. package/dist/cjs/index.js.map +1 -1
  19. package/dist/cjs/index.min.js +1 -1
  20. package/dist/cjs/index.min.js.map +1 -1
  21. package/dist/cjs/stories/{UploadButton.stories.d.ts → AttachmentButton.stories.d.ts} +1 -0
  22. package/dist/cjs/stories/{Input.stories.d.ts → PeriodInput.stories.d.ts} +1 -1
  23. package/dist/cjs/stories/{Avatar.stories.d.ts → ResourceAvatar.stories.d.ts} +0 -0
  24. package/dist/cjs/stories/ResourceForm.stories.d.ts +1 -0
  25. package/dist/cjs/stories/{Dialog.stories.d.ts → ResourceInput.stories.d.ts} +2 -1
  26. package/dist/cjs/stories/SearchControl.stories.d.ts +1 -0
  27. package/dist/cjs/styles.css +70 -1053
  28. package/dist/cjs/utils/outcomes.d.ts +1 -0
  29. package/dist/esm/AddressInput.js +9 -21
  30. package/dist/esm/AddressInput.js.map +1 -1
  31. package/dist/esm/AnnotationInput.js +2 -2
  32. package/dist/esm/AnnotationInput.js.map +1 -1
  33. package/dist/esm/AttachmentArrayInput.js +11 -8
  34. package/dist/esm/AttachmentArrayInput.js.map +1 -1
  35. package/dist/esm/AttachmentButton.d.ts +9 -0
  36. package/dist/esm/{UploadButton.js → AttachmentButton.js} +9 -9
  37. package/dist/esm/AttachmentButton.js.map +1 -0
  38. package/dist/esm/AttachmentInput.js +3 -3
  39. package/dist/esm/AttachmentInput.js.map +1 -1
  40. package/dist/esm/CalendarInput.js +6 -7
  41. package/dist/esm/CalendarInput.js.map +1 -1
  42. package/dist/esm/CodeInput.d.ts +2 -1
  43. package/dist/esm/CodeInput.js +16 -21
  44. package/dist/esm/CodeInput.js.map +1 -1
  45. package/dist/esm/CodeableConceptInput.d.ts +1 -0
  46. package/dist/esm/CodeableConceptInput.js +18 -33
  47. package/dist/esm/CodeableConceptInput.js.map +1 -1
  48. package/dist/esm/CodingInput.d.ts +1 -0
  49. package/dist/esm/CodingInput.js +24 -23
  50. package/dist/esm/CodingInput.js.map +1 -1
  51. package/dist/esm/ContactDetailInput.js +3 -4
  52. package/dist/esm/ContactDetailInput.js.map +1 -1
  53. package/dist/esm/ContactPointInput.js +5 -21
  54. package/dist/esm/ContactPointInput.js.map +1 -1
  55. package/dist/esm/DateTimeInput.d.ts +9 -2
  56. package/dist/esm/DateTimeInput.js +13 -3
  57. package/dist/esm/DateTimeInput.js.map +1 -1
  58. package/dist/esm/DiagnosticReportDisplay.js +16 -1
  59. package/dist/esm/DiagnosticReportDisplay.js.map +1 -1
  60. package/dist/esm/EncounterTimeline.js +2 -0
  61. package/dist/esm/EncounterTimeline.js.map +1 -1
  62. package/dist/esm/ExtensionInput.js +2 -2
  63. package/dist/esm/ExtensionInput.js.map +1 -1
  64. package/dist/esm/FhirPathTable.js +4 -5
  65. package/dist/esm/FhirPathTable.js.map +1 -1
  66. package/dist/esm/HumanNameInput.js +7 -17
  67. package/dist/esm/HumanNameInput.js.map +1 -1
  68. package/dist/esm/IdentifierInput.js +4 -5
  69. package/dist/esm/IdentifierInput.js.map +1 -1
  70. package/dist/esm/Logo.js +4 -4
  71. package/dist/esm/Logo.js.map +1 -1
  72. package/dist/esm/PatientTimeline.js +2 -0
  73. package/dist/esm/PatientTimeline.js.map +1 -1
  74. package/dist/esm/PeriodInput.js +5 -5
  75. package/dist/esm/PeriodInput.js.map +1 -1
  76. package/dist/esm/PlanDefinitionBuilder.js +17 -29
  77. package/dist/esm/PlanDefinitionBuilder.js.map +1 -1
  78. package/dist/esm/QuantityInput.js +5 -12
  79. package/dist/esm/QuantityInput.js.map +1 -1
  80. package/dist/esm/QuestionnaireBuilder.js +22 -25
  81. package/dist/esm/QuestionnaireBuilder.js.map +1 -1
  82. package/dist/esm/QuestionnaireForm.js +35 -29
  83. package/dist/esm/QuestionnaireForm.js.map +1 -1
  84. package/dist/esm/RangeInput.js +2 -2
  85. package/dist/esm/RangeInput.js.map +1 -1
  86. package/dist/esm/RatioInput.js +2 -2
  87. package/dist/esm/RatioInput.js.map +1 -1
  88. package/dist/esm/ReferenceInput.d.ts +1 -0
  89. package/dist/esm/ReferenceInput.js +4 -6
  90. package/dist/esm/ReferenceInput.js.map +1 -1
  91. package/dist/esm/RequestGroupDisplay.js +1 -1
  92. package/dist/esm/RequestGroupDisplay.js.map +1 -1
  93. package/dist/esm/ResourceArrayInput.js +10 -7
  94. package/dist/esm/ResourceArrayInput.js.map +1 -1
  95. package/dist/esm/ResourceAvatar.d.ts +8 -0
  96. package/dist/esm/ResourceAvatar.js +24 -0
  97. package/dist/esm/ResourceAvatar.js.map +1 -0
  98. package/dist/esm/ResourceBadge.d.ts +0 -1
  99. package/dist/esm/ResourceBadge.js +2 -3
  100. package/dist/esm/ResourceBadge.js.map +1 -1
  101. package/dist/esm/ResourceBlame.js +3 -3
  102. package/dist/esm/ResourceBlame.js.map +1 -1
  103. package/dist/esm/ResourceForm.js +10 -10
  104. package/dist/esm/ResourceForm.js.map +1 -1
  105. package/dist/esm/ResourceInput.d.ts +2 -3
  106. package/dist/esm/ResourceInput.js +37 -29
  107. package/dist/esm/ResourceInput.js.map +1 -1
  108. package/dist/esm/ResourcePropertyInput.js +30 -18
  109. package/dist/esm/ResourcePropertyInput.js.map +1 -1
  110. package/dist/esm/ResourceTimeline.js +19 -15
  111. package/dist/esm/ResourceTimeline.js.map +1 -1
  112. package/dist/esm/Scheduler.js +7 -7
  113. package/dist/esm/Scheduler.js.map +1 -1
  114. package/dist/esm/SearchControl.js +76 -58
  115. package/dist/esm/SearchControl.js.map +1 -1
  116. package/dist/esm/SearchControlField.js.map +1 -1
  117. package/dist/esm/SearchFieldEditor.js +7 -7
  118. package/dist/esm/SearchFieldEditor.js.map +1 -1
  119. package/dist/esm/SearchFilterEditor.js +10 -15
  120. package/dist/esm/SearchFilterEditor.js.map +1 -1
  121. package/dist/esm/SearchFilterValueDialog.js +4 -3
  122. package/dist/esm/SearchFilterValueDialog.js.map +1 -1
  123. package/dist/esm/SearchFilterValueInput.js +6 -7
  124. package/dist/esm/SearchFilterValueInput.js.map +1 -1
  125. package/dist/esm/SearchPopupMenu.d.ts +0 -4
  126. package/dist/esm/SearchPopupMenu.js +59 -73
  127. package/dist/esm/SearchPopupMenu.js.map +1 -1
  128. package/dist/esm/SearchUtils.d.ts +5 -5
  129. package/dist/esm/SearchUtils.js +11 -12
  130. package/dist/esm/SearchUtils.js.map +1 -1
  131. package/dist/esm/ServiceRequestTimeline.js +2 -0
  132. package/dist/esm/ServiceRequestTimeline.js.map +1 -1
  133. package/dist/esm/Timeline.js +12 -20
  134. package/dist/esm/Timeline.js.map +1 -1
  135. package/dist/esm/TimingInput.js +14 -17
  136. package/dist/esm/TimingInput.js.map +1 -1
  137. package/dist/esm/ValueSetAutocomplete.d.ts +10 -0
  138. package/dist/esm/ValueSetAutocomplete.js +57 -0
  139. package/dist/esm/ValueSetAutocomplete.js.map +1 -0
  140. package/dist/esm/auth/AuthenticationForm.js +12 -20
  141. package/dist/esm/auth/AuthenticationForm.js.map +1 -1
  142. package/dist/esm/auth/ChooseProfileForm.js +10 -10
  143. package/dist/esm/auth/ChooseProfileForm.js.map +1 -1
  144. package/dist/esm/auth/NewProjectForm.js +12 -15
  145. package/dist/esm/auth/NewProjectForm.js.map +1 -1
  146. package/dist/esm/auth/NewUserForm.js +25 -33
  147. package/dist/esm/auth/NewUserForm.js.map +1 -1
  148. package/dist/esm/auth/RegisterForm.d.ts +0 -1
  149. package/dist/esm/auth/RegisterForm.js.map +1 -1
  150. package/dist/esm/auth/SignInForm.d.ts +0 -1
  151. package/dist/esm/auth/SignInForm.js.map +1 -1
  152. package/dist/esm/defaulttheme.css +0 -51
  153. package/dist/esm/index.d.ts +3 -14
  154. package/dist/esm/index.js +4 -15
  155. package/dist/esm/index.js.map +1 -1
  156. package/dist/esm/index.min.js +1 -1
  157. package/dist/esm/index.min.js.map +1 -1
  158. package/dist/esm/node_modules/tslib/tslib.es6.js +13 -1
  159. package/dist/esm/node_modules/tslib/tslib.es6.js.map +1 -1
  160. package/dist/esm/stories/{UploadButton.stories.d.ts → AttachmentButton.stories.d.ts} +1 -0
  161. package/dist/{cjs/stories/Select.stories.d.ts → esm/stories/PeriodInput.stories.d.ts} +1 -1
  162. package/dist/esm/stories/{Avatar.stories.d.ts → ResourceAvatar.stories.d.ts} +0 -0
  163. package/dist/esm/stories/ResourceForm.stories.d.ts +1 -0
  164. package/dist/{cjs/stories/FormSection.stories.d.ts → esm/stories/ResourceInput.stories.d.ts} +2 -2
  165. package/dist/esm/stories/SearchControl.stories.d.ts +1 -0
  166. package/dist/esm/styles.css +70 -1053
  167. package/dist/esm/utils/outcomes.d.ts +1 -0
  168. package/dist/esm/utils/outcomes.js +5 -1
  169. package/dist/esm/utils/outcomes.js.map +1 -1
  170. package/package.json +27 -19
  171. package/dist/cjs/Autocomplete.d.ts +0 -20
  172. package/dist/cjs/Avatar.d.ts +0 -12
  173. package/dist/cjs/Button.d.ts +0 -15
  174. package/dist/cjs/Checkbox.d.ts +0 -12
  175. package/dist/cjs/Dialog.d.ts +0 -10
  176. package/dist/cjs/Header.d.ts +0 -12
  177. package/dist/cjs/HeaderSearchInput.d.ts +0 -10
  178. package/dist/cjs/Input.d.ts +0 -22
  179. package/dist/cjs/InputRow.d.ts +0 -7
  180. package/dist/cjs/Loading.d.ts +0 -3
  181. package/dist/cjs/MenuItem.d.ts +0 -9
  182. package/dist/cjs/MenuSeparator.d.ts +0 -3
  183. package/dist/cjs/Popup.d.ts +0 -14
  184. package/dist/cjs/Select.d.ts +0 -16
  185. package/dist/cjs/SubMenu.d.ts +0 -7
  186. package/dist/cjs/TextArea.d.ts +0 -18
  187. package/dist/cjs/UploadButton.d.ts +0 -7
  188. package/dist/cjs/stories/Autocomplete.stories.d.ts +0 -9
  189. package/dist/cjs/stories/Button.stories.d.ts +0 -9
  190. package/dist/cjs/stories/Header.stories.d.ts +0 -8
  191. package/dist/cjs/stories/Loading.stories.d.ts +0 -5
  192. package/dist/esm/Autocomplete.d.ts +0 -20
  193. package/dist/esm/Autocomplete.js +0 -281
  194. package/dist/esm/Autocomplete.js.map +0 -1
  195. package/dist/esm/Avatar.d.ts +0 -12
  196. package/dist/esm/Avatar.js +0 -24
  197. package/dist/esm/Avatar.js.map +0 -1
  198. package/dist/esm/Button.d.ts +0 -15
  199. package/dist/esm/Button.js +0 -13
  200. package/dist/esm/Button.js.map +0 -1
  201. package/dist/esm/Checkbox.d.ts +0 -12
  202. package/dist/esm/Checkbox.js +0 -13
  203. package/dist/esm/Checkbox.js.map +0 -1
  204. package/dist/esm/Dialog.d.ts +0 -10
  205. package/dist/esm/Dialog.js +0 -43
  206. package/dist/esm/Dialog.js.map +0 -1
  207. package/dist/esm/Header.d.ts +0 -12
  208. package/dist/esm/Header.js +0 -99
  209. package/dist/esm/Header.js.map +0 -1
  210. package/dist/esm/HeaderSearchInput.d.ts +0 -10
  211. package/dist/esm/HeaderSearchInput.js +0 -181
  212. package/dist/esm/HeaderSearchInput.js.map +0 -1
  213. package/dist/esm/Input.d.ts +0 -22
  214. package/dist/esm/Input.js +0 -26
  215. package/dist/esm/Input.js.map +0 -1
  216. package/dist/esm/InputRow.d.ts +0 -7
  217. package/dist/esm/InputRow.js +0 -8
  218. package/dist/esm/InputRow.js.map +0 -1
  219. package/dist/esm/Loading.d.ts +0 -3
  220. package/dist/esm/Loading.js +0 -11
  221. package/dist/esm/Loading.js.map +0 -1
  222. package/dist/esm/MenuItem.d.ts +0 -9
  223. package/dist/esm/MenuItem.js +0 -8
  224. package/dist/esm/MenuItem.js.map +0 -1
  225. package/dist/esm/MenuSeparator.d.ts +0 -3
  226. package/dist/esm/MenuSeparator.js +0 -8
  227. package/dist/esm/MenuSeparator.js.map +0 -1
  228. package/dist/esm/Popup.d.ts +0 -14
  229. package/dist/esm/Popup.js +0 -78
  230. package/dist/esm/Popup.js.map +0 -1
  231. package/dist/esm/Select.d.ts +0 -16
  232. package/dist/esm/Select.js +0 -16
  233. package/dist/esm/Select.js.map +0 -1
  234. package/dist/esm/SubMenu.d.ts +0 -7
  235. package/dist/esm/SubMenu.js +0 -38
  236. package/dist/esm/SubMenu.js.map +0 -1
  237. package/dist/esm/TextArea.d.ts +0 -18
  238. package/dist/esm/TextArea.js +0 -16
  239. package/dist/esm/TextArea.js.map +0 -1
  240. package/dist/esm/UploadButton.d.ts +0 -7
  241. package/dist/esm/UploadButton.js.map +0 -1
  242. package/dist/esm/stories/Autocomplete.stories.d.ts +0 -9
  243. package/dist/esm/stories/Button.stories.d.ts +0 -9
  244. package/dist/esm/stories/Dialog.stories.d.ts +0 -5
  245. package/dist/esm/stories/FormSection.stories.d.ts +0 -6
  246. package/dist/esm/stories/Header.stories.d.ts +0 -8
  247. package/dist/esm/stories/Input.stories.d.ts +0 -6
  248. package/dist/esm/stories/Loading.stories.d.ts +0 -5
  249. package/dist/esm/stories/Select.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,77 @@
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) }));
1229
+ }
1230
+
1231
+ function ValueSetAutocomplete(props) {
1232
+ const medplum = useMedplum();
1233
+ const defaultValue = props.defaultValue;
1234
+ const [value, setValue] = React.useState(defaultValue);
1235
+ const [text, setText] = React.useState(defaultValue ? getDisplay(defaultValue) : '');
1236
+ const [loading, setLoading] = React.useState(false);
1237
+ const [data, setData] = React.useState([]);
1238
+ function loadValues(input) {
1239
+ var _a, _b;
1240
+ return __awaiter(this, void 0, void 0, function* () {
1241
+ setLoading(true);
1242
+ const system = (_a = props.property.binding) === null || _a === void 0 ? void 0 : _a.valueSet;
1243
+ const valueSet = yield medplum.searchValueSet(system, input);
1244
+ const valueSetElements = (_b = valueSet.expansion) === null || _b === void 0 ? void 0 : _b.contains;
1245
+ setData(valueSetElements.map((element) => ({ value: getDisplay(element), element })));
1246
+ setLoading(false);
1247
+ });
1248
+ }
1249
+ function handleChange(val) {
1250
+ return __awaiter(this, void 0, void 0, function* () {
1251
+ setText(val);
1252
+ return loadValues(val);
1253
+ });
1254
+ }
1255
+ function handleSelect(item) {
1256
+ setValue(item.element);
1257
+ setText(item.value);
1258
+ setData([]);
1259
+ if (props.onChange) {
1260
+ props.onChange(item.element);
1261
+ }
1262
+ }
1263
+ function handleBlur(val) {
1264
+ if (!value) {
1265
+ const unstructured = {
1266
+ display: val,
1267
+ code: val,
1268
+ };
1269
+ setValue(unstructured);
1270
+ if (props.onChange) {
1271
+ props.onChange(unstructured);
1272
+ }
1273
+ }
1274
+ }
1275
+ return (React__default["default"].createElement(core$1.Autocomplete, { value: text, data: data, placeholder: props.placeholder, onFocus: () => loadValues(text), onBlur: () => handleBlur(text), onChange: handleChange, onItemSubmit: handleSelect, rightSection: loading ? React__default["default"].createElement(core$1.Loader, { size: 16 }) : null }));
1570
1276
  }
1571
-
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);
1577
- }
1578
- } }));
1277
+ function getDisplay(item) {
1278
+ return item.display || item.code || '';
1579
1279
  }
1580
1280
 
1581
1281
  function CodeableConceptInput(props) {
1582
- const medplum = useMedplum();
1583
- let defaultValue = undefined;
1584
- if (props.defaultValue) {
1585
- defaultValue = [props.defaultValue];
1282
+ const [value, setValue] = React.useState(props.defaultValue);
1283
+ function handleChange(newValue) {
1284
+ const newConcept = valueSetElementToCodeableConcept(newValue);
1285
+ setValue(newConcept);
1286
+ if (props.onChange) {
1287
+ props.onChange(newConcept);
1288
+ }
1586
1289
  }
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
- } }));
1290
+ return (React__default["default"].createElement(ValueSetAutocomplete, { property: props.property, name: props.name, placeholder: props.placeholder, defaultValue: value && codeableConceptToValueSetElement(value), onChange: handleChange }));
1291
+ }
1292
+ function codeableConceptToValueSetElement(concept) {
1293
+ var _a, _b, _c, _d, _e, _f;
1294
+ return {
1295
+ system: (_b = (_a = concept.coding) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.system,
1296
+ code: (_d = (_c = concept.coding) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.code,
1297
+ display: (_f = (_e = concept.coding) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.display,
1298
+ };
1598
1299
  }
1599
1300
  function valueSetElementToCodeableConcept(element) {
1600
1301
  return {
@@ -1608,64 +1309,49 @@
1608
1309
  ],
1609
1310
  };
1610
1311
  }
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;
1617
- }
1618
- return core.stringify(concept);
1619
- }
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);
1624
- }
1625
1312
 
1626
- const cachedDisplayValues = {};
1627
1313
  function CodeInput(props) {
1628
- const medplum = useMedplum();
1629
- let defaultValue = undefined;
1630
- if (props.defaultValue) {
1631
- defaultValue = [props.defaultValue];
1314
+ const [value, setValue] = React.useState(props.defaultValue);
1315
+ function handleChange(newValue) {
1316
+ const newCode = valueSetElementToCode(newValue);
1317
+ setValue(newCode);
1318
+ if (props.onChange) {
1319
+ props.onChange(newCode);
1320
+ }
1632
1321
  }
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
- } }));
1322
+ return (React__default["default"].createElement(ValueSetAutocomplete, { property: props.property, name: props.name, placeholder: props.placeholder, defaultValue: codeToValueSetElement(value), onChange: handleChange }));
1323
+ }
1324
+ function codeToValueSetElement(code) {
1325
+ return { code };
1326
+ }
1327
+ function valueSetElementToCode(element) {
1328
+ return element.code;
1646
1329
  }
1647
1330
 
1648
1331
  function CodingInput(props) {
1649
- const medplum = useMedplum();
1650
- let defaultValue = undefined;
1651
- if (props.defaultValue) {
1652
- defaultValue = [props.defaultValue];
1332
+ const [value, setValue] = React.useState(props.defaultValue);
1333
+ function handleChange(newValue) {
1334
+ const newConcept = valueSetElementToCoding(newValue);
1335
+ setValue(newConcept);
1336
+ if (props.onChange) {
1337
+ props.onChange(newConcept);
1338
+ }
1653
1339
  }
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
- } }));
1340
+ return (React__default["default"].createElement(ValueSetAutocomplete, { property: props.property, name: props.name, placeholder: props.placeholder, defaultValue: value && codingToValueSetElement(value), onChange: handleChange }));
1341
+ }
1342
+ function codingToValueSetElement(coding) {
1343
+ return {
1344
+ system: coding.system,
1345
+ code: coding.code,
1346
+ display: coding.display,
1347
+ };
1348
+ }
1349
+ function valueSetElementToCoding(element) {
1350
+ return {
1351
+ system: element.system,
1352
+ code: element.code,
1353
+ display: element.display,
1354
+ };
1669
1355
  }
1670
1356
 
1671
1357
  function ContactPointInput(props) {
@@ -1702,24 +1388,10 @@
1702
1388
  }
1703
1389
  setContactPointWrapper(newValue);
1704
1390
  }
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 })));
1391
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1392
+ 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'] }),
1393
+ 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'] }),
1394
+ 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
1395
  }
1724
1396
 
1725
1397
  function ContactDetailInput(props) {
@@ -1747,8 +1419,8 @@
1747
1419
  }
1748
1420
  setContactDetailWrapper(newValue);
1749
1421
  }
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 }),
1422
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1423
+ 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
1424
  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
1425
  }
1754
1426
 
@@ -1761,11 +1433,12 @@
1761
1433
  * @returns The JSX element to render.
1762
1434
  */
1763
1435
  function DateTimeInput(props) {
1764
- return (React__default["default"].createElement(Input, Object.assign({}, props, { type: "datetime-local", defaultValue: convertIsoToLocal(props.defaultValue), onChange: (newValue) => {
1436
+ 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
1437
  if (props.onChange) {
1438
+ const newValue = e.currentTarget.value;
1766
1439
  props.onChange(convertLocalToIso(newValue));
1767
1440
  }
1768
- } })));
1441
+ } }));
1769
1442
  }
1770
1443
  /**
1771
1444
  * Converts an ISO-8601 date/time string to a local date/time string.
@@ -1805,20 +1478,17 @@
1805
1478
  }
1806
1479
  return date.toISOString();
1807
1480
  }
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
- } }));
1481
+ /**
1482
+ * Returns the input type for the requested type.
1483
+ * JSDOM does not support many of the valid <input> type attributes.
1484
+ * For example, it won't fire change events for <input type="datetime-local">.
1485
+ */
1486
+ function getInputType() {
1487
+ return 'datetime-local';
1818
1488
  }
1819
1489
 
1820
1490
  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) => {
1491
+ 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
1492
  if (props.onChange) {
1823
1493
  props.onChange(JSON.parse(newValue));
1824
1494
  }
@@ -1851,20 +1521,12 @@
1851
1521
  function setSuffix(suffix) {
1852
1522
  setValueWrapper(Object.assign(Object.assign({}, valueRef.current), { suffix: suffix ? suffix.split(' ') : undefined }));
1853
1523
  }
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 })));
1524
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1525
+ 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'] }),
1526
+ 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) }),
1527
+ 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) }),
1528
+ 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) }),
1529
+ 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
1530
  }
1869
1531
 
1870
1532
  function IdentifierInput(props) {
@@ -1875,9 +1537,9 @@
1875
1537
  props.onChange(newValue);
1876
1538
  }
1877
1539
  }
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 })) })));
1540
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1541
+ 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 })) }),
1542
+ 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
1543
  }
1882
1544
 
1883
1545
  function PeriodInput(props) {
@@ -1888,9 +1550,9 @@
1888
1550
  props.onChange(newValue);
1889
1551
  }
1890
1552
  }
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 })) })));
1553
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1554
+ 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 })) }),
1555
+ 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
1556
  }
1895
1557
 
1896
1558
  function QuantityInput(props) {
@@ -1902,15 +1564,10 @@
1902
1564
  props.onChange(newValue);
1903
1565
  }
1904
1566
  }
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 })) })));
1567
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1568
+ 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 })) }),
1569
+ 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) })) }),
1570
+ 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
1571
  }
1915
1572
  function tryParseNumber(str) {
1916
1573
  if (!str) {
@@ -1933,7 +1590,7 @@
1933
1590
  props.onChange(newValue);
1934
1591
  }
1935
1592
  }
1936
- return (React__default["default"].createElement(InputRow, null,
1593
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1937
1594
  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
1595
  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
1596
  }
@@ -1952,50 +1609,65 @@
1952
1609
  props.onChange(newValue);
1953
1610
  }
1954
1611
  }
1955
- return (React__default["default"].createElement(InputRow, null,
1612
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1956
1613
  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
1614
  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
1615
  }
1959
1616
 
1960
- function ResourceName(props) {
1617
+ function ResourceAvatar(props) {
1618
+ var _a, _b, _c;
1961
1619
  const resource = useResource(props.value);
1962
- if (!resource) {
1963
- return null;
1620
+ const text = resource ? core.getDisplayString(resource) : (_a = props.alt) !== null && _a !== void 0 ? _a : '';
1621
+ const imageUrl = (_b = (resource && core.getImageSrc(resource))) !== null && _b !== void 0 ? _b : props.src;
1622
+ const radius = (_c = props.radius) !== null && _c !== void 0 ? _c : 'xl';
1623
+ const avatarProps = Object.assign({}, props);
1624
+ delete avatarProps.value;
1625
+ delete avatarProps.link;
1626
+ if (props.link) {
1627
+ return (React__default["default"].createElement(MedplumLink, { to: resource },
1628
+ React__default["default"].createElement(core$1.Avatar, Object.assign({ src: imageUrl, alt: text, radius: radius }, avatarProps))));
1964
1629
  }
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);
1630
+ return React__default["default"].createElement(core$1.Avatar, Object.assign({ src: imageUrl, alt: text, radius: radius }, avatarProps));
1967
1631
  }
1968
1632
 
1969
1633
  function ResourceInput(props) {
1970
1634
  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);
1635
+ const defaultValue = useResource(props.defaultValue);
1636
+ const [value, setValue] = React.useState(defaultValue ? core.getDisplayString(defaultValue) : '');
1637
+ const [loading, setLoading] = React.useState(false);
1638
+ const [data, setData] = React.useState([]);
1639
+ function loadValues(input) {
1640
+ return __awaiter(this, void 0, void 0, function* () {
1641
+ setLoading(true);
1642
+ const resources = yield medplum.searchResources(props.resourceType, 'name=' + encodeURIComponent(input) + '&_count=10');
1643
+ setData(resources.map((resource) => ({ value: core.getDisplayString(resource), resource })));
1644
+ setLoading(false);
1645
+ });
1646
+ }
1647
+ function handleChange(val) {
1648
+ return __awaiter(this, void 0, void 0, function* () {
1649
+ setValue(val);
1650
+ return loadValues(val);
1651
+ });
1652
+ }
1653
+ function handleSelect(item) {
1654
+ setValue(item.value);
1655
+ setData([]);
1980
1656
  if (props.onChange) {
1981
- props.onChange(newValue);
1657
+ props.onChange(item.resource);
1982
1658
  }
1983
1659
  }
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
- } }));
1660
+ 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
1661
  }
1662
+ const ItemComponent = React.forwardRef((_a, ref) => {
1663
+ var { value, resource } = _a, others = __rest(_a, ["value", "resource"]);
1664
+ return (React__default["default"].createElement("div", Object.assign({ ref: ref }, others),
1665
+ React__default["default"].createElement(core$1.Group, { noWrap: true },
1666
+ React__default["default"].createElement(ResourceAvatar, { value: resource }),
1667
+ React__default["default"].createElement("div", null,
1668
+ React__default["default"].createElement(core$1.Text, null, value),
1669
+ React__default["default"].createElement(core$1.Text, { size: "xs", color: "dimmed" }, resource.birthDate)))));
1670
+ });
1999
1671
 
2000
1672
  function ReferenceInput(props) {
2001
1673
  const targetTypes = props.targetTypes;
@@ -2012,9 +1684,9 @@
2012
1684
  props.onChange(newValue);
2013
1685
  }
2014
1686
  }
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) => {
1687
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1688
+ 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) })),
1689
+ React__default["default"].createElement(ResourceInput, { resourceType: resourceType, name: props.name + '-id', placeholder: props.placeholder, defaultValue: value, onChange: (item) => {
2018
1690
  setValueHelper(item ? core.createReference(item) : undefined);
2019
1691
  } })));
2020
1692
  }
@@ -2042,8 +1714,8 @@
2042
1714
  }
2043
1715
  return (React__default["default"].createElement("table", { style: { width: '100%', borderCollapse: 'collapse' } },
2044
1716
  React__default["default"].createElement("colgroup", null,
2045
- React__default["default"].createElement("col", { width: "90%" }),
2046
- React__default["default"].createElement("col", { width: "10%" })),
1717
+ React__default["default"].createElement("col", { width: "97%" }),
1718
+ React__default["default"].createElement("col", { width: "3%" })),
2047
1719
  React__default["default"].createElement("tbody", null,
2048
1720
  values.map((v, index) => (React__default["default"].createElement("tr", { key: `${index}-${values.length}` },
2049
1721
  React__default["default"].createElement("td", null,
@@ -2053,58 +1725,23 @@
2053
1725
  setValuesWrapper(copy);
2054
1726
  } })),
2055
1727
  React__default["default"].createElement("td", { style: { textAlign: 'right' } },
2056
- React__default["default"].createElement(Button, { onClick: (e) => {
1728
+ React__default["default"].createElement(core$1.ActionIcon, { title: "Remove", size: "sm", onClick: (e) => {
2057
1729
  killEvent(e);
2058
1730
  const copy = [...valuesRef.current];
2059
1731
  copy.splice(index, 1);
2060
1732
  setValuesWrapper(copy);
2061
- } }, "Remove"))))),
1733
+ } },
1734
+ React__default["default"].createElement(icons.IconCircleMinus, null)))))),
2062
1735
  React__default["default"].createElement("tr", null,
2063
1736
  React__default["default"].createElement("td", null),
2064
1737
  React__default["default"].createElement("td", { style: { textAlign: 'right' } },
2065
- React__default["default"].createElement(Button, { onClick: (e) => {
1738
+ React__default["default"].createElement(core$1.ActionIcon, { title: "Add", size: "sm", color: "green", onClick: (e) => {
2066
1739
  killEvent(e);
2067
1740
  const copy = [...valuesRef.current];
2068
1741
  copy.push(undefined);
2069
1742
  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")))));
1743
+ } },
1744
+ React__default["default"].createElement(icons.IconCirclePlus, null)))))));
2108
1745
  }
2109
1746
 
2110
1747
  const daysOfWeek = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
@@ -2114,9 +1751,9 @@
2114
1751
  const valueRef = React.useRef();
2115
1752
  valueRef.current = value;
2116
1753
  return (React__default["default"].createElement(React__default["default"].Fragment, null,
2117
- React__default["default"].createElement(InputRow, null,
1754
+ React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
2118
1755
  React__default["default"].createElement("span", null, core.formatTiming(valueRef.current) || 'No repeat'),
2119
- React__default["default"].createElement(Button, { onClick: () => setOpen(true) }, "Edit")),
1756
+ React__default["default"].createElement(core$1.Button, { onClick: () => setOpen(true) }, "Edit")),
2120
1757
  React__default["default"].createElement(TimingEditorDialog, { visible: open, defaultValue: valueRef.current, onOk: (newValue) => {
2121
1758
  if (props.onChange) {
2122
1759
  props.onChange(newValue);
@@ -2166,22 +1803,24 @@
2166
1803
  setRepeat(Object.assign(Object.assign({}, (_c = valueRef.current) === null || _c === void 0 ? void 0 : _c.repeat), { dayOfWeek: existing.filter((d) => d !== day) }));
2167
1804
  }
2168
1805
  }
2169
- return (React__default["default"].createElement(Dialog, { title: "Timing", visible: props.visible, onOk: () => props.onOk(value), onCancel: () => props.onCancel() },
1806
+ return (React__default["default"].createElement(core$1.Modal, { title: "Timing", closeButtonLabel: "Close", opened: props.visible, onClose: () => props.onCancel() },
2170
1807
  React__default["default"].createElement("div", { style: { padding: '5px 20px', textAlign: 'left' } },
2171
1808
  React__default["default"].createElement(FormSection, { title: "Starts on", htmlFor: 'timing-dialog-start' },
2172
1809
  React__default["default"].createElement(DateTimeInput, { name: 'timing-dialog-start', onChange: (newValue) => setStart(newValue) })),
2173
1810
  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")))),
1811
+ React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1812
+ 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)) }),
1813
+ 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: [
1814
+ { label: 'day', value: 'd' },
1815
+ { label: 'week', value: 'wk' },
1816
+ { label: 'month', value: 'mo' },
1817
+ { label: 'year', value: 'a' },
1818
+ ] }))),
2181
1819
  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 },
1820
+ 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
1821
  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) })))))))));
1822
+ React__default["default"].createElement(core$1.Checkbox, { id: 'timing-dialog-repeat-' + day, name: 'timing-dialog-repeat-' + day, onChange: (e) => setDayOfWeek(day, e.currentTarget.checked) }))))))),
1823
+ React__default["default"].createElement(core$1.Button, { onClick: () => props.onOk(value) }, "OK")));
2185
1824
  }
2186
1825
 
2187
1826
  function ResourcePropertyInput(props) {
@@ -2214,10 +1853,13 @@
2214
1853
  initialPropertyType = propertyTypes[0];
2215
1854
  }
2216
1855
  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)))),
1856
+ return (React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
1857
+ React__default["default"].createElement(core$1.NativeSelect, { style: { width: '200px' }, defaultValue: selectedType === null || selectedType === void 0 ? void 0 : selectedType.code, onChange: (e) => {
1858
+ setSelectedType(propertyTypes.find((type) => type.code === e.currentTarget.value));
1859
+ }, data: propertyTypes.map((type) => ({
1860
+ value: type.code,
1861
+ label: type.code,
1862
+ })) }),
2221
1863
  React__default["default"].createElement(ElementDefinitionTypeInput, Object.assign({}, props, { elementDefinitionType: selectedType, onChange: (newValue) => {
2222
1864
  if (props.onChange) {
2223
1865
  props.onChange(newValue, props.name.replace('[x]', core.capitalize(selectedType.code)));
@@ -2239,31 +1881,43 @@
2239
1881
  case core.PropertyType.time:
2240
1882
  case core.PropertyType.uri:
2241
1883
  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 }));
1884
+ return (React__default["default"].createElement(core$1.TextInput, { id: name, name: name, "data-testid": name, defaultValue: value, onChange: (e) => {
1885
+ if (props.onChange) {
1886
+ props.onChange(e.currentTarget.value);
1887
+ }
1888
+ }, error: getErrorsForInput(props.outcome, name) }));
2243
1889
  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 }));
1890
+ return (React__default["default"].createElement(core$1.TextInput, { type: "date", id: name, name: name, "data-testid": name, defaultValue: value, onChange: (e) => {
1891
+ if (props.onChange) {
1892
+ props.onChange(e.currentTarget.value);
1893
+ }
1894
+ }, error: getErrorsForInput(props.outcome, name) }));
2245
1895
  case core.PropertyType.dateTime:
2246
1896
  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 }));
1897
+ return React__default["default"].createElement(DateTimeInput, { name: name, defaultValue: value, onChange: props.onChange, outcome: props.outcome });
2248
1898
  case core.PropertyType.decimal:
2249
1899
  case core.PropertyType.integer:
2250
1900
  case core.PropertyType.positiveInt:
2251
1901
  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) => {
1902
+ 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
1903
  if (props.onChange) {
2254
- props.onChange(parseFloat(newValue));
1904
+ props.onChange(e.currentTarget.valueAsNumber);
2255
1905
  }
2256
- }, outcome: props.outcome }));
1906
+ } }));
2257
1907
  case core.PropertyType.code:
2258
1908
  return React__default["default"].createElement(CodeInput, { property: property, name: name, defaultValue: value, onChange: props.onChange });
2259
1909
  case core.PropertyType.boolean:
2260
- return (React__default["default"].createElement(Checkbox, { name: name, testid: name, defaultValue: !!value, onChange: (newValue) => {
1910
+ return (React__default["default"].createElement(core$1.Checkbox, { id: name, name: name, "data-testid": name, defaultChecked: !!value, onChange: (e) => {
2261
1911
  if (props.onChange) {
2262
- props.onChange(newValue);
1912
+ props.onChange(e.currentTarget.checked);
2263
1913
  }
2264
1914
  } }));
2265
1915
  case core.PropertyType.markdown:
2266
- return React__default["default"].createElement(TextArea, { name: name, testid: name, defaultValue: value, onChange: props.onChange });
1916
+ return (React__default["default"].createElement(core$1.Textarea, { id: name, name: name, "data-testid": name, defaultValue: value, onChange: (e) => {
1917
+ if (props.onChange) {
1918
+ props.onChange(e.currentTarget.value);
1919
+ }
1920
+ } }));
2267
1921
  // 2.24.0.2 Complex Types
2268
1922
  // https://www.hl7.org/fhir/datatypes.html#complex
2269
1923
  case core.PropertyType.Address:
@@ -2347,10 +2001,18 @@
2347
2001
  })));
2348
2002
  }
2349
2003
 
2004
+ function ResourceName(props) {
2005
+ const resource = useResource(props.value);
2006
+ if (!resource) {
2007
+ return null;
2008
+ }
2009
+ const text = core.getDisplayString(resource);
2010
+ return props.link ? React__default["default"].createElement(MedplumLink, { to: resource }, text) : React__default["default"].createElement("span", null, text);
2011
+ }
2012
+
2350
2013
  function ResourceBadge(props) {
2351
- var _a;
2352
2014
  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 }),
2015
+ React__default["default"].createElement(ResourceAvatar, { size: 24, radius: 12, value: props.value, link: props.link }),
2354
2016
  React__default["default"].createElement(ResourceName, { value: props.value, link: props.link })));
2355
2017
  }
2356
2018
 
@@ -2410,7 +2072,11 @@
2410
2072
  if (!observation) {
2411
2073
  return null;
2412
2074
  }
2413
- return (React__default["default"].createElement("tr", null,
2075
+ let className = undefined;
2076
+ if (isCritical(observation)) {
2077
+ className = 'medplum-critical';
2078
+ }
2079
+ return (React__default["default"].createElement("tr", { className: className },
2414
2080
  React__default["default"].createElement("td", null,
2415
2081
  React__default["default"].createElement(MedplumLink, { to: observation },
2416
2082
  React__default["default"].createElement(CodeableConceptDisplay, { value: observation.code }))),
@@ -2443,16 +2109,16 @@
2443
2109
  }
2444
2110
  return React__default["default"].createElement(RangeDisplay, { value: range });
2445
2111
  }
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));
2112
+ /**
2113
+ * Returns true if the observation is critical.
2114
+ * See: https://www.hl7.org/fhir/valueset-observation-interpretation.html
2115
+ * @param observation The FHIR observation.
2116
+ * @returns True if the FHIR observation is a critical value.
2117
+ */
2118
+ function isCritical(observation) {
2119
+ var _a, _b, _c, _d;
2120
+ 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;
2121
+ return code === 'AA' || code === 'LL' || code === 'HH';
2456
2122
  }
2457
2123
 
2458
2124
  function ResourceDiffTable(props) {
@@ -2552,112 +2218,33 @@
2552
2218
  }
2553
2219
  }
2554
2220
 
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
2221
  function Timeline(props) {
2628
2222
  return React__default["default"].createElement("main", { className: "medplum-document medplum-timeline" }, props.children);
2629
2223
  }
2630
2224
  function TimelineItem(props) {
2631
2225
  var _a, _b, _c;
2632
- const [popupAnchor, setPopupAnchor] = React.useState();
2633
2226
  const author = (_a = props.profile) !== null && _a !== void 0 ? _a : (_b = props.resource.meta) === null || _b === void 0 ? void 0 : _b.author;
2634
2227
  return (React__default["default"].createElement("article", { className: props.className || 'medplum-timeline-item', "data-testid": "timeline-item" },
2635
2228
  React__default["default"].createElement("div", { className: "medplum-timeline-item-header" },
2636
2229
  React__default["default"].createElement("div", { className: "medplum-timeline-item-avatar" },
2637
- React__default["default"].createElement(Avatar, { value: author, link: true, size: "medium" })),
2230
+ React__default["default"].createElement(ResourceAvatar, { value: author, link: true, size: "md" })),
2638
2231
  React__default["default"].createElement("div", { className: "medplum-timeline-item-title" },
2639
2232
  React__default["default"].createElement(ResourceName, { value: author, link: true }),
2640
2233
  React__default["default"].createElement("div", { className: "medplum-timeline-item-subtitle" },
2641
2234
  React__default["default"].createElement(MedplumLink, { to: props.resource }, core.formatDateTime((_c = props.resource.meta) === null || _c === void 0 ? void 0 : _c.lastUpdated)),
2642
2235
  React__default["default"].createElement("span", null, "\u00B7"),
2643
2236
  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" }))))))),
2237
+ props.popupMenuItems && (React__default["default"].createElement(core$1.Menu, { position: "bottom-end", shadow: "md", width: 200 },
2238
+ React__default["default"].createElement(core$1.Menu.Target, null,
2239
+ React__default["default"].createElement(core$1.ActionIcon, { radius: "xl", "aria-label": `Actions for ${core.getReferenceString(props.resource)}` },
2240
+ React__default["default"].createElement(icons.IconDots, null))),
2241
+ props.popupMenuItems))),
2654
2242
  React__default["default"].createElement(ErrorBoundary, null,
2655
2243
  props.padding && React__default["default"].createElement("div", { style: { padding: '2px 16px 16px 16px' } }, props.children),
2656
2244
  !props.padding && React__default["default"].createElement(React__default["default"].Fragment, null, props.children)),
2657
2245
  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))));
2246
+ React__default["default"].createElement(core$1.Button, { variant: "subtle" }, "Like"),
2247
+ React__default["default"].createElement(core$1.Button, { variant: "subtle" }, "Comment")))));
2661
2248
  }
2662
2249
 
2663
2250
  /**
@@ -2822,7 +2409,7 @@
2822
2409
  navigate(`/${version.resourceType}/${version.id}/_history/${(_a = version.meta) === null || _a === void 0 ? void 0 : _a.versionId}`);
2823
2410
  }
2824
2411
  if (!resource || !history) {
2825
- return React__default["default"].createElement(Loading, null);
2412
+ return React__default["default"].createElement(core$1.Loader, null);
2826
2413
  }
2827
2414
  return (React__default["default"].createElement(Timeline, null,
2828
2415
  props.createCommunication && (React__default["default"].createElement("article", { className: "medplum-timeline-item" },
@@ -2835,9 +2422,10 @@
2835
2422
  input.focus();
2836
2423
  }
2837
2424
  } },
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 }))))),
2425
+ React__default["default"].createElement(core$1.Group, { noWrap: true },
2426
+ React__default["default"].createElement(ResourceAvatar, { value: sender }),
2427
+ React__default["default"].createElement(core$1.TextInput, { name: "text", "data-testid": "timeline-input", ref: inputRef, size: "md", radius: "xl", rightSectionWidth: 40, rightSection: React__default["default"].createElement(AttachmentButton, { onUpload: createMedia }, (props) => (React__default["default"].createElement(core$1.ActionIcon, Object.assign({}, props, { size: 24, radius: "xl", color: "blue", variant: "filled" }),
2428
+ React__default["default"].createElement(icons.IconCloudUpload, { size: 16 })))), placeholder: "Add comment" })))))),
2841
2429
  items.map((item) => {
2842
2430
  var _a;
2843
2431
  if (item.resourceType === resource.resourceType && item.id === resource.id) {
@@ -2860,12 +2448,16 @@
2860
2448
  })));
2861
2449
  }
2862
2450
  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"))));
2451
+ return (React__default["default"].createElement(core$1.Menu.Dropdown, null,
2452
+ React__default["default"].createElement(core$1.Menu.Label, null, "Resource"),
2453
+ 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")),
2454
+ 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")),
2455
+ 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")),
2456
+ 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")),
2457
+ props.onDelete && (React__default["default"].createElement(React__default["default"].Fragment, null,
2458
+ React__default["default"].createElement(core$1.Menu.Divider, null),
2459
+ React__default["default"].createElement(core$1.Menu.Label, null, "Danger zone"),
2460
+ 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
2461
  }
2870
2462
  function HistoryTimelineItem(props) {
2871
2463
  const previous = getPrevious(props.history, props.resource);
@@ -2961,6 +2553,7 @@
2961
2553
  ],
2962
2554
  }), createCommunication: (resource, sender, text) => ({
2963
2555
  resourceType: 'Communication',
2556
+ status: 'completed',
2964
2557
  encounter: core.createReference(resource),
2965
2558
  subject: resource.subject,
2966
2559
  sender: core.createReference(sender),
@@ -2968,6 +2561,7 @@
2968
2561
  payload: [{ contentString: text }],
2969
2562
  }), createMedia: (resource, operator, content) => ({
2970
2563
  resourceType: 'Media',
2564
+ status: 'completed',
2971
2565
  encounter: core.createReference(resource),
2972
2566
  subject: resource.subject,
2973
2567
  operator: core.createReference(operator),
@@ -3396,17 +2990,16 @@
3396
2990
  return Object.assign(Object.assign({}, definition), { offset, name: undefined });
3397
2991
  }
3398
2992
  /**
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.
2993
+ * Creates a new search request with the search offset at the specified page.
2994
+ * @param definition The search definition.
2995
+ * @param page The new page number
2996
+ * @return The new search definition.
3403
2997
  */
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));
2998
+ function setPage(definition, page) {
2999
+ var _a;
3000
+ const count = (_a = definition.count) !== null && _a !== void 0 ? _a : core.DEFAULT_SEARCH_COUNT;
3001
+ const newOffset = (page - 1) * count;
3002
+ return setOffset(definition, newOffset);
3410
3003
  }
3411
3004
  /**
3412
3005
  * Sorts the search by the specified key, and optional direction.
@@ -3697,7 +3290,7 @@
3697
3290
  const available = getFieldsList(typeDef)
3698
3291
  .filter((field) => !(selected === null || selected === void 0 ? void 0 : selected.includes(field)))
3699
3292
  .sort();
3700
- return (React__default["default"].createElement(Dialog, { title: "Fields", visible: props.visible, onOk: () => props.onOk(state.search), onCancel: props.onCancel },
3293
+ return (React__default["default"].createElement(core$1.Modal, { title: "Fields", closeButtonLabel: "Close", opened: props.visible, onClose: props.onCancel },
3701
3294
  React__default["default"].createElement("div", null,
3702
3295
  React__default["default"].createElement("table", { style: { margin: 'auto' } },
3703
3296
  React__default["default"].createElement("thead", null,
@@ -3713,13 +3306,14 @@
3713
3306
  React__default["default"].createElement("tfoot", null,
3714
3307
  React__default["default"].createElement("tr", null,
3715
3308
  React__default["default"].createElement("td", { align: "center" },
3716
- React__default["default"].createElement(Button, { size: "small", onClick: onAddField }, "Add")),
3309
+ React__default["default"].createElement(core$1.Button, { compact: true, variant: "outline", onClick: onAddField }, "Add")),
3717
3310
  React__default["default"].createElement("td", { align: "center" },
3718
- React__default["default"].createElement(Button, { size: "small", onClick: onRemoveField }, "Remove")),
3311
+ React__default["default"].createElement(core$1.Button, { compact: true, variant: "outline", onClick: onRemoveField }, "Remove")),
3719
3312
  React__default["default"].createElement("td", { align: "center" },
3720
- React__default["default"].createElement(Button, { size: "small", onClick: onMoveUp }, "Up")),
3313
+ React__default["default"].createElement(core$1.Button, { compact: true, variant: "outline", onClick: onMoveUp }, "Up")),
3721
3314
  React__default["default"].createElement("td", { align: "center" },
3722
- React__default["default"].createElement(Button, { size: "small", onClick: onMoveDown }, "Down"))))))));
3315
+ React__default["default"].createElement(core$1.Button, { compact: true, variant: "outline", onClick: onMoveDown }, "Down")))))),
3316
+ React__default["default"].createElement(core$1.Button, { onClick: () => props.onOk(state.search) }, "OK")));
3723
3317
  }
3724
3318
  /**
3725
3319
  * Returns a list of fields/columns available for a type.
@@ -3781,13 +3375,13 @@
3781
3375
  }
3782
3376
  } }));
3783
3377
  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()) }));
3378
+ 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
3379
  case core.SearchParameterType.DATE:
3786
- return React__default["default"].createElement(Input, { type: "date", testid: name, defaultValue: props.defaultValue, onChange: props.onChange });
3380
+ 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
3381
  case core.SearchParameterType.DATETIME:
3788
- return React__default["default"].createElement(DateTimeInput, { testid: name, defaultValue: props.defaultValue, onChange: props.onChange });
3382
+ return React__default["default"].createElement(DateTimeInput, { name: name, defaultValue: props.defaultValue, onChange: props.onChange });
3789
3383
  case core.SearchParameterType.NUMBER:
3790
- return React__default["default"].createElement(Input, { type: "number", defaultValue: props.defaultValue, onChange: props.onChange });
3384
+ 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
3385
  case core.SearchParameterType.QUANTITY:
3792
3386
  return (React__default["default"].createElement(QuantityInput, { name: name, defaultValue: tryParseQuantity(props.defaultValue), onChange: (newQuantity) => {
3793
3387
  if (newQuantity) {
@@ -3798,7 +3392,7 @@
3798
3392
  }
3799
3393
  } }));
3800
3394
  default:
3801
- return (React__default["default"].createElement(Input, { testid: name, defaultValue: props.defaultValue, autoFocus: props.autoFocus, onChange: props.onChange }));
3395
+ 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
3396
  }
3803
3397
  }
3804
3398
  function tryParseQuantity(value) {
@@ -3832,7 +3426,7 @@
3832
3426
  const resourceType = props.search.resourceType;
3833
3427
  const searchParams = core.globalSchema.types[resourceType].searchParams;
3834
3428
  const filters = search.filters || [];
3835
- return (React__default["default"].createElement(Dialog, { title: "Filters", visible: props.visible, onOk: () => props.onOk(searchRef.current), onCancel: props.onCancel },
3429
+ return (React__default["default"].createElement(core$1.Modal, { title: "Filters", closeButtonLabel: "Close", size: 900, opened: props.visible, onClose: props.onCancel },
3836
3430
  React__default["default"].createElement("div", { className: "medplum-filter-editor" },
3837
3431
  React__default["default"].createElement("table", { className: "medplum-filter-editor-table" },
3838
3432
  React__default["default"].createElement("colgroup", null,
@@ -3860,7 +3454,8 @@
3860
3454
  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
3455
  }
3862
3456
  }),
3863
- React__default["default"].createElement(FilterRowInput, { resourceType: resourceType, searchParams: searchParams, okText: "Add", onOk: onAddFilter }))))));
3457
+ React__default["default"].createElement(FilterRowInput, { resourceType: resourceType, searchParams: searchParams, okText: "Add", onOk: onAddFilter })))),
3458
+ React__default["default"].createElement(core$1.Button, { onClick: () => props.onOk(searchRef.current) }, "OK")));
3864
3459
  }
3865
3460
  function FilterRowDisplay(props) {
3866
3461
  const { filter } = props;
@@ -3870,8 +3465,8 @@
3870
3465
  React__default["default"].createElement("td", null,
3871
3466
  React__default["default"].createElement(SearchFilterValueDisplay, { resourceType: props.resourceType, filter: filter })),
3872
3467
  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"))));
3468
+ React__default["default"].createElement(core$1.Button, { compact: true, variant: "outline", onClick: props.onEdit }, "Edit"),
3469
+ React__default["default"].createElement(core$1.Button, { compact: true, variant: "outline", onClick: props.onDelete }, "Delete"))));
3875
3470
  }
3876
3471
  function FilterRowInput(props) {
3877
3472
  var _a;
@@ -3891,19 +3486,15 @@
3891
3486
  const operators = searchParam && getSearchOperators(searchParam);
3892
3487
  return (React__default["default"].createElement("tr", null,
3893
3488
  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))))))),
3489
+ 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) })) })),
3490
+ 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
3491
  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
3492
  React__default["default"].createElement("td", null,
3902
- value.code && value.operator && value.value && (React__default["default"].createElement(Button, { size: "small", onClick: () => {
3493
+ value.code && value.operator && value.value && (React__default["default"].createElement(core$1.Button, { compact: true, variant: "outline", onClick: () => {
3903
3494
  props.onOk(valueRef.current);
3904
3495
  setValue({});
3905
3496
  } }, props.okText)),
3906
- props.onCancel && (React__default["default"].createElement(Button, { size: "small", onClick: props.onCancel }, "Cancel")))));
3497
+ props.onCancel && (React__default["default"].createElement(core$1.Button, { compact: true, variant: "outline", onClick: props.onCancel }, "Cancel")))));
3907
3498
  }
3908
3499
 
3909
3500
  function SearchFilterValueDialog(props) {
@@ -3915,47 +3506,11 @@
3915
3506
  function onOk() {
3916
3507
  props.onOk(Object.assign(Object.assign({}, props.filter), { value }));
3917
3508
  }
3918
- return (React__default["default"].createElement(Dialog, { title: props.title, visible: props.visible, onOk: onOk, onCancel: props.onCancel },
3509
+ return (React__default["default"].createElement(core$1.Modal, { title: props.title, size: "xl", opened: props.visible, onClose: props.onCancel },
3919
3510
  React__default["default"].createElement("div", { style: { width: 500 } },
3920
3511
  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)));
3512
+ React__default["default"].createElement(SearchFilterValueInput, { resourceType: props.resourceType, searchParam: props.searchParam, defaultValue: value, autoFocus: true, onChange: setValue }))),
3513
+ React__default["default"].createElement(core$1.Button, { onClick: onOk }, "OK")));
3959
3514
  }
3960
3515
 
3961
3516
  function SearchPopupMenu(props) {
@@ -3974,15 +3529,12 @@
3974
3529
  function onChange(definition) {
3975
3530
  props.onChange(definition);
3976
3531
  }
3977
- const anchor = { left: props.x, right: props.x, top: props.y, bottom: props.y };
3978
3532
  // If there is only one search parameter, then show it directly
3979
3533
  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 })));
3534
+ return (React__default["default"].createElement(SearchParameterSubMenu, { search: props.search, searchParam: props.searchParams[0], onSort: onSort, onPrompt: onPrompt, onChange: onChange, onClear: onClear }));
3982
3535
  }
3983
3536
  // 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 }))))));
3537
+ 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
3538
  }
3987
3539
  function SearchParameterSubMenu(props) {
3988
3540
  switch (props.searchParam.type) {
@@ -4006,85 +3558,72 @@
4006
3558
  function DateFilterSubMenu(props) {
4007
3559
  const { searchParam } = props;
4008
3560
  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")));
3561
+ return (React__default["default"].createElement(core$1.Menu.Dropdown, null,
3562
+ 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"),
3563
+ 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"),
3564
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3565
+ 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..."),
3566
+ 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..."),
3567
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3568
+ 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..."),
3569
+ 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..."),
3570
+ 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..."),
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.IconCalendar, { size: 14 }), onClick: () => props.onChange(addTomorrowFilter(props.search, code)) }, "Tomorrow"),
3573
+ 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"),
3574
+ 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"),
3575
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3576
+ 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"),
3577
+ 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"),
3578
+ 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"),
3579
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3580
+ 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"),
3581
+ React__default["default"].createElement(CommonMenuItems, Object.assign({}, props))));
4034
3582
  }
4035
3583
  function NumericFilterSubMenu(props) {
4036
3584
  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")));
3585
+ return (React__default["default"].createElement(core$1.Menu.Dropdown, null,
3586
+ 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"),
3587
+ 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"),
3588
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3589
+ 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..."),
3590
+ 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..."),
3591
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3592
+ 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..."),
3593
+ 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..."),
3594
+ 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..."),
3595
+ 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..."),
3596
+ React__default["default"].createElement(CommonMenuItems, Object.assign({}, props))));
4054
3597
  }
4055
3598
  function ReferenceFilterSubMenu(props) {
4056
3599
  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")));
3600
+ return (React__default["default"].createElement(core$1.Menu.Dropdown, null,
3601
+ 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..."),
3602
+ 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..."),
3603
+ React__default["default"].createElement(CommonMenuItems, Object.assign({}, props))));
4066
3604
  }
4067
3605
  function TextFilterSubMenu(props) {
3606
+ const { searchParam } = props;
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.IconSortAscending, { size: 14 }), onClick: () => props.onSort(searchParam, false) }, "Sort A to Z"),
3609
+ 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"),
3610
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3611
+ 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..."),
3612
+ 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..."),
3613
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3614
+ 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..."),
3615
+ 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..."),
3616
+ React__default["default"].createElement(CommonMenuItems, Object.assign({}, props))));
3617
+ }
3618
+ function CommonMenuItems(props) {
4068
3619
  const { searchParam } = props;
4069
3620
  const code = searchParam.code;
4070
3621
  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);
3622
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3623
+ 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"),
3624
+ 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"),
3625
+ React__default["default"].createElement(core$1.Menu.Divider, null),
3626
+ React__default["default"].createElement(core$1.Menu.Item, { icon: React__default["default"].createElement(icons.IconX, { size: 14 }), onClick: () => props.onClear(searchParam) }, "Clear filters")));
4088
3627
  }
4089
3628
 
4090
3629
  class SearchChangeEvent extends Event {
@@ -4106,23 +3645,37 @@
4106
3645
  this.browserEvent = browserEvent;
4107
3646
  }
4108
3647
  }
3648
+ const useStyles = core$1.createStyles((theme) => ({
3649
+ th: {
3650
+ padding: '0 !important',
3651
+ },
3652
+ control: {
3653
+ width: '100%',
3654
+ padding: `${theme.spacing.xs}px ${theme.spacing.md}px`,
3655
+ '&:hover': {
3656
+ backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[0],
3657
+ },
3658
+ },
3659
+ icon: {
3660
+ width: 21,
3661
+ height: 21,
3662
+ borderRadius: 21,
3663
+ },
3664
+ }));
4109
3665
  /**
4110
3666
  * The SearchControl component represents the embeddable search table control.
4111
3667
  * It includes the table, rows, headers, sorting, etc.
4112
3668
  * It does not include the field editor, filter editor, pagination buttons.
4113
3669
  */
4114
3670
  function SearchControl(props) {
4115
- var _a, _b, _c, _d;
3671
+ var _a, _b;
3672
+ const { classes } = useStyles();
4116
3673
  const medplum = useMedplum();
4117
3674
  const [schemaLoaded, setSchemaLoaded] = React.useState(false);
4118
3675
  const [outcome, setOutcome] = React.useState();
4119
3676
  const { search, onLoad } = props;
4120
3677
  const [state, setState] = React.useState({
4121
3678
  selected: {},
4122
- popupVisible: false,
4123
- popupX: 0,
4124
- popupY: 0,
4125
- popupSearchParams: undefined,
4126
3679
  fieldEditorVisible: false,
4127
3680
  filterEditorVisible: false,
4128
3681
  filterDialogVisible: false,
@@ -4187,14 +3740,6 @@
4187
3740
  }
4188
3741
  return true;
4189
3742
  }
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
3743
  /**
4199
3744
  * Emits a change event to the optional change listener.
4200
3745
  * @param newSearch The new search definition.
@@ -4215,6 +3760,10 @@
4215
3760
  // Ignore clicks on checkboxes
4216
3761
  return;
4217
3762
  }
3763
+ if (e.button === 2) {
3764
+ // Ignore right clicks
3765
+ return;
3766
+ }
4218
3767
  killEvent(e);
4219
3768
  if (e.button !== 1 && props.onClick) {
4220
3769
  props.onClick(new SearchClickEvent(resource, e));
@@ -4232,7 +3781,7 @@
4232
3781
  }, [medplum, props.search.resourceType]);
4233
3782
  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
3783
  if (!typeSchema) {
4235
- return React__default["default"].createElement(Loading, null);
3784
+ return React__default["default"].createElement(core$1.Loader, null);
4236
3785
  }
4237
3786
  const checkboxColumn = props.checkboxesEnabled;
4238
3787
  const fields = getFieldDefinitions(search);
@@ -4240,41 +3789,45 @@
4240
3789
  const lastResult = state.searchResponse;
4241
3790
  const entries = lastResult === null || lastResult === void 0 ? void 0 : lastResult.entry;
4242
3791
  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,
3792
+ const buttonVariant = 'subtle';
3793
+ const buttonColor = 'gray';
3794
+ const iconSize = 16;
3795
+ const isMobile = window.innerWidth < 768;
3796
+ return (React__default["default"].createElement("div", { className: "medplum-search-control", "data-testid": "search-control" },
3797
+ !props.hideToolbar && (React__default["default"].createElement(core$1.Group, { position: "apart", mb: "xl" },
3798
+ React__default["default"].createElement(core$1.Group, { spacing: 2 },
3799
+ 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"),
3800
+ 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"),
3801
+ 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...")),
3802
+ !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...")),
3803
+ !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...")),
3804
+ !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..."))),
3805
+ lastResult && (React__default["default"].createElement(core$1.Group, { spacing: 2 },
4261
3806
  React__default["default"].createElement("span", { className: "medplum-search-summary" },
4262
3807
  getStart$1(search, lastResult.total),
4263
3808
  "-",
4264
3809
  getEnd$1(search, lastResult.total),
4265
3810
  " 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,
3811
+ ' ', (_b = lastResult.total) === null || _b === void 0 ? void 0 :
3812
+ _b.toLocaleString()))))),
3813
+ React__default["default"].createElement(core$1.Table, null,
4271
3814
  React__default["default"].createElement("thead", null,
4272
3815
  React__default["default"].createElement("tr", null,
4273
3816
  checkboxColumn && (React__default["default"].createElement("th", { className: "medplum-search-icon-cell" },
4274
3817
  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))))),
3818
+ fields.map((field) => (React__default["default"].createElement("th", { key: field.name },
3819
+ React__default["default"].createElement(core$1.Menu, { shadow: "md", width: 240, position: "bottom-end" },
3820
+ React__default["default"].createElement(core$1.Menu.Target, null,
3821
+ React__default["default"].createElement(core$1.UnstyledButton, { className: classes.control },
3822
+ React__default["default"].createElement(core$1.Group, { position: "apart", noWrap: true },
3823
+ React__default["default"].createElement(core$1.Text, { weight: 500, size: "sm" }, buildFieldNameString(field.name)),
3824
+ React__default["default"].createElement(core$1.Center, { className: classes.icon },
3825
+ React__default["default"].createElement(icons.IconAdjustmentsHorizontal, { size: 14, stroke: 1.5 }))))),
3826
+ React__default["default"].createElement(SearchPopupMenu, { search: props.search, searchParams: field.searchParams, onPrompt: (searchParam, filter) => {
3827
+ setState(Object.assign(Object.assign({}, stateRef.current), { filterDialogVisible: true, filterDialogSearchParam: searchParam, filterDialogFilter: filter }));
3828
+ }, onChange: (result) => {
3829
+ emitSearchChange(result);
3830
+ } })))))),
4278
3831
  !props.hideFilters && (React__default["default"].createElement("tr", null,
4279
3832
  checkboxColumn && React__default["default"].createElement("th", { className: "filters medplum-search-icon-cell" }),
4280
3833
  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 +3836,19 @@
4283
3836
  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
3837
  fields.map((field) => (React__default["default"].createElement("td", { key: field.name }, renderValue(resource, field))))))))),
4285
3838
  (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")),
3839
+ (lastResult === null || lastResult === void 0 ? void 0 : lastResult.total) !== undefined && lastResult.total > 0 && (React__default["default"].createElement(core$1.Center, { m: "md", p: "md" },
3840
+ React__default["default"].createElement(core$1.Pagination, { page: getPage(search), total: getTotalPages(search, lastResult.total), onChange: (newPage) => emitSearchChange(setPage(search, newPage)), getItemAriaLabel: (page) => {
3841
+ switch (page) {
3842
+ case 'prev':
3843
+ return 'Previous page';
3844
+ case 'next':
3845
+ return 'Next page';
3846
+ default:
3847
+ return undefined;
3848
+ }
3849
+ } }))),
4286
3850
  outcome && (React__default["default"].createElement("div", { "data-testid": "search-error", className: "medplum-empty-search" },
4287
3851
  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
3852
  React__default["default"].createElement(SearchFieldEditor, { search: props.search, visible: stateRef.current.fieldEditorVisible, onOk: (result) => {
4297
3853
  emitSearchChange(result);
4298
3854
  setState(Object.assign(Object.assign({}, stateRef.current), { fieldEditorVisible: false }));
@@ -4324,9 +3880,12 @@
4324
3880
  "\u00A0",
4325
3881
  React__default["default"].createElement(SearchFilterValueDisplay, { resourceType: props.resourceType, filter: filter }))))));
4326
3882
  }
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" })));
3883
+ function getPage(search) {
3884
+ return Math.floor((search.offset || 0) / (search.count || core.DEFAULT_SEARCH_COUNT)) + 1;
3885
+ }
3886
+ function getTotalPages(search, total) {
3887
+ const pageSize = search.count || core.DEFAULT_SEARCH_COUNT;
3888
+ return Math.ceil(total / pageSize);
4330
3889
  }
4331
3890
  function getStart$1(search, total) {
4332
3891
  var _a;
@@ -4423,11 +3982,11 @@
4423
3982
  }, [medplum, props.resourceType]);
4424
3983
  const typeSchema = (_a = schema === null || schema === void 0 ? void 0 : schema.types) === null || _a === void 0 ? void 0 : _a[props.resourceType];
4425
3984
  if (!typeSchema) {
4426
- return React__default["default"].createElement(Loading, null);
3985
+ return React__default["default"].createElement(core$1.Loader, null);
4427
3986
  }
4428
3987
  const checkboxColumn = props.checkboxesEnabled;
4429
3988
  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,
3989
+ React__default["default"].createElement(core$1.Table, null,
4431
3990
  React__default["default"].createElement("thead", null,
4432
3991
  React__default["default"].createElement("tr", null,
4433
3992
  checkboxColumn && (React__default["default"].createElement("th", { className: "medplum-search-icon-cell" },
@@ -4443,7 +4002,7 @@
4443
4002
  ((_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
4003
  outcome && (React__default["default"].createElement("div", { "data-testid": "search-error", className: "medplum-empty-search" },
4445
4004
  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..."))));
4005
+ props.onBulk && (React__default["default"].createElement(core$1.Button, { onClick: () => props.onBulk(Object.keys(selectedRef.current)) }, "Bulk..."))));
4447
4006
  }
4448
4007
  const MemoizedFhirPathTable = React__default["default"].memo(FhirPathTable);
4449
4008
 
@@ -4451,263 +4010,6 @@
4451
4010
  return React__default["default"].createElement("div", { className: "medplum-footer" }, props.children);
4452
4011
  }
4453
4012
 
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
4013
  const searches = [
4712
4014
  '$/_history',
4713
4015
  'Communication?subject=$',
@@ -4729,12 +4031,14 @@
4729
4031
  })),
4730
4032
  }), createCommunication: (resource, sender, text) => ({
4731
4033
  resourceType: 'Communication',
4034
+ status: 'completed',
4732
4035
  subject: core.createReference(resource),
4733
4036
  sender: core.createReference(sender),
4734
4037
  sent: new Date().toISOString(),
4735
4038
  payload: [{ contentString: text }],
4736
4039
  }), createMedia: (resource, operator, content) => ({
4737
4040
  resourceType: 'Media',
4041
+ status: 'completed',
4738
4042
  subject: core.createReference(resource),
4739
4043
  operator: core.createReference(operator),
4740
4044
  issued: new Date().toISOString(),
@@ -4777,10 +4081,9 @@
4777
4081
  }
4778
4082
  return (React__default["default"].createElement("div", { className: "medplum-questionnaire-builder" },
4779
4083
  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) })),
4084
+ React__default["default"].createElement(core$1.TextInput, { label: "Plan Title", defaultValue: value.title, onChange: (e) => changeProperty('title', e.currentTarget.value) }),
4782
4085
  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"))));
4086
+ React__default["default"].createElement(core$1.Button, { type: "submit" }, "Save"))));
4784
4087
  }
4785
4088
  function ActionArrayBuilder(props) {
4786
4089
  const actionsRef = React.useRef();
@@ -4852,17 +4155,9 @@
4852
4155
  props.onChange(Object.assign(Object.assign({}, action), { [property]: value }));
4853
4156
  }
4854
4157
  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"))),
4158
+ React__default["default"].createElement(core$1.TextInput, { name: `actionTitle-${action.id}`, label: "Title", defaultValue: action.title, onChange: (e) => changeProperty('title', e.currentTarget.value) }),
4159
+ React__default["default"].createElement(core$1.TextInput, { name: `actionDescription-${action.id}`, label: "Description", defaultValue: action.description, onChange: (e) => changeProperty('description', e.currentTarget.value) }),
4160
+ 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
4161
  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
4162
  (() => {
4868
4163
  switch (actionType) {
@@ -4878,23 +4173,23 @@
4878
4173
  return null;
4879
4174
  }
4880
4175
  })(),
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 }))));
4176
+ React__default["default"].createElement("p", null, "Timing"),
4177
+ React__default["default"].createElement("p", null, "When the action should take place."),
4178
+ React__default["default"].createElement(ActionTimingInput, { name: 'timing-' + action.id, action: action, onChange: props.onChange })));
4883
4179
  }
4884
4180
  function ActionResourceTypeBuilder(props) {
4885
4181
  const { id, definitionCanonical } = props.action;
4886
4182
  const reference = (definitionCanonical === null || definitionCanonical === void 0 ? void 0 : definitionCanonical.startsWith(props.resourceType + '/'))
4887
4183
  ? { reference: definitionCanonical }
4888
4184
  : 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
- } })));
4185
+ return (React__default["default"].createElement(ResourceInput, { name: id, resourceType: props.resourceType, defaultValue: reference, loadOnFocus: true, onChange: (newValue) => {
4186
+ if (newValue) {
4187
+ props.onChange(Object.assign(Object.assign({}, props.action), { definitionCanonical: core.getReferenceString(newValue) }));
4188
+ }
4189
+ else {
4190
+ props.onChange(Object.assign(Object.assign({}, props.action), { definitionCanonical: undefined }));
4191
+ }
4192
+ } }));
4898
4193
  }
4899
4194
  function ActionTimingInput(props) {
4900
4195
  const value = props.action;
@@ -5009,7 +4304,7 @@
5009
4304
  } },
5010
4305
  questionnaire.title && React__default["default"].createElement("h1", null, questionnaire.title),
5011
4306
  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')));
4307
+ React__default["default"].createElement(core$1.Button, { type: "submit" }, props.submitButtonText || 'OK')));
5013
4308
  }
5014
4309
  function QuestionnaireFormItemArray(props) {
5015
4310
  const [responseItems, setResponseItems] = React.useState(buildInitialResponseItems(props.items));
@@ -5032,10 +4327,10 @@
5032
4327
  if (item.type === exports.QuestionnaireItemType.boolean) {
5033
4328
  const initial = item.initial && item.initial.length > 0 ? item.initial[0] : undefined;
5034
4329
  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, {
4330
+ 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
4331
  linkId: item.linkId,
5037
4332
  text: item.text,
5038
- answer: [{ valueBoolean: newValue }],
4333
+ answer: [{ valueBoolean: e.currentTarget.checked }],
5039
4334
  }) })));
5040
4335
  }
5041
4336
  return (React__default["default"].createElement(FormSection, { key: item.linkId, htmlFor: item.linkId, title: item.text || '' },
@@ -5073,23 +4368,22 @@
5073
4368
  React__default["default"].createElement("h3", null, item.text),
5074
4369
  item.item && (React__default["default"].createElement(QuestionnaireFormItemArray, { items: item.item, answers: props.answers, onChange: onChangeItem }))));
5075
4370
  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 }) }));
4371
+ 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
4372
  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) }) }));
4373
+ 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
4374
  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) }) }));
4375
+ 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
4376
  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 }) }));
4377
+ 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
4378
  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 }) }));
4379
+ return (React__default["default"].createElement(DateTimeInput, { name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueDateTime, onChange: (newValue) => onChangeAnswer({ valueDateTime: newValue }) }));
5085
4380
  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 }) }));
4381
+ 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
4382
  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
4383
  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 }) }));
4384
+ 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 }) }));
4385
+ case exports.QuestionnaireItemType.text:
4386
+ 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
4387
  case exports.QuestionnaireItemType.attachment:
5094
4388
  return (React__default["default"].createElement(AttachmentInput, { name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueAttachment, onChange: (newValue) => onChangeAnswer({ valueAttachment: newValue }) }));
5095
4389
  case exports.QuestionnaireItemType.reference:
@@ -5109,9 +4403,15 @@
5109
4403
  }
5110
4404
  function QuestionnaireChoiceDropDownInput(props) {
5111
4405
  const { name, item, initial } = props;
5112
- const valueElementDefinition = core.globalSchema.types['QuestionnaireItemAnswerOption'].properties['value[x]'];
5113
4406
  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) => {
4407
+ const data = [''];
4408
+ if (item.answerOption) {
4409
+ for (const option of item.answerOption) {
4410
+ const optionValue = core.getTypedPropertyValue({ type: 'QuestionnaireItemAnswerOption', value: option }, 'value');
4411
+ data.push(typedValueToString(optionValue));
4412
+ }
4413
+ }
4414
+ return (React__default["default"].createElement(core$1.NativeSelect, { id: name, name: name, className: "medplum-select", onChange: (e) => {
5115
4415
  const index = e.currentTarget.selectedIndex;
5116
4416
  if (index === 0) {
5117
4417
  props.onChangeAnswer({});
@@ -5121,15 +4421,19 @@
5121
4421
  const optionValue = core.getTypedPropertyValue({ type: 'QuestionnaireItemAnswerOption', value: option }, 'value');
5122
4422
  const propertyName = 'value' + core.capitalize(optionValue.type);
5123
4423
  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
- })));
4424
+ }, defaultValue: typedValueToString(initialValue), data: data }));
4425
+ }
4426
+ function typedValueToString(typedValue) {
4427
+ if (!typedValue) {
4428
+ return undefined;
4429
+ }
4430
+ if (typedValue.type === 'CodeableConcept') {
4431
+ return typedValue.value.coding[0].display;
4432
+ }
4433
+ if (typedValue.type === 'Coding') {
4434
+ return typedValue.value.display;
4435
+ }
4436
+ return typedValue.value.toString();
5133
4437
  }
5134
4438
  function QuestionnaireChoiceRadioInput(props) {
5135
4439
  const { name, item, initial, onChangeAnswer } = props;
@@ -5243,7 +4547,7 @@
5243
4547
  return (React__default["default"].createElement("div", { className: "medplum-questionnaire-builder" },
5244
4548
  React__default["default"].createElement(Form, { testid: "questionnaire-form", onSubmit: () => props.onSubmit(value) },
5245
4549
  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"))));
4550
+ React__default["default"].createElement(core$1.Button, { type: "submit" }, "Save"))));
5247
4551
  }
5248
4552
  function ItemBuilder(props) {
5249
4553
  var _a;
@@ -5284,26 +4588,26 @@
5284
4588
  return (React__default["default"].createElement("div", { "data-testid": item.linkId, className: className, onClick: onClick, onMouseOver: onHover },
5285
4589
  editing ? (React__default["default"].createElement(React__default["default"].Fragment, null,
5286
4590
  isResource && (React__default["default"].createElement("div", null,
5287
- React__default["default"].createElement(Input, { defaultValue: resource.title, onChange: (newValue) => changeProperty('title', newValue) }))),
4591
+ React__default["default"].createElement(core$1.TextInput, { defaultValue: resource.title, onChange: (e) => changeProperty('title', e.currentTarget.value) }))),
5288
4592
  !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) })),
4593
+ React__default["default"].createElement(core$1.NativeSelect, { defaultValue: item.type, onChange: (e) => changeProperty('type', e.currentTarget.value), data: [
4594
+ { value: 'display', label: 'Display' },
4595
+ { value: 'boolean', label: 'Boolean' },
4596
+ { value: 'decimal', label: 'Decimal' },
4597
+ { value: 'integer', label: 'Integer' },
4598
+ { value: 'date', label: 'Date' },
4599
+ { value: 'dateTime', label: 'Date/Time' },
4600
+ { value: 'time', label: 'Time' },
4601
+ { value: 'string', label: 'String' },
4602
+ { value: 'text', label: 'Text' },
4603
+ { value: 'url', label: 'URL' },
4604
+ { value: 'choice', label: 'Choice' },
4605
+ { value: 'open-choice', label: 'Open Choice' },
4606
+ { value: 'attachment', label: 'Attachment' },
4607
+ { value: 'reference', label: 'Reference' },
4608
+ { value: 'quantity', label: 'Quantity' },
4609
+ ] }))),
4610
+ !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
4611
  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
4612
  resource.title && React__default["default"].createElement("h1", null, resource.title),
5309
4613
  item.text && React__default["default"].createElement("p", null, item.text),
@@ -5311,7 +4615,7 @@
5311
4615
  item.item &&
5312
4616
  item.item.map((i) => (React__default["default"].createElement("div", { key: i.id },
5313
4617
  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)))),
4618
+ !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
4619
  React__default["default"].createElement("div", { className: "bottom-actions" },
5316
4620
  isContainer && (React__default["default"].createElement(React__default["default"].Fragment, null,
5317
4621
  React__default["default"].createElement("a", { href: "#", onClick: (e) => {
@@ -5459,8 +4763,8 @@
5459
4763
  "Status: ",
5460
4764
  React__default["default"].createElement(StatusBadge, { status: (task === null || task === void 0 ? void 0 : task.status) || 'unknown' }))),
5461
4765
  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")))));
4766
+ taskInput && !taskOutput && React__default["default"].createElement(core$1.Button, { onClick: () => props.onStart(task, taskInput) }, "Start"),
4767
+ taskInput && taskOutput && (React__default["default"].createElement(core$1.Button, { onClick: () => props.onEdit(task, taskInput, taskOutput) }, "Edit")))));
5464
4768
  })));
5465
4769
  function buildBatchRequest(request) {
5466
4770
  var _a;
@@ -5692,8 +4996,8 @@
5692
4996
  React__default["default"].createElement("table", { className: "medplum-blame" },
5693
4997
  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
4998
  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 }),
4999
+ React__default["default"].createElement(core$1.Group, { spacing: "xs", grow: true, noWrap: true },
5000
+ React__default["default"].createElement(ResourceBadge, { value: row.meta.author, link: true }),
5697
5001
  React__default["default"].createElement(MedplumLink, { to: getVersionUrl$1(resource, row.meta.versionId) }, getTimeString(row.meta.lastUpdated))))),
5698
5002
  React__default["default"].createElement("td", { className: "line-number" }, index + 1),
5699
5003
  React__default["default"].createElement("td", { className: "line" },
@@ -5817,11 +5121,11 @@
5817
5121
  }
5818
5122
  const grid = React.useMemo(() => buildGrid(month, props.slots), [month, props.slots]);
5819
5123
  return (React__default["default"].createElement("div", null,
5820
- React__default["default"].createElement(InputRow, null,
5124
+ React__default["default"].createElement(core$1.Group, { position: "apart", spacing: "xs", grow: true, noWrap: true },
5821
5125
  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) }, ">"))),
5126
+ React__default["default"].createElement(core$1.Group, { position: "right", spacing: "xs" },
5127
+ React__default["default"].createElement(core$1.Button, { variant: "outline", "aria-label": "Previous month", onClick: () => moveMonth(-1) }, "<"),
5128
+ React__default["default"].createElement(core$1.Button, { variant: "outline", "aria-label": "Next month", onClick: () => moveMonth(1) }, ">"))),
5825
5129
  React__default["default"].createElement("table", { className: "medplum-calendar-table" },
5826
5130
  React__default["default"].createElement("thead", null,
5827
5131
  React__default["default"].createElement("tr", null,
@@ -5832,7 +5136,7 @@
5832
5136
  React__default["default"].createElement("th", null, "THU"),
5833
5137
  React__default["default"].createElement("th", null, "FRI"),
5834
5138
  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()))))))))))));
5139
+ 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
5140
  }
5837
5141
  function getStartMonth() {
5838
5142
  const result = new Date();
@@ -5922,8 +5226,8 @@
5922
5226
  const actor = (_a = schedule.actor) === null || _a === void 0 ? void 0 : _a[0];
5923
5227
  return (React__default["default"].createElement("div", { className: "medplum-calendar-container", "data-testid": "scheduler" },
5924
5228
  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,
5229
+ actor && React__default["default"].createElement(ResourceAvatar, { value: actor, size: "xl" }),
5230
+ actor && (React__default["default"].createElement(core$1.Text, { size: "xl", weight: 500 },
5927
5231
  React__default["default"].createElement(ResourceName, { value: actor }))),
5928
5232
  React__default["default"].createElement("p", null, "1 hour"),
5929
5233
  date && React__default["default"].createElement("p", null, date.toLocaleDateString()),
@@ -5934,12 +5238,12 @@
5934
5238
  React__default["default"].createElement(CalendarInput, { slots: slots, onChangeMonth: setMonth, onClick: setDate }))),
5935
5239
  date && !slot && (React__default["default"].createElement("div", null,
5936
5240
  React__default["default"].createElement("h3", null, "Select time"),
5937
- slots.map((s) => {
5241
+ React__default["default"].createElement(core$1.Stack, null, slots.map((s) => {
5938
5242
  const slotStart = new Date(s.start);
5939
5243
  return (slotStart.getTime() > date.getTime() &&
5940
5244
  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
- }))),
5245
+ React__default["default"].createElement(core$1.Button, { variant: "outline", style: { width: 150 }, onClick: () => setSlot(s) }, formatTime(slotStart)))));
5246
+ })))),
5943
5247
  date && slot && !response && (React__default["default"].createElement(QuestionnaireForm, { questionnaire: questionnaire, submitButtonText: 'Next', onSubmit: setResponse })),
5944
5248
  date && slot && response && (React__default["default"].createElement("div", null,
5945
5249
  React__default["default"].createElement("h3", null, "You're all set!"),
@@ -5990,6 +5294,7 @@
5990
5294
  ],
5991
5295
  }), createCommunication: (resource, sender, text) => ({
5992
5296
  resourceType: 'Communication',
5297
+ status: 'completed',
5993
5298
  basedOn: [core.createReference(resource)],
5994
5299
  subject: resource.subject,
5995
5300
  sender: core.createReference(sender),
@@ -5997,6 +5302,7 @@
5997
5302
  payload: [{ contentString: text }],
5998
5303
  }), createMedia: (resource, operator, content) => ({
5999
5304
  resourceType: 'Media',
5305
+ status: 'completed',
6000
5306
  basedOn: [core.createReference(resource)],
6001
5307
  subject: resource.subject,
6002
5308
  operator: core.createReference(operator),
@@ -6051,16 +5357,17 @@
6051
5357
  })));
6052
5358
  }
6053
5359
 
5360
+ function TitleBar(props) {
5361
+ return React__default["default"].createElement("div", { className: "medplum-title-bar" }, props.children);
5362
+ }
5363
+
6054
5364
  exports.AddressDisplay = AddressDisplay;
6055
5365
  exports.AddressInput = AddressInput;
6056
5366
  exports.AttachmentArrayDisplay = AttachmentArrayDisplay;
6057
5367
  exports.AttachmentArrayInput = AttachmentArrayInput;
5368
+ exports.AttachmentButton = AttachmentButton;
6058
5369
  exports.AttachmentInput = AttachmentInput;
6059
- exports.Autocomplete = Autocomplete;
6060
- exports.Avatar = Avatar;
6061
5370
  exports.BackboneElementInput = BackboneElementInput;
6062
- exports.Button = Button;
6063
- exports.Checkbox = Checkbox;
6064
5371
  exports.CheckboxFormSection = CheckboxFormSection;
6065
5372
  exports.CodeInput = CodeInput;
6066
5373
  exports.CodeableConceptDisplay = CodeableConceptDisplay;
@@ -6074,7 +5381,6 @@
6074
5381
  exports.DescriptionList = DescriptionList;
6075
5382
  exports.DescriptionListEntry = DescriptionListEntry;
6076
5383
  exports.DiagnosticReportDisplay = DiagnosticReportDisplay;
6077
- exports.Dialog = Dialog;
6078
5384
  exports.Document = Document;
6079
5385
  exports.ElementDefinitionInputSelector = ElementDefinitionInputSelector;
6080
5386
  exports.ElementDefinitionTypeInput = ElementDefinitionTypeInput;
@@ -6084,23 +5390,17 @@
6084
5390
  exports.FooterLinks = FooterLinks;
6085
5391
  exports.Form = Form;
6086
5392
  exports.FormSection = FormSection;
6087
- exports.Header = Header;
6088
5393
  exports.HumanNameDisplay = HumanNameDisplay;
6089
5394
  exports.HumanNameInput = HumanNameInput;
6090
5395
  exports.IdentifierInput = IdentifierInput;
6091
- exports.Input = Input;
6092
- exports.InputRow = InputRow;
6093
- exports.Loading = Loading;
6094
5396
  exports.Logo = Logo;
6095
5397
  exports.MedplumLink = MedplumLink;
6096
5398
  exports.MedplumProvider = MedplumProvider;
6097
5399
  exports.MemoizedFhirPathTable = MemoizedFhirPathTable;
6098
5400
  exports.MemoizedSearchControl = MemoizedSearchControl;
6099
- exports.MenuItem = MenuItem;
6100
5401
  exports.ObservationTable = ObservationTable;
6101
5402
  exports.PatientTimeline = PatientTimeline;
6102
5403
  exports.PlanDefinitionBuilder = PlanDefinitionBuilder;
6103
- exports.Popup = Popup;
6104
5404
  exports.QuestionnaireBuilder = QuestionnaireBuilder;
6105
5405
  exports.QuestionnaireForm = QuestionnaireForm;
6106
5406
  exports.QuestionnaireFormItem = QuestionnaireFormItem;
@@ -6111,6 +5411,7 @@
6111
5411
  exports.RequestGroupDisplay = RequestGroupDisplay;
6112
5412
  exports.ResourceArrayDisplay = ResourceArrayDisplay;
6113
5413
  exports.ResourceArrayInput = ResourceArrayInput;
5414
+ exports.ResourceAvatar = ResourceAvatar;
6114
5415
  exports.ResourceBadge = ResourceBadge;
6115
5416
  exports.ResourceBlame = ResourceBlame;
6116
5417
  exports.ResourceDiff = ResourceDiff;
@@ -6130,7 +5431,6 @@
6130
5431
  exports.SearchFieldEditor = SearchFieldEditor;
6131
5432
  exports.SearchFilterEditor = SearchFilterEditor;
6132
5433
  exports.SearchLoadEvent = SearchLoadEvent;
6133
- exports.Select = Select;
6134
5434
  exports.ServiceRequestTimeline = ServiceRequestTimeline;
6135
5435
  exports.SignInForm = SignInForm;
6136
5436
  exports.StatusBadge = StatusBadge;
@@ -6138,11 +5438,9 @@
6138
5438
  exports.TabList = TabList;
6139
5439
  exports.TabPanel = TabPanel;
6140
5440
  exports.TabSwitch = TabSwitch;
6141
- exports.TextArea = TextArea;
6142
5441
  exports.Timeline = Timeline;
6143
5442
  exports.TimelineItem = TimelineItem;
6144
5443
  exports.TitleBar = TitleBar;
6145
- exports.UploadButton = UploadButton;
6146
5444
  exports.addDateEqualsFilter = addDateEqualsFilter;
6147
5445
  exports.addDateFilter = addDateFilter;
6148
5446
  exports.addDateFilterBetween = addDateFilterBetween;
@@ -6164,6 +5462,8 @@
6164
5462
  exports.createScriptTag = createScriptTag;
6165
5463
  exports.deleteFilter = deleteFilter;
6166
5464
  exports.formatRangeString = formatRangeString;
5465
+ exports.getErrorsForInput = getErrorsForInput;
5466
+ exports.getIssuesForExpression = getIssuesForExpression;
6167
5467
  exports.getOpString = getOpString;
6168
5468
  exports.getRecaptcha = getRecaptcha;
6169
5469
  exports.getSearchOperators = getSearchOperators;
@@ -6175,11 +5475,11 @@
6175
5475
  exports.isChoiceQuestion = isChoiceQuestion;
6176
5476
  exports.isQuestionEnabled = isQuestionEnabled;
6177
5477
  exports.isSortDescending = isSortDescending;
6178
- exports.movePage = movePage;
6179
5478
  exports.parseForm = parseForm;
6180
5479
  exports.renderValue = renderValue;
6181
5480
  exports.setFilters = setFilters;
6182
5481
  exports.setOffset = setOffset;
5482
+ exports.setPage = setPage;
6183
5483
  exports.setPropertyValue = setPropertyValue;
6184
5484
  exports.setSort = setSort;
6185
5485
  exports.sortByDateAndPriority = sortByDateAndPriority;