@aehrc/smart-forms-renderer 1.2.13 → 1.3.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 (73) hide show
  1. package/lib/components/FormComponents/ChoiceItems/ChoiceAutocompleteField.js +1 -1
  2. package/lib/components/FormComponents/ChoiceItems/ChoiceAutocompleteField.js.map +1 -1
  3. package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionFields.js +1 -1
  4. package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionFields.js.map +1 -1
  5. package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerValueSetFields.js +1 -1
  6. package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerValueSetFields.js.map +1 -1
  7. package/lib/components/FormComponents/GridGroup/GridGroup.js +1 -1
  8. package/lib/components/FormComponents/GridGroup/GridRow.js +1 -1
  9. package/lib/components/FormComponents/GridGroup/GridRow.js.map +1 -1
  10. package/lib/components/FormComponents/GroupItem/GroupItem.styles.js +1 -1
  11. package/lib/components/FormComponents/GroupItem/GroupItem.styles.js.map +1 -1
  12. package/lib/components/FormComponents/GroupItem/GroupItemView.js +2 -2
  13. package/lib/components/FormComponents/GroupItem/GroupItemView.js.map +1 -1
  14. package/lib/components/FormComponents/GroupItem/TabButtonsWrapper.js +1 -1
  15. package/lib/components/FormComponents/GroupItem/TabButtonsWrapper.js.map +1 -1
  16. package/lib/components/FormComponents/ItemParts/CheckboxSingle.js +2 -1
  17. package/lib/components/FormComponents/ItemParts/CheckboxSingle.js.map +1 -1
  18. package/lib/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerOptionField.js +1 -1
  19. package/lib/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerOptionField.js.map +1 -1
  20. package/lib/components/FormComponents/RepeatGroup/AddItemButton.js +1 -1
  21. package/lib/components/FormComponents/RepeatGroup/AddItemButton.js.map +1 -1
  22. package/lib/components/FormComponents/RepeatGroup/RepeatGroupView.js +1 -1
  23. package/lib/components/FormComponents/RepeatItem/AddItemButton.js +1 -1
  24. package/lib/components/FormComponents/RepeatItem/AddItemButton.js.map +1 -1
  25. package/lib/components/FormComponents/RepeatItem/RepeatItem.styles.js +2 -4
  26. package/lib/components/FormComponents/RepeatItem/RepeatItem.styles.js.map +1 -1
  27. package/lib/components/FormComponents/Tables/GroupTableView.js +1 -1
  28. package/lib/components/Renderer/FormBodySingleCollapsible.js +1 -1
  29. package/lib/components/Renderer/FormBodySingleCollapsible.js.map +1 -1
  30. package/lib/components/Renderer/FormBodyTabbed.js +23 -2
  31. package/lib/components/Renderer/FormBodyTabbed.js.map +1 -1
  32. package/lib/components/Tabs/FormBodyTabList.js +1 -1
  33. package/lib/components/Tabs/FormBodyTabList.js.map +1 -1
  34. package/lib/hooks/useValueSetCodings.js +2 -1
  35. package/lib/hooks/useValueSetCodings.js.map +1 -1
  36. package/lib/stores/rendererConfigStore.d.ts +7 -0
  37. package/lib/stores/rendererConfigStore.js +2 -0
  38. package/lib/stores/rendererConfigStore.js.map +1 -1
  39. package/lib/stores/smartConfigStore.d.ts +7 -1
  40. package/lib/stores/smartConfigStore.js +3 -1
  41. package/lib/stores/smartConfigStore.js.map +1 -1
  42. package/lib/utils/calculatedExpression.js +11 -3
  43. package/lib/utils/calculatedExpression.js.map +1 -1
  44. package/lib/utils/populateContexts.js +2 -14
  45. package/lib/utils/populateContexts.js.map +1 -1
  46. package/lib/utils/valueSet.d.ts +1 -1
  47. package/lib/utils/valueSet.js +2 -2
  48. package/lib/utils/valueSet.js.map +1 -1
  49. package/package.json +2 -2
  50. package/src/components/FormComponents/ChoiceItems/ChoiceAutocompleteField.tsx +1 -1
  51. package/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionFields.tsx +1 -1
  52. package/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerValueSetFields.tsx +2 -1
  53. package/src/components/FormComponents/GridGroup/GridGroup.tsx +1 -1
  54. package/src/components/FormComponents/GridGroup/GridRow.tsx +6 -1
  55. package/src/components/FormComponents/GroupItem/GroupItem.styles.ts +1 -1
  56. package/src/components/FormComponents/GroupItem/GroupItemView.tsx +4 -0
  57. package/src/components/FormComponents/GroupItem/TabButtonsWrapper.tsx +1 -1
  58. package/src/components/FormComponents/ItemParts/CheckboxSingle.tsx +3 -0
  59. package/src/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerOptionField.tsx +1 -1
  60. package/src/components/FormComponents/RepeatGroup/AddItemButton.tsx +1 -1
  61. package/src/components/FormComponents/RepeatGroup/RepeatGroupView.tsx +1 -1
  62. package/src/components/FormComponents/RepeatItem/AddItemButton.tsx +1 -1
  63. package/src/components/FormComponents/RepeatItem/RepeatItem.styles.tsx +2 -4
  64. package/src/components/FormComponents/Tables/GroupTableView.tsx +1 -1
  65. package/src/components/Renderer/FormBodySingleCollapsible.tsx +3 -0
  66. package/src/components/Renderer/FormBodyTabbed.tsx +23 -2
  67. package/src/components/Tabs/FormBodyTabList.tsx +5 -1
  68. package/src/hooks/useValueSetCodings.ts +8 -1
  69. package/src/stores/rendererConfigStore.ts +8 -0
  70. package/src/stores/smartConfigStore.ts +11 -2
  71. package/src/utils/calculatedExpression.ts +11 -8
  72. package/src/utils/populateContexts.ts +2 -16
  73. package/src/utils/valueSet.ts +3 -2
@@ -45,6 +45,10 @@ import type { Breakpoints } from '@mui/material';
45
45
  * @property tabListWidthOrResponsive - Configures the width of the tab list, either as a fixed number or responsive breakpoints.
46
46
  * - Default: `{ tabListBreakpoints: { xs: 12, sm: 3, md: 3, lg: 2.75 }, tabContentBreakpoints: { xs: 12, sm: 9, md: 9, lg: 9.25 } }`
47
47
  *
48
+ * @property tabListStickyTop - The pixel offset from the top of the viewport at which the tab list becomes sticky.
49
+ * Set this to the height of any sticky header in the consuming app so the tab list sticks immediately below it.
50
+ * - Default: `0`
51
+ *
48
52
  * @property textFieldWidth - Defines the default width for text input fields (in pixels).
49
53
  * - Default: `320`
50
54
  *
@@ -96,6 +100,7 @@ export interface RendererConfig {
96
100
  tabListBreakpoints: Partial<Breakpoints['values']>;
97
101
  tabContentBreakpoints: Partial<Breakpoints['values']>;
98
102
  };
103
+ tabListStickyTop?: number;
99
104
  textFieldWidth?: number;
100
105
  inputsFlexGrow?: boolean;
101
106
  reverseBooleanYesNo?: boolean;
@@ -128,6 +133,7 @@ export interface RendererConfigStoreType {
128
133
  tabListBreakpoints: Partial<Breakpoints['values']>;
129
134
  tabContentBreakpoints: Partial<Breakpoints['values']>;
130
135
  };
136
+ tabListStickyTop: number;
131
137
  showTabbedFormAt: UseResponsiveProps;
132
138
  textFieldWidth: number;
133
139
  inputsFlexGrow: boolean; // radio, checkbox and boolean inputs should have flexGrow: 1
@@ -158,6 +164,7 @@ export const rendererConfigStore = createStore<RendererConfigStoreType>()((set)
158
164
  tabListBreakpoints: { xs: 12, sm: 3, md: 3, lg: 2.75 },
159
165
  tabContentBreakpoints: { xs: 12, sm: 9, md: 9, lg: 9.25 }
160
166
  },
167
+ tabListStickyTop: 0,
161
168
  showTabbedFormAt: { query: 'up', start: 'md' },
162
169
  textFieldWidth: 320,
163
170
  inputsFlexGrow: false,
@@ -176,6 +183,7 @@ export const rendererConfigStore = createStore<RendererConfigStoreType>()((set)
176
183
  params.requiredIndicatorPosition ?? state.requiredIndicatorPosition,
177
184
  itemResponsive: params.itemResponsive ?? state.itemResponsive,
178
185
  tabListWidthOrResponsive: params.tabListWidthOrResponsive ?? state.tabListWidthOrResponsive,
186
+ tabListStickyTop: params.tabListStickyTop ?? state.tabListStickyTop,
179
187
  showTabbedFormAt: params.showTabbedFormAt ?? state.showTabbedFormAt,
180
188
  textFieldWidth: params.textFieldWidth ?? state.textFieldWidth,
181
189
  inputsFlexGrow: params.inputsFlexGrow ?? state.inputsFlexGrow,
@@ -16,7 +16,7 @@
16
16
  */
17
17
 
18
18
  import { createStore } from 'zustand/vanilla';
19
- import type { Encounter, Patient, Practitioner } from 'fhir/r4';
19
+ import type { Encounter, FhirResource, Patient, Practitioner } from 'fhir/r4';
20
20
  import type Client from 'fhirclient/lib/Client';
21
21
  import { createSelectors } from './selector';
22
22
  import type { FhirContext } from '@aehrc/sdc-populate';
@@ -31,11 +31,13 @@ import type { FhirContext } from '@aehrc/sdc-populate';
31
31
  * @property user - The user resource in context
32
32
  * @property encounter - The encounter resource in context
33
33
  * @property fhirContext - fhirContext array from SMART App Launch
34
+ * @property resolvedFhirContextReferences - resolved references from fhirContext, keyed by resource type e.g. `{ "PractitionerRole": <PractitionerRole> }`
34
35
  * @property setClient - Set the FHIRClient object when launching via SMART App Launch
35
36
  * @property setPatient - Set the patient resource in context
36
37
  * @property setUser - Set the user resource in context
37
38
  * @property setEncounter - Set the encounter resource in context
38
39
  * @property setFhirContext - Set the fhirContext array from SMART App Launch
40
+ * @property setResolvedFhirContextReferences - Set the resolvedFhirContextReferences object
39
41
  *
40
42
  * @author Sean Fong
41
43
  */
@@ -45,11 +47,15 @@ export interface SmartConfigStoreType {
45
47
  user: Practitioner | null;
46
48
  encounter: Encounter | null;
47
49
  fhirContext: FhirContext[] | null;
50
+ resolvedFhirContextReferences: Record<string, FhirResource> | null;
48
51
  setClient: (client: Client) => void;
49
52
  setPatient: (patient: Patient) => void;
50
53
  setUser: (user: Practitioner) => void;
51
54
  setEncounter: (encounter: Encounter) => void;
52
55
  setFhirContext: (fhirContext: FhirContext[]) => void;
56
+ setResolvedFhirContextReferences: (
57
+ resolvedFhirContextReferences: Record<string, FhirResource>
58
+ ) => void;
53
59
  }
54
60
 
55
61
  /**
@@ -68,11 +74,14 @@ export const smartConfigStore = createStore<SmartConfigStoreType>()((set) => ({
68
74
  user: null,
69
75
  encounter: null,
70
76
  fhirContext: null,
77
+ resolvedFhirContextReferences: null,
71
78
  setClient: (client: Client) => set(() => ({ client: client })),
72
79
  setPatient: (patient: Patient) => set(() => ({ patient: patient })),
73
80
  setUser: (user: Practitioner) => set(() => ({ user: user })),
74
81
  setEncounter: (encounter: Encounter) => set(() => ({ encounter: encounter })),
75
- setFhirContext: (fhirContext: FhirContext[]) => set(() => ({ fhirContext: fhirContext }))
82
+ setFhirContext: (fhirContext: FhirContext[]) => set(() => ({ fhirContext: fhirContext })),
83
+ setResolvedFhirContextReferences: (resolvedFhirContextReferences: Record<string, FhirResource>) =>
84
+ set(() => ({ resolvedFhirContextReferences }))
76
85
  }));
77
86
 
78
87
  /**
@@ -370,7 +370,7 @@ function applyCalculatedExpressionValuesRecursive(
370
370
  );
371
371
  }
372
372
 
373
- const qrItem = qrItemOrItems;
373
+ let qrItem = qrItemOrItems;
374
374
  const childQItems = qItem.item;
375
375
  if (childQItems && childQItems.length > 0) {
376
376
  const childQrItems = qrItem?.item ?? [];
@@ -391,13 +391,17 @@ function applyCalculatedExpressionValuesRecursive(
391
391
  // Update QR items in repeating group
392
392
  if (Array.isArray(updatedChildQRItemOrItems)) {
393
393
  if (updatedChildQRItemOrItems.length > 0) {
394
+ // Lazily initialise qrItem so all children are added to the same group object
395
+ if (!qrItem) {
396
+ qrItem = structuredClone(createEmptyQrGroup(qItem));
397
+ }
394
398
  updateQrItemsInGroup(
395
399
  null,
396
400
  {
397
401
  linkId: childQItem.linkId,
398
402
  qrItems: updatedChildQRItemOrItems
399
403
  },
400
- qrItem ?? structuredClone(createEmptyQrGroup(qItem)),
404
+ qrItem,
401
405
  indexMap
402
406
  );
403
407
  }
@@ -407,12 +411,11 @@ function applyCalculatedExpressionValuesRecursive(
407
411
  // Update QR items in non-repeating group
408
412
  const updatedChildQRItem = updatedChildQRItemOrItems;
409
413
  if (updatedChildQRItem) {
410
- updateQrItemsInGroup(
411
- updatedChildQRItem,
412
- null,
413
- qrItem ?? structuredClone(createEmptyQrGroup(qItem)),
414
- indexMap
415
- );
414
+ // Lazily initialise qrItem so all children are added to the same group object
415
+ if (!qrItem) {
416
+ qrItem = structuredClone(createEmptyQrGroup(qItem));
417
+ }
418
+ updateQrItemsInGroup(updatedChildQRItem, null, qrItem, indexMap);
416
419
  }
417
420
  }
418
421
 
@@ -23,25 +23,11 @@ export function isLaunchContext(extension: Extension): extension is LaunchContex
23
23
  extension.url ===
24
24
  'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-launchContext' &&
25
25
  !!extension.extension?.find(
26
- (ext) =>
27
- ext.url === 'name' &&
28
- (ext.valueId ||
29
- (ext.valueCoding &&
30
- (ext.valueCoding.code === 'patient' ||
31
- ext.valueCoding.code === 'encounter' ||
32
- ext.valueCoding.code === 'location' ||
33
- ext.valueCoding.code === 'user' ||
34
- ext.valueCoding.code === 'study' ||
35
- ext.valueCoding.code === 'sourceQueries')))
26
+ (ext) => ext.url === 'name' && (ext.valueId || (ext.valueCoding && ext.valueCoding.code))
36
27
  );
37
28
 
38
29
  const hasLaunchContextType = !!extension.extension?.find(
39
- (ext) =>
40
- ext.url === 'type' &&
41
- ext.valueCode &&
42
- (ext.valueCode === 'Patient' ||
43
- ext.valueCode === 'Practitioner' ||
44
- ext.valueCode === 'Encounter')
30
+ (ext) => ext.url === 'type' && ext.valueCode
45
31
  );
46
32
 
47
33
  return (
@@ -198,7 +198,8 @@ export function getResourceFromLaunchContext(
198
198
  resourceType: FhirResourceString,
199
199
  patient: Patient | null,
200
200
  user: Practitioner | null,
201
- encounter: Encounter | null
201
+ encounter: Encounter | null,
202
+ resolvedFhirContextReferences: Record<string, FhirResource> | null
202
203
  ): FhirResource | null {
203
204
  switch (resourceType) {
204
205
  case 'Patient':
@@ -208,7 +209,7 @@ export function getResourceFromLaunchContext(
208
209
  case 'Encounter':
209
210
  return encounter;
210
211
  }
211
- return null;
212
+ return resolvedFhirContextReferences?.[resourceType] ?? null;
212
213
  }
213
214
 
214
215
  /**