@getodk/xforms-engine 0.16.0 → 0.17.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 (124) hide show
  1. package/dist/client/AttributeNode.d.ts +4 -3
  2. package/dist/client/InputNode.d.ts +8 -4
  3. package/dist/client/MarkdownNode.d.ts +3 -0
  4. package/dist/client/NoteNode.d.ts +6 -2
  5. package/dist/client/form/FormInstanceConfig.d.ts +4 -0
  6. package/dist/client/form/LoadFormResult.d.ts +5 -14
  7. package/dist/client/form/ResetFormInstance.d.ts +13 -0
  8. package/dist/entrypoints/FormResult/BaseFormResult.d.ts +1 -0
  9. package/dist/entrypoints/FormResult/BaseInstantiableFormResult.d.ts +2 -0
  10. package/dist/entrypoints/FormResult/FormFailureResult.d.ts +2 -0
  11. package/dist/entrypoints/createPotentiallyClientOwnedReactiveScope.d.ts +19 -0
  12. package/dist/index.js +22150 -25908
  13. package/dist/index.js.map +1 -1
  14. package/dist/instance/Attribute.d.ts +11 -23
  15. package/dist/instance/Group.d.ts +3 -0
  16. package/dist/instance/InputControl.d.ts +3 -0
  17. package/dist/instance/ModelValue.d.ts +4 -0
  18. package/dist/instance/Note.d.ts +4 -0
  19. package/dist/instance/PrimaryInstance.d.ts +7 -1
  20. package/dist/instance/RangeControl.d.ts +4 -0
  21. package/dist/instance/RankControl.d.ts +5 -1
  22. package/dist/instance/Root.d.ts +3 -0
  23. package/dist/instance/SelectControl.d.ts +5 -1
  24. package/dist/instance/TriggerControl.d.ts +4 -0
  25. package/dist/instance/UploadControl.d.ts +3 -0
  26. package/dist/instance/abstract/DescendantNode.d.ts +5 -4
  27. package/dist/instance/abstract/InstanceNode.d.ts +4 -3
  28. package/dist/instance/hierarchy.d.ts +2 -1
  29. package/dist/instance/internal-api/AttributeContext.d.ts +1 -0
  30. package/dist/instance/internal-api/InstanceConfig.d.ts +2 -1
  31. package/dist/instance/internal-api/InstanceValueContext.d.ts +1 -0
  32. package/dist/instance/markdown/MarkdownNode.d.ts +14 -9
  33. package/dist/instance/repeat/RepeatInstance.d.ts +2 -0
  34. package/dist/integration/xpath/adapter/XFormsXPathNode.d.ts +1 -1
  35. package/dist/integration/xpath/adapter/kind.d.ts +5 -3
  36. package/dist/integration/xpath/adapter/traversal.d.ts +3 -3
  37. package/dist/integration/xpath/static-dom/StaticAttribute.d.ts +1 -0
  38. package/dist/integration/xpath/static-dom/StaticDocument.d.ts +2 -0
  39. package/dist/lib/codecs/{Geopoint/Geopoint.d.ts → geolocation/Geolocation.d.ts} +11 -15
  40. package/dist/lib/codecs/geolocation/Geopoint.d.ts +7 -0
  41. package/dist/lib/codecs/geolocation/Geoshape.d.ts +7 -0
  42. package/dist/lib/codecs/geolocation/Geotrace.d.ts +7 -0
  43. package/dist/lib/codecs/geolocation/createGeolocationValueCodec.d.ts +3 -0
  44. package/dist/lib/codecs/getSharedValueCodec.d.ts +7 -5
  45. package/dist/lib/reactivity/text/createTextRange.d.ts +0 -2
  46. package/dist/parse/XFormDOM.d.ts +7 -1
  47. package/dist/parse/body/appearance/inputAppearanceParser.d.ts +1 -1
  48. package/dist/parse/model/ActionDefinition.d.ts +1 -1
  49. package/dist/parse/model/AttributeDefinition.d.ts +2 -0
  50. package/dist/parse/model/BindPreloadDefinition.d.ts +2 -1
  51. package/dist/parse/model/ModelActionMap.d.ts +3 -2
  52. package/dist/parse/model/ModelDefinition.d.ts +3 -5
  53. package/dist/parse/model/SecondaryInstance/sources/CSVExternalSecondaryInstance.d.ts +0 -17
  54. package/dist/parse/model/SecondaryInstance/sources/external-instance-csv-parser.d.ts +8 -0
  55. package/dist/parse/model/TranslationDefinitionMap.d.ts +4 -0
  56. package/dist/solid.js +21608 -25366
  57. package/dist/solid.js.map +1 -1
  58. package/package.json +2 -2
  59. package/src/client/AttributeNode.ts +4 -3
  60. package/src/client/InputNode.ts +11 -3
  61. package/src/client/MarkdownNode.ts +3 -0
  62. package/src/client/NoteNode.ts +9 -1
  63. package/src/client/form/FormInstanceConfig.ts +6 -0
  64. package/src/client/form/LoadFormResult.ts +5 -17
  65. package/src/client/form/ResetFormInstance.ts +17 -0
  66. package/src/entrypoints/FormInstance.ts +2 -0
  67. package/src/entrypoints/FormResult/BaseFormResult.ts +1 -0
  68. package/src/entrypoints/FormResult/BaseInstantiableFormResult.ts +10 -1
  69. package/src/entrypoints/FormResult/FormFailureResult.ts +3 -0
  70. package/src/entrypoints/createPotentiallyClientOwnedReactiveScope.ts +30 -0
  71. package/src/entrypoints/loadForm.ts +1 -31
  72. package/src/instance/Attribute.ts +38 -54
  73. package/src/instance/Group.ts +12 -4
  74. package/src/instance/InputControl.ts +15 -9
  75. package/src/instance/ModelValue.ts +13 -4
  76. package/src/instance/Note.ts +13 -4
  77. package/src/instance/PrimaryInstance.ts +29 -6
  78. package/src/instance/RangeControl.ts +13 -4
  79. package/src/instance/RankControl.ts +14 -5
  80. package/src/instance/Root.ts +12 -4
  81. package/src/instance/SelectControl.ts +14 -5
  82. package/src/instance/TriggerControl.ts +13 -4
  83. package/src/instance/UploadControl.ts +13 -3
  84. package/src/instance/abstract/DescendantNode.ts +4 -3
  85. package/src/instance/abstract/InstanceNode.ts +5 -3
  86. package/src/instance/attachments/buildAttributes.ts +26 -2
  87. package/src/instance/children/childrenInitOptions.ts +2 -1
  88. package/src/instance/hierarchy.ts +2 -0
  89. package/src/instance/internal-api/AttributeContext.ts +1 -0
  90. package/src/instance/internal-api/InstanceConfig.ts +3 -0
  91. package/src/instance/internal-api/InstanceValueContext.ts +1 -0
  92. package/src/instance/markdown/MarkdownNode.ts +19 -7
  93. package/src/instance/repeat/RepeatInstance.ts +11 -3
  94. package/src/instance/text/markdownFormat.ts +4 -3
  95. package/src/integration/xpath/adapter/XFormsXPathNode.ts +1 -0
  96. package/src/integration/xpath/adapter/engineDOMAdapter.ts +2 -2
  97. package/src/integration/xpath/adapter/kind.ts +6 -1
  98. package/src/integration/xpath/adapter/names.ts +1 -0
  99. package/src/integration/xpath/adapter/traversal.ts +5 -6
  100. package/src/integration/xpath/static-dom/StaticAttribute.ts +1 -0
  101. package/src/integration/xpath/static-dom/StaticDocument.ts +2 -0
  102. package/src/lib/codecs/{Geopoint/Geopoint.ts → geolocation/Geolocation.ts} +43 -24
  103. package/src/lib/codecs/geolocation/Geopoint.ts +15 -0
  104. package/src/lib/codecs/geolocation/Geoshape.ts +36 -0
  105. package/src/lib/codecs/geolocation/Geotrace.ts +36 -0
  106. package/src/lib/codecs/geolocation/createGeolocationValueCodec.ts +18 -0
  107. package/src/lib/codecs/getSharedValueCodec.ts +37 -11
  108. package/src/lib/reactivity/createInstanceValueState.ts +90 -34
  109. package/src/lib/reactivity/text/createTextRange.ts +71 -45
  110. package/src/parse/XFormDOM.ts +22 -2
  111. package/src/parse/model/ActionDefinition.ts +6 -6
  112. package/src/parse/model/AttributeDefinition.ts +7 -0
  113. package/src/parse/model/BindDefinition.ts +1 -1
  114. package/src/parse/model/BindPreloadDefinition.ts +21 -14
  115. package/src/parse/model/ModelActionMap.ts +30 -13
  116. package/src/parse/model/ModelDefinition.ts +5 -10
  117. package/src/parse/model/RootDefinition.ts +2 -1
  118. package/src/parse/model/SecondaryInstance/sources/CSVExternalSecondaryInstance.ts +2 -184
  119. package/src/parse/model/SecondaryInstance/sources/external-instance-csv-parser.ts +185 -0
  120. package/src/parse/model/TranslationDefinitionMap.ts +23 -0
  121. package/dist/lib/codecs/Geopoint/GeopointValueCodec.d.ts +0 -5
  122. package/dist/parse/model/generateItextChunks.d.ts +0 -5
  123. package/src/lib/codecs/Geopoint/GeopointValueCodec.ts +0 -20
  124. package/src/parse/model/generateItextChunks.ts +0 -61
@@ -13,7 +13,10 @@ import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPat
13
13
  import type { StaticLeafElement } from '../integration/xpath/static-dom/StaticElement.ts';
14
14
  import type { RuntimeInputValue, RuntimeValue } from '../lib/codecs/getSharedValueCodec.ts';
15
15
  import { getSharedValueCodec } from '../lib/codecs/getSharedValueCodec.ts';
16
- import { createAttributeState } from '../lib/reactivity/createAttributeState.ts';
16
+ import {
17
+ createAttributeState,
18
+ type AttributeState,
19
+ } from '../lib/reactivity/createAttributeState.ts';
17
20
  import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
18
21
  import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
19
22
  import type { SharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
@@ -38,9 +41,7 @@ const stringInputNodeOptions = (control: InputControlDefinition): InputNodeOptio
38
41
  rows: control.rows,
39
42
  });
40
43
 
41
- const geoInputNodeOptions = (
42
- control: InputControlDefinition
43
- ): InputNodeOptions<'geopoint' | 'geoshape' | 'geotrace'> => ({
44
+ const geoInputNodeOptions = (control: InputControlDefinition): InputNodeOptions<'geopoint'> => ({
44
45
  accuracyThreshold: control.accuracyThreshold,
45
46
  unacceptableAccuracyThreshold: control.unacceptableAccuracyThreshold,
46
47
  });
@@ -62,8 +63,8 @@ const nodeOptionsFactoryByType: NodeOptionsFactoryByType = {
62
63
  time: () => null,
63
64
  dateTime: () => null,
64
65
  geopoint: geoInputNodeOptions,
65
- geotrace: geoInputNodeOptions,
66
- geoshape: geoInputNodeOptions,
66
+ geotrace: () => null,
67
+ geoshape: () => null,
67
68
  binary: () => null,
68
69
  barcode: () => null,
69
70
  intent: () => null,
@@ -104,6 +105,7 @@ export class InputControl<V extends ValueType = ValueType>
104
105
  // InstanceNode
105
106
  protected readonly state: SharedNodeState<InputControlStateSpec<V>>;
106
107
  protected readonly engineState: EngineState<InputControlStateSpec<V>>;
108
+ readonly attributeState: AttributeState;
107
109
 
108
110
  // InputNode
109
111
  readonly nodeType = 'input';
@@ -122,7 +124,7 @@ export class InputControl<V extends ValueType = ValueType>
122
124
 
123
125
  this.appearances = definition.bodyElement.appearances;
124
126
  this.nodeOptions = nodeOptionsFactoryByType[definition.valueType](definition.bodyElement);
125
- const attributeState = createAttributeState(this.scope);
127
+ this.attributeState = createAttributeState(this.scope);
126
128
 
127
129
  const state = createSharedNodeState(
128
130
  this.scope,
@@ -135,7 +137,7 @@ export class InputControl<V extends ValueType = ValueType>
135
137
  label: createNodeLabel(this, definition),
136
138
  hint: createFieldHint(this, definition),
137
139
  children: null,
138
- attributes: attributeState.getAttributes,
140
+ attributes: this.attributeState.getAttributes,
139
141
  valueOptions: null,
140
142
  value: this.valueState,
141
143
  instanceValue: this.getInstanceValue,
@@ -143,7 +145,7 @@ export class InputControl<V extends ValueType = ValueType>
143
145
  this.instanceConfig
144
146
  );
145
147
 
146
- attributeState.setAttributes(buildAttributes(this));
148
+ this.attributeState.setAttributes(buildAttributes(this));
147
149
 
148
150
  this.state = state;
149
151
  this.engineState = state.engineState;
@@ -155,6 +157,10 @@ export class InputControl<V extends ValueType = ValueType>
155
157
 
156
158
  return this.root;
157
159
  }
160
+
161
+ override getAttributes(): readonly Attribute[] {
162
+ return this.attributeState.getAttributes();
163
+ }
158
164
  }
159
165
 
160
166
  export type AnyInputControl =
@@ -5,11 +5,15 @@ import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPat
5
5
  import type { StaticLeafElement } from '../integration/xpath/static-dom/StaticElement.ts';
6
6
  import type { RuntimeInputValue, RuntimeValue } from '../lib/codecs/getSharedValueCodec.ts';
7
7
  import { getSharedValueCodec } from '../lib/codecs/getSharedValueCodec.ts';
8
- import { createAttributeState } from '../lib/reactivity/createAttributeState.ts';
8
+ import {
9
+ createAttributeState,
10
+ type AttributeState,
11
+ } from '../lib/reactivity/createAttributeState.ts';
9
12
  import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
10
13
  import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
11
14
  import type { SharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
12
15
  import { createSharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
16
+ import type { Attribute } from './Attribute.ts';
13
17
  import { ValueNode, type ValueNodeStateSpec } from './abstract/ValueNode.ts';
14
18
  import { buildAttributes } from './attachments/buildAttributes.ts';
15
19
  import type { GeneralParentNode } from './hierarchy.ts';
@@ -51,6 +55,7 @@ export class ModelValue<V extends ValueType = ValueType>
51
55
  // InstanceNode
52
56
  protected readonly state: SharedNodeState<ModelValueStateSpec<V>>;
53
57
  protected readonly engineState: EngineState<ModelValueStateSpec<V>>;
58
+ readonly attributeState: AttributeState;
54
59
 
55
60
  // ModelValueNode
56
61
  readonly nodeType = 'model-value';
@@ -67,7 +72,7 @@ export class ModelValue<V extends ValueType = ValueType>
67
72
 
68
73
  super(parent, instanceNode, definition, codec);
69
74
 
70
- const attributeState = createAttributeState(this.scope);
75
+ this.attributeState = createAttributeState(this.scope);
71
76
 
72
77
  const state = createSharedNodeState(
73
78
  this.scope,
@@ -80,7 +85,7 @@ export class ModelValue<V extends ValueType = ValueType>
80
85
  label: null,
81
86
  hint: null,
82
87
  children: null,
83
- attributes: attributeState.getAttributes,
88
+ attributes: this.attributeState.getAttributes,
84
89
  valueOptions: null,
85
90
  value: this.valueState,
86
91
  instanceValue: this.getInstanceValue,
@@ -88,12 +93,16 @@ export class ModelValue<V extends ValueType = ValueType>
88
93
  this.instanceConfig
89
94
  );
90
95
 
91
- attributeState.setAttributes(buildAttributes(this));
96
+ this.attributeState.setAttributes(buildAttributes(this));
92
97
 
93
98
  this.state = state;
94
99
  this.engineState = state.engineState;
95
100
  this.currentState = state.currentState;
96
101
  }
102
+
103
+ override getAttributes(): readonly Attribute[] {
104
+ return this.attributeState.getAttributes();
105
+ }
97
106
  }
98
107
 
99
108
  export type AnyModelValue =
@@ -8,7 +8,10 @@ import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPat
8
8
  import type { StaticLeafElement } from '../integration/xpath/static-dom/StaticElement.ts';
9
9
  import { getNoteCodec } from '../lib/codecs/getNoteCodec.ts';
10
10
  import type { NoteInputValue, NoteRuntimeValue } from '../lib/codecs/NoteCodec.ts';
11
- import { createAttributeState } from '../lib/reactivity/createAttributeState.ts';
11
+ import {
12
+ createAttributeState,
13
+ type AttributeState,
14
+ } from '../lib/reactivity/createAttributeState.ts';
12
15
  import { createNoteReadonlyThunk } from '../lib/reactivity/createNoteReadonlyThunk.ts';
13
16
  import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
14
17
  import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
@@ -20,6 +23,7 @@ import { createNoteText, type ComputedNoteText } from '../lib/reactivity/text/cr
20
23
  import type { NoteNodeDefinition } from '../parse/model/NoteNodeDefinition.ts';
21
24
  import { ValueNode, type ValueNodeStateSpec } from './abstract/ValueNode.ts';
22
25
  import { buildAttributes } from './attachments/buildAttributes.ts';
26
+ import type { Attribute } from './Attribute.ts';
23
27
  import type { GeneralParentNode } from './hierarchy.ts';
24
28
  import type { EvaluationContext } from './internal-api/EvaluationContext.ts';
25
29
  import type { ClientReactiveSerializableValueNode } from './internal-api/serialization/ClientReactiveSerializableValueNode.ts';
@@ -48,6 +52,7 @@ export class Note<V extends ValueType = ValueType>
48
52
  // InstanceNode
49
53
  protected readonly state: SharedNodeState<NoteStateSpec<V>>;
50
54
  protected readonly engineState: EngineState<NoteStateSpec<V>>;
55
+ readonly attributeState: AttributeState;
51
56
 
52
57
  // NoteNode
53
58
  readonly nodeType = 'note';
@@ -68,7 +73,7 @@ export class Note<V extends ValueType = ValueType>
68
73
 
69
74
  const isReadonly = createNoteReadonlyThunk(this, definition);
70
75
  const noteTextComputation = createNoteText(this, definition.noteTextDefinition);
71
- const attributeState = createAttributeState(this.scope);
76
+ this.attributeState = createAttributeState(this.scope);
72
77
 
73
78
  let noteText: ComputedNoteText;
74
79
  let label: Accessor<TextRange<'label', 'form'> | null>;
@@ -108,7 +113,7 @@ export class Note<V extends ValueType = ValueType>
108
113
  noteText,
109
114
 
110
115
  children: null,
111
- attributes: attributeState.getAttributes,
116
+ attributes: this.attributeState.getAttributes,
112
117
  valueOptions: null,
113
118
  value: this.valueState,
114
119
  instanceValue: this.getInstanceValue,
@@ -116,12 +121,16 @@ export class Note<V extends ValueType = ValueType>
116
121
  this.instanceConfig
117
122
  );
118
123
 
119
- attributeState.setAttributes(buildAttributes(this));
124
+ this.attributeState.setAttributes(buildAttributes(this));
120
125
 
121
126
  this.state = state;
122
127
  this.engineState = state.engineState;
123
128
  this.currentState = state.currentState;
124
129
  }
130
+
131
+ override getAttributes(): readonly Attribute[] {
132
+ return this.attributeState.getAttributes();
133
+ }
125
134
  }
126
135
 
127
136
  export type AnyNote =
@@ -1,6 +1,7 @@
1
- import { XPathNodeKindKey } from '@getodk/xpath';
1
+ import { clearCache, XPathNodeKindKey } from '@getodk/xpath';
2
2
  import type { Accessor } from 'solid-js';
3
3
  import { createSignal } from 'solid-js';
4
+ import type { GeolocationProvider } from '../client';
4
5
  import type { FormInstanceInitializationMode } from '../client/form/FormInstance.ts';
5
6
  import type { ActiveLanguage, FormLanguage, FormLanguages } from '../client/FormLanguage.ts';
6
7
  import type { FormNodeID } from '../client/identity.ts';
@@ -17,7 +18,10 @@ import { EngineXPathEvaluator } from '../integration/xpath/EngineXPathEvaluator.
17
18
  import type { StaticDocument } from '../integration/xpath/static-dom/StaticDocument.ts';
18
19
  import { createPrimaryInstanceState } from '../lib/client-reactivity/instance-state/createPrimaryInstanceState.ts';
19
20
  import { prepareInstancePayload } from '../lib/client-reactivity/instance-state/prepareInstancePayload.ts';
20
- import { createAttributeState } from '../lib/reactivity/createAttributeState.ts';
21
+ import {
22
+ createAttributeState,
23
+ type AttributeState,
24
+ } from '../lib/reactivity/createAttributeState.ts';
21
25
  import { createChildrenState } from '../lib/reactivity/createChildrenState.ts';
22
26
  import { createTranslationState } from '../lib/reactivity/createTranslationState.ts';
23
27
  import type { MaterializedChildren } from '../lib/reactivity/materializeCurrentStateChildren.ts';
@@ -84,6 +88,7 @@ interface PrimaryInstanceStateSpec {
84
88
 
85
89
  interface PrimaryInstanceStateInputByMode {
86
90
  readonly create: null;
91
+ readonly reset: null;
87
92
  readonly edit: InitialInstanceState;
88
93
  readonly restore: InitialInstanceState;
89
94
  }
@@ -92,7 +97,7 @@ export type PrimaryInstanceInitialState<Mode extends FormInstanceInitializationM
92
97
  PrimaryInstanceStateInputByMode[Mode];
93
98
 
94
99
  export interface BasePrimaryInstanceOptions {
95
- readonly scope: ReactiveScope;
100
+ scope: ReactiveScope;
96
101
  readonly model: ModelDefinition;
97
102
  readonly secondaryInstances: SecondaryInstancesDefinition;
98
103
  }
@@ -125,6 +130,7 @@ export class PrimaryInstance<
125
130
  // InstanceNode
126
131
  protected readonly state: SharedNodeState<PrimaryInstanceStateSpec>;
127
132
  protected readonly engineState: EngineState<PrimaryInstanceStateSpec>;
133
+ readonly attributeState: AttributeState;
128
134
 
129
135
  override readonly instanceNode: StaticDocument;
130
136
  readonly getChildren: Accessor<readonly Root[]>;
@@ -133,6 +139,7 @@ export class PrimaryInstance<
133
139
  readonly hasNonRelevantAncestor = () => false;
134
140
  readonly isRelevant = () => true;
135
141
 
142
+ private geolocationProvider: GeolocationProvider | undefined;
136
143
  // TranslationContext (support)
137
144
  private readonly setActiveLanguage: SimpleAtomicStateSetter<FormLanguage>;
138
145
 
@@ -164,6 +171,8 @@ export class PrimaryInstance<
164
171
  const activeInstance = initialState?.document ?? modelInstance;
165
172
  const definition = model.getRootDefinition(activeInstance);
166
173
 
174
+ clearCache();
175
+
167
176
  super(config, null, activeInstance, definition, {
168
177
  scope,
169
178
  computeReference: () => PRIMARY_INSTANCE_REFERENCE,
@@ -173,6 +182,7 @@ export class PrimaryInstance<
173
182
  this.model = model;
174
183
  this.attachments = new InstanceAttachmentsState(initialState?.attachments);
175
184
  this.instanceNode = activeInstance;
185
+ this.geolocationProvider = config.geolocationProvider;
176
186
 
177
187
  const [isAttached, setIsAttached] = createSignal(false);
178
188
 
@@ -197,7 +207,7 @@ export class PrimaryInstance<
197
207
  this.classes = definition.classes;
198
208
 
199
209
  const childrenState = createChildrenState<this, Root>(this);
200
- const attributeState = createAttributeState(this.scope);
210
+ this.attributeState = createAttributeState(this.scope);
201
211
 
202
212
  this.getChildren = childrenState.getChildren;
203
213
 
@@ -212,7 +222,7 @@ export class PrimaryInstance<
212
222
  valueOptions: null,
213
223
  value: null,
214
224
  children: childrenState.childIds,
215
- attributes: attributeState.getAttributes,
225
+ attributes: this.attributeState.getAttributes,
216
226
  };
217
227
 
218
228
  const state = createSharedNodeState(scope, stateSpec, config);
@@ -233,10 +243,14 @@ export class PrimaryInstance<
233
243
  this.instanceState = createPrimaryInstanceState(this);
234
244
 
235
245
  childrenState.setChildren([root]);
236
- attributeState.setAttributes(buildAttributes(this));
246
+ this.attributeState.setAttributes(buildAttributes(this));
237
247
  setIsAttached(true);
238
248
  }
239
249
 
250
+ override getAttributes(): readonly Attribute[] {
251
+ return this.attributeState.getAttributes();
252
+ }
253
+
240
254
  // PrimaryInstanceDocument
241
255
  /**
242
256
  * @todo Note that this method's signature is intentionally derived from
@@ -286,4 +300,13 @@ export class PrimaryInstance<
286
300
 
287
301
  return Promise.resolve(result);
288
302
  }
303
+
304
+ async getBackgroundGeopoint(): Promise<string> {
305
+ if (!this.geolocationProvider) {
306
+ return '';
307
+ }
308
+
309
+ const location = await this.geolocationProvider.getLocation();
310
+ return location ?? '';
311
+ }
289
312
  }
@@ -11,7 +11,10 @@ import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPat
11
11
  import type { StaticLeafElement } from '../integration/xpath/static-dom/StaticElement.ts';
12
12
  import { RangeCodec } from '../lib/codecs/RangeCodec.ts';
13
13
  import { getSharedValueCodec } from '../lib/codecs/getSharedValueCodec.ts';
14
- import { createAttributeState } from '../lib/reactivity/createAttributeState.ts';
14
+ import {
15
+ createAttributeState,
16
+ type AttributeState,
17
+ } from '../lib/reactivity/createAttributeState.ts';
15
18
  import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
16
19
  import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
17
20
  import type { SharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
@@ -23,6 +26,7 @@ import type {
23
26
  RangeNodeDefinition,
24
27
  RangeValueType,
25
28
  } from '../parse/model/RangeNodeDefinition.ts';
29
+ import type { Attribute } from './Attribute.ts';
26
30
  import type { Root } from './Root.ts';
27
31
  import { ValueNode, type ValueNodeStateSpec } from './abstract/ValueNode.ts';
28
32
  import { buildAttributes } from './attachments/buildAttributes.ts';
@@ -66,6 +70,7 @@ export class RangeControl<V extends RangeValueType = RangeValueType>
66
70
  // InstanceNode
67
71
  protected readonly state: SharedNodeState<RangeControlStateSpec<V>>;
68
72
  protected readonly engineState: EngineState<RangeControlStateSpec<V>>;
73
+ readonly attributeState: AttributeState;
69
74
 
70
75
  // RangeNode
71
76
  readonly nodeType = 'range';
@@ -84,7 +89,7 @@ export class RangeControl<V extends RangeValueType = RangeValueType>
84
89
  super(parent, instanceNode, definition, codec);
85
90
 
86
91
  this.appearances = definition.bodyElement.appearances;
87
- const attributeState = createAttributeState(this.scope);
92
+ this.attributeState = createAttributeState(this.scope);
88
93
 
89
94
  const state = createSharedNodeState(
90
95
  this.scope,
@@ -97,7 +102,7 @@ export class RangeControl<V extends RangeValueType = RangeValueType>
97
102
  label: createNodeLabel(this, definition),
98
103
  hint: createFieldHint(this, definition),
99
104
  children: null,
100
- attributes: attributeState.getAttributes,
105
+ attributes: this.attributeState.getAttributes,
101
106
  valueOptions: null,
102
107
  value: this.valueState,
103
108
  instanceValue: this.getInstanceValue,
@@ -105,7 +110,7 @@ export class RangeControl<V extends RangeValueType = RangeValueType>
105
110
  this.instanceConfig
106
111
  );
107
112
 
108
- attributeState.setAttributes(buildAttributes(this));
113
+ this.attributeState.setAttributes(buildAttributes(this));
109
114
 
110
115
  this.state = state;
111
116
  this.engineState = state.engineState;
@@ -117,6 +122,10 @@ export class RangeControl<V extends RangeValueType = RangeValueType>
117
122
 
118
123
  return this.root;
119
124
  }
125
+
126
+ override getAttributes(): readonly Attribute[] {
127
+ return this.attributeState.getAttributes();
128
+ }
120
129
  }
121
130
 
122
131
  // prettier-ignore
@@ -1,4 +1,4 @@
1
- import { type XPathChoiceNode, XPathNodeKindKey } from '@getodk/xpath';
1
+ import { XPathNodeKindKey, type XPathChoiceNode } from '@getodk/xpath';
2
2
  import type { Accessor } from 'solid-js';
3
3
  import { createMemo } from 'solid-js';
4
4
  import type { RankDefinition, RankItem, RankNode, RankValueOptions } from '../client/RankNode.ts';
@@ -10,7 +10,10 @@ import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPat
10
10
  import type { StaticLeafElement } from '../integration/xpath/static-dom/StaticElement.ts';
11
11
  import { sharedValueCodecs } from '../lib/codecs/getSharedValueCodec.ts';
12
12
  import { MultipleValueItemCodec } from '../lib/codecs/items/MultipleValueItemCodec.ts';
13
- import { createAttributeState } from '../lib/reactivity/createAttributeState.ts';
13
+ import {
14
+ createAttributeState,
15
+ type AttributeState,
16
+ } from '../lib/reactivity/createAttributeState.ts';
14
17
  import { createItemCollection } from '../lib/reactivity/createItemCollection.ts';
15
18
  import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
16
19
  import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
@@ -20,6 +23,7 @@ import { createFieldHint } from '../lib/reactivity/text/createFieldHint.ts';
20
23
  import { createNodeLabel } from '../lib/reactivity/text/createNodeLabel.ts';
21
24
  import type { SimpleAtomicState } from '../lib/reactivity/types.ts';
22
25
  import type { UnknownAppearanceDefinition } from '../parse/body/appearance/unknownAppearanceParser.ts';
26
+ import type { Attribute } from './Attribute.ts';
23
27
  import type { Root } from './Root.ts';
24
28
  import type { ValueNodeStateSpec } from './abstract/ValueNode.ts';
25
29
  import { ValueNode } from './abstract/ValueNode.ts';
@@ -96,6 +100,7 @@ export class RankControl
96
100
  // InstanceNode
97
101
  protected readonly state: SharedNodeState<RankControlStateSpec>;
98
102
  protected readonly engineState: EngineState<RankControlStateSpec>;
103
+ readonly attributeState: AttributeState;
99
104
 
100
105
  // RankNode
101
106
  readonly nodeType = 'rank';
@@ -125,7 +130,7 @@ export class RankControl
125
130
  const baseValueState = this.valueState;
126
131
  const [baseGetValue, setValue] = baseValueState;
127
132
 
128
- const attributeState = createAttributeState(this.scope);
133
+ this.attributeState = createAttributeState(this.scope);
129
134
 
130
135
  /**
131
136
  * @ToDo As new value options become available, they're not yet in the
@@ -178,7 +183,7 @@ export class RankControl
178
183
  label: createNodeLabel(this, definition),
179
184
  hint: createFieldHint(this, definition),
180
185
  children: null,
181
- attributes: attributeState.getAttributes,
186
+ attributes: this.attributeState.getAttributes,
182
187
  valueOptions,
183
188
  value: valueState,
184
189
  instanceValue: this.getInstanceValue,
@@ -186,13 +191,17 @@ export class RankControl
186
191
  this.instanceConfig
187
192
  );
188
193
 
189
- attributeState.setAttributes(buildAttributes(this));
194
+ this.attributeState.setAttributes(buildAttributes(this));
190
195
 
191
196
  this.state = state;
192
197
  this.engineState = state.engineState;
193
198
  this.currentState = state.currentState;
194
199
  }
195
200
 
201
+ override getAttributes(): readonly Attribute[] {
202
+ return this.attributeState.getAttributes();
203
+ }
204
+
196
205
  getValueLabel(value: string): TextRange<'item-label'> | null {
197
206
  const valueOption = this.currentState.valueOptions.find((item) => item.value === value);
198
207
  return valueOption?.label ?? null;
@@ -12,7 +12,10 @@ import type { InstanceState } from '../client/serialization/InstanceState.ts';
12
12
  import type { AncestorNodeValidationState } from '../client/validation.ts';
13
13
  import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPathNode.ts';
14
14
  import { createRootInstanceState } from '../lib/client-reactivity/instance-state/createRootInstanceState.ts';
15
- import { createAttributeState } from '../lib/reactivity/createAttributeState.ts';
15
+ import {
16
+ createAttributeState,
17
+ type AttributeState,
18
+ } from '../lib/reactivity/createAttributeState.ts';
16
19
  import type { ChildrenState } from '../lib/reactivity/createChildrenState.ts';
17
20
  import { createChildrenState } from '../lib/reactivity/createChildrenState.ts';
18
21
  import type { MaterializedChildren } from '../lib/reactivity/materializeCurrentStateChildren.ts';
@@ -67,6 +70,7 @@ export class Root
67
70
  // DescendantNode
68
71
  protected readonly state: SharedNodeState<RootStateSpec>;
69
72
  protected readonly engineState: EngineState<RootStateSpec>;
73
+ readonly attributeState: AttributeState;
70
74
 
71
75
  override readonly hasReadonlyAncestor = () => false;
72
76
  override readonly isSelfReadonly = () => false;
@@ -99,7 +103,7 @@ export class Root
99
103
  this.classes = parent.classes;
100
104
 
101
105
  const childrenState = createChildrenState<Root, GeneralChildNode>(this);
102
- const attributeState = createAttributeState(this.scope);
106
+ this.attributeState = createAttributeState(this.scope);
103
107
 
104
108
  this.childrenState = childrenState;
105
109
  this.languages = parent.languages;
@@ -117,7 +121,7 @@ export class Root
117
121
  valueOptions: null,
118
122
  value: null,
119
123
  children: childrenState.childIds,
120
- attributes: attributeState.getAttributes,
124
+ attributes: this.attributeState.getAttributes,
121
125
  },
122
126
  this.instanceConfig
123
127
  );
@@ -131,7 +135,7 @@ export class Root
131
135
  );
132
136
 
133
137
  childrenState.setChildren(buildChildren(this));
134
- attributeState.setAttributes(buildAttributes(this));
138
+ this.attributeState.setAttributes(buildAttributes(this));
135
139
  this.validationState = createAggregatedViolations(this, this.instanceConfig);
136
140
  this.instanceState = createRootInstanceState(this);
137
141
  }
@@ -140,6 +144,10 @@ export class Root
140
144
  return this.childrenState.getChildren();
141
145
  }
142
146
 
147
+ override getAttributes(): readonly Attribute[] {
148
+ return this.attributeState.getAttributes();
149
+ }
150
+
143
151
  // RootNode
144
152
  setLanguage(language: FormLanguage): Root {
145
153
  this.rootDocument.setLanguage(language);
@@ -1,4 +1,4 @@
1
- import { type XPathChoiceNode, XPathNodeKindKey } from '@getodk/xpath';
1
+ import { XPathNodeKindKey, type XPathChoiceNode } from '@getodk/xpath';
2
2
  import type { Accessor } from 'solid-js';
3
3
  import { createMemo } from 'solid-js';
4
4
  import type {
@@ -14,7 +14,10 @@ import { SelectValueTypeError } from '../error/SelectValueTypeError.ts';
14
14
  import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPathNode.ts';
15
15
  import type { StaticLeafElement } from '../integration/xpath/static-dom/StaticElement.ts';
16
16
  import { getSelectCodec } from '../lib/codecs/getSelectCodec.ts';
17
- import { createAttributeState } from '../lib/reactivity/createAttributeState.ts';
17
+ import {
18
+ createAttributeState,
19
+ type AttributeState,
20
+ } from '../lib/reactivity/createAttributeState.ts';
18
21
  import { createItemCollection } from '../lib/reactivity/createItemCollection.ts';
19
22
  import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
20
23
  import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
@@ -24,6 +27,7 @@ import { createFieldHint } from '../lib/reactivity/text/createFieldHint.ts';
24
27
  import { createNodeLabel } from '../lib/reactivity/text/createNodeLabel.ts';
25
28
  import type { SimpleAtomicState } from '../lib/reactivity/types.ts';
26
29
  import type { SelectType } from '../parse/body/control/SelectControlDefinition.ts';
30
+ import type { Attribute } from './Attribute.ts';
27
31
  import type { Root } from './Root.ts';
28
32
  import type { ValueNodeStateSpec } from './abstract/ValueNode.ts';
29
33
  import { ValueNode } from './abstract/ValueNode.ts';
@@ -91,6 +95,7 @@ export class SelectControl
91
95
  // InstanceNode
92
96
  protected readonly state: SharedNodeState<SelectControlStateSpec>;
93
97
  protected readonly engineState: EngineState<SelectControlStateSpec>;
98
+ readonly attributeState: AttributeState;
94
99
 
95
100
  // SelectNode
96
101
  readonly nodeType = 'select';
@@ -110,7 +115,7 @@ export class SelectControl
110
115
 
111
116
  this.appearances = definition.bodyElement.appearances;
112
117
  this.selectType = definition.bodyElement.type;
113
- const attributeState = createAttributeState(this.scope);
118
+ this.attributeState = createAttributeState(this.scope);
114
119
 
115
120
  const valueOptions = createItemCollection(this);
116
121
 
@@ -156,7 +161,7 @@ export class SelectControl
156
161
  label: createNodeLabel(this, definition),
157
162
  hint: createFieldHint(this, definition),
158
163
  children: null,
159
- attributes: attributeState.getAttributes,
164
+ attributes: this.attributeState.getAttributes,
160
165
  valueOptions,
161
166
  value: valueState,
162
167
  instanceValue: this.getInstanceValue,
@@ -165,7 +170,7 @@ export class SelectControl
165
170
  this.instanceConfig
166
171
  );
167
172
 
168
- attributeState.setAttributes(buildAttributes(this));
173
+ this.attributeState.setAttributes(buildAttributes(this));
169
174
 
170
175
  this.state = state;
171
176
  this.engineState = state.engineState;
@@ -243,4 +248,8 @@ export class SelectControl
243
248
  const option = this.mapOptionsByValue().get(value);
244
249
  return option?.label?.asString ?? null;
245
250
  }
251
+
252
+ override getAttributes(): readonly Attribute[] {
253
+ return this.attributeState.getAttributes();
254
+ }
246
255
  }
@@ -8,7 +8,10 @@ import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPat
8
8
  import type { StaticLeafElement } from '../integration/xpath/static-dom/StaticElement.ts';
9
9
  import type { TriggerInputValue, TriggerRuntimeValue } from '../lib/codecs/TriggerCodec.ts';
10
10
  import { TriggerCodec } from '../lib/codecs/TriggerCodec.ts';
11
- import { createAttributeState } from '../lib/reactivity/createAttributeState.ts';
11
+ import {
12
+ createAttributeState,
13
+ type AttributeState,
14
+ } from '../lib/reactivity/createAttributeState.ts';
12
15
  import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
13
16
  import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
14
17
  import type { SharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
@@ -16,6 +19,7 @@ import { createSharedNodeState } from '../lib/reactivity/node-state/createShared
16
19
  import { createFieldHint } from '../lib/reactivity/text/createFieldHint.ts';
17
20
  import { createNodeLabel } from '../lib/reactivity/text/createNodeLabel.ts';
18
21
  import type { UnknownAppearanceDefinition } from '../parse/body/appearance/unknownAppearanceParser.ts';
22
+ import type { Attribute } from './Attribute.ts';
19
23
  import type { Root } from './Root.ts';
20
24
  import { ValueNode, type ValueNodeStateSpec } from './abstract/ValueNode.ts';
21
25
  import { buildAttributes } from './attachments/buildAttributes.ts';
@@ -75,6 +79,7 @@ export class TriggerControl
75
79
  // InstanceNode
76
80
  protected readonly state: SharedNodeState<TriggerControlStateSpec>;
77
81
  protected readonly engineState: EngineState<TriggerControlStateSpec>;
82
+ readonly attributeState: AttributeState;
78
83
 
79
84
  // TriggerNode
80
85
  readonly nodeType = 'trigger';
@@ -90,7 +95,7 @@ export class TriggerControl
90
95
  super(parent, instanceNode, definition, codec);
91
96
 
92
97
  this.appearances = definition.bodyElement.appearances;
93
- const attributeState = createAttributeState(this.scope);
98
+ this.attributeState = createAttributeState(this.scope);
94
99
 
95
100
  const state = createSharedNodeState(
96
101
  this.scope,
@@ -103,7 +108,7 @@ export class TriggerControl
103
108
  label: createNodeLabel(this, definition),
104
109
  hint: createFieldHint(this, definition),
105
110
  children: null,
106
- attributes: attributeState.getAttributes,
111
+ attributes: this.attributeState.getAttributes,
107
112
  valueOptions: null,
108
113
  value: this.valueState,
109
114
  instanceValue: this.getInstanceValue,
@@ -111,13 +116,17 @@ export class TriggerControl
111
116
  this.instanceConfig
112
117
  );
113
118
 
114
- attributeState.setAttributes(buildAttributes(this));
119
+ this.attributeState.setAttributes(buildAttributes(this));
115
120
 
116
121
  this.state = state;
117
122
  this.engineState = state.engineState;
118
123
  this.currentState = state.currentState;
119
124
  }
120
125
 
126
+ override getAttributes(): readonly Attribute[] {
127
+ return this.attributeState.getAttributes();
128
+ }
129
+
121
130
  // TriggerNode
122
131
  setValue(value: TriggerInputValue): Root {
123
132
  this.setValueState(value);