@adriansteffan/reactive 0.0.44 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { W as e } from "./mod-D6DlS3ur.js";
1
+ import { W as e } from "./mod-Beb0Bz3s.js";
2
2
  class s extends e {
3
3
  async enable() {
4
4
  console.log("Immersive mode is only available on Android");
@@ -1,4 +1,4 @@
1
- import { W as P, b as x, E } from "./mod-D6DlS3ur.js";
1
+ import { W as P, b as x, E } from "./mod-Beb0Bz3s.js";
2
2
  function m(w) {
3
3
  const e = w.split("/").filter((t) => t !== "."), r = [];
4
4
  return e.forEach((t) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adriansteffan/reactive",
3
- "version": "0.0.44",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite",
@@ -10,11 +10,14 @@ import {
10
10
  UnifiedBytecodeInstruction,
11
11
  ExecuteContentInstruction,
12
12
  Store,
13
- RefinedTrialData,
13
+ TrialResult,
14
14
  CanvasResultData,
15
15
  } from '../utils/bytecode';
16
16
  import { BaseComponentProps, isFullscreen, now } from '../utils/common';
17
17
  import { registerSimulation, ParticipantState } from '../utils/simulation';
18
+ import { registerFlattener, arrayFlattener } from '../utils/upload';
19
+
20
+ registerFlattener('CanvasBlock', 'canvas', arrayFlattener);
18
21
 
19
22
  export type SlideSimulatorResult = {
20
23
  key: string | null;
@@ -37,12 +40,12 @@ interface CanvasSlide {
37
40
  allowedKeys?: string[] | boolean;
38
41
  metadata?:
39
42
  | Record<string, any>
40
- | ((data?: RefinedTrialData[], store?: Store) => Record<string, any>);
43
+ | ((data?: TrialResult[], store?: Store) => Record<string, any>);
41
44
  nestMetadata?: boolean;
42
45
  simulate?: SlideSimulator;
43
46
  }
44
47
 
45
- type DynamicCanvasSlideGenerator = (data: RefinedTrialData[], store: Store) => CanvasSlide;
48
+ type DynamicCanvasSlideGenerator = (data: TrialResult[], store: Store) => CanvasSlide;
46
49
 
47
50
  function isDynamicCanvasSlideGenerator(content: any): content is DynamicCanvasSlideGenerator {
48
51
  return typeof content === 'function';
@@ -77,7 +80,7 @@ export default function CanvasBlock({
77
80
  const isDrawingVisibleRef = useRef<boolean>(true);
78
81
  const responseRegisteredRef = useRef<null | Record<string, any>>(null);
79
82
  const canvasRef = useRef<HTMLCanvasElement>(null);
80
- const dataRef = useRef<RefinedTrialData[]>([]);
83
+ const dataRef = useRef<TrialResult[]>([]);
81
84
  const storeRef = useRef<Store>(store ?? {});
82
85
  const animationFrameRef = useRef<number | null>(null);
83
86
  const contentInstructionsCompletedRef = useRef(0);
@@ -513,7 +516,7 @@ registerSimulation('CanvasBlock', (trialProps, experimentState, simulators, part
513
516
  let slideNumber = 0;
514
517
 
515
518
  const getStore = () => innerStore;
516
- const getData = () => innerData as RefinedTrialData[];
519
+ const getData = () => innerData as TrialResult[];
517
520
  const onUpdateStore = (s: Store) => { innerStore = s; };
518
521
 
519
522
  let pointer = advanceToNextContent(bytecode, 0, getStore, getData, onUpdateStore);
@@ -1,6 +1,9 @@
1
1
  import { BaseComponentProps } from '../mod';
2
2
  import { useEffect, useRef, useState } from 'react';
3
3
  import { registerSimulation } from '../utils/simulation';
4
+ import { registerFlattener } from '../utils/upload';
5
+
6
+ registerFlattener('CheckDevice', 'session');
4
7
 
5
8
  registerSimulation('CheckDevice', (_trialProps, _experimentState, _simulators, participant) => {
6
9
  const deviceInfo = {
@@ -1,11 +1,13 @@
1
1
  import React, { useState, useCallback, useRef, useEffect } from 'react';
2
2
  import { BaseComponentProps, getPlatform, isFullscreen } from '../utils/common';
3
3
  import { registerSimulation, noopSimulate } from '../utils/simulation';
4
+ import { registerFlattener } from '../utils/upload';
4
5
  import Text from '../components/text';
5
6
  import { StatusBar } from '@capacitor/status-bar';
6
7
  import { ImmersiveMode } from '@adriansteffan/immersive-mode';
7
8
  import { Capacitor } from '@capacitor/core';
8
9
 
10
+ registerFlattener('EnterFullscreen', 'session');
9
11
  registerSimulation('EnterFullscreen', noopSimulate, {});
10
12
 
11
13
  export default function EnterFullscreen({
@@ -1,10 +1,12 @@
1
1
  import { useCallback, useRef, useEffect } from 'react';
2
2
  import { BaseComponentProps, getPlatform, isFullscreen } from '../utils/common';
3
3
  import { registerSimulation, noopSimulate } from '../utils/simulation';
4
+ import { registerFlattener } from '../utils/upload';
4
5
  import { StatusBar } from '@capacitor/status-bar';
5
6
  import { ImmersiveMode } from '@adriansteffan/immersive-mode';
6
7
  import { Capacitor } from '@capacitor/core';
7
8
 
9
+ registerFlattener('ExitFullscreen', 'session');
8
10
  registerSimulation('ExitFullscreen', noopSimulate, {});
9
11
 
10
12
  export default function ExitFullscreen({
@@ -8,7 +8,7 @@ import {
8
8
  advanceToNextContent,
9
9
  applyMetadata,
10
10
  TimelineItem,
11
- RefinedTrialData,
11
+ TrialResult,
12
12
  ComponentResultData,
13
13
  } from '../utils/bytecode';
14
14
  import {
@@ -60,13 +60,14 @@ const defaultCustomQuestions: ComponentsMap = {
60
60
  interface RuntimeComponentContent {
61
61
  name?: string;
62
62
  type: string;
63
+ csv?: string | string[];
63
64
  collectRefreshRate?: boolean;
64
65
  hideSettings?: string[] | boolean;
65
66
  metadata?:
66
67
  | Record<string, any>
67
- | ((data: RefinedTrialData[], store: Store) => Record<string, any>);
68
+ | ((data: TrialResult[], store: Store) => Record<string, any>);
68
69
  nestMetadata?: boolean;
69
- props?: Record<string, any> | ((data: RefinedTrialData[], store: Store) => Record<string, any>);
70
+ props?: Record<string, any> | ((data: TrialResult[], store: Store) => Record<string, any>);
70
71
  simulate?: SimulateFunction | boolean;
71
72
  simulators?: Record<string, any>;
72
73
  }
@@ -95,8 +96,7 @@ export default function ExperimentRunner({
95
96
  return compileTimeline(timeline);
96
97
  }, [timeline]);
97
98
 
98
- const [instructionPointer, setInstructionPointer] = useState(0);
99
- const dataRef = useRef<RefinedTrialData[]>((() => {
99
+ const dataRef = useRef<TrialResult[]>((() => {
100
100
  const urlParams: Record<string, any> = {};
101
101
  const searchParams = new URLSearchParams(window.location.search);
102
102
  for (const [key, value] of searchParams.entries()) {
@@ -150,6 +150,16 @@ export default function ExperimentRunner({
150
150
  const lastTrialEndTimeRef = useRef(now());
151
151
  const experimentStoreRef = useRef<Store>({});
152
152
 
153
+ const [instructionPointer, setInstructionPointer] = useState(() =>
154
+ advanceToNextContent(
155
+ trialByteCode,
156
+ 0,
157
+ () => experimentStoreRef.current,
158
+ () => dataRef.current,
159
+ (s) => { experimentStoreRef.current = { ...experimentStoreRef.current, ...s }; },
160
+ )
161
+ );
162
+
153
163
  const simulationMode =
154
164
  (!disableHybridSimulation && getParam('hybridSimulation', false, 'boolean'))
155
165
  ? 'hybrid' as const
@@ -199,6 +209,7 @@ export default function ExperimentRunner({
199
209
  duration: endTime - startTime,
200
210
  type: content.type,
201
211
  name: content.name ?? '',
212
+ ...(content.csv !== undefined ? { csv: content.csv } : {}),
202
213
  responseData: componentResponseData,
203
214
  };
204
215
 
@@ -396,8 +407,9 @@ export default function ExperimentRunner({
396
407
  <div
397
408
  className={` ${
398
409
  config.showProgressBar ? '' : 'hidden '
399
- } px-4 mt-4 sm:mt-12 max-w-2xl mx-auto flex-1 h-6 bg-gray-200 rounded-full overflow-hidden`}
410
+ } px-4 mt-4 sm:mt-12 max-w-2xl mx-auto`}
400
411
  >
412
+ <div className='flex-1 h-6 bg-gray-200 rounded-full overflow-hidden'>
401
413
  <div
402
414
  className={`h-full bg-gray-200 rounded-full duration-300 ${
403
415
  progress > 0 ? ' border-black border-2' : ''
@@ -410,6 +422,7 @@ export default function ExperimentRunner({
410
422
  transition: 'width 300ms ease-in-out',
411
423
  }}
412
424
  />
425
+ </div>
413
426
  </div>
414
427
  {componentToRender}
415
428
  </div>
@@ -1,7 +1,9 @@
1
1
  import { useState, useEffect } from 'react';
2
2
  import { VoiceRecorder } from './voicerecorder';
3
3
  import { registerSimulation, noopSimulate } from '../utils/simulation';
4
+ import { registerFlattener } from '../utils/upload';
4
5
 
6
+ registerFlattener('MicrophoneCheck', 'session');
5
7
  registerSimulation('MicrophoneCheck', noopSimulate, {});
6
8
 
7
9
  interface MicrophoneDevice {
@@ -156,7 +158,7 @@ const MicrophoneCheck = ({ next }: { next: (data: object) => void }) => {
156
158
  <div className='mt-16 flex justify-center'>
157
159
  <button
158
160
  onClick={() => next({})}
159
- className='bg-white px-8 py-3 border-2 border-black font-bold text-black text-lg rounded-xl shadow-[2px_2px_0px_rgba(0,0,0,1)] hover:translate-x-[2px] hover:translate-y-[2px] hover:shadow-none'
161
+ className='bg-white cursor-pointer px-8 py-3 border-2 border-black font-bold text-black text-lg rounded-xl shadow-[2px_2px_0px_rgba(0,0,0,1)] hover:translate-x-[2px] hover:translate-y-[2px] hover:shadow-none'
160
162
  >
161
163
  Next
162
164
  </button>
@@ -1,6 +1,9 @@
1
1
  import { BaseComponentProps } from '../mod';
2
2
  import { useState } from 'react';
3
3
  import { registerSimulation } from '../utils/simulation';
4
+ import { registerFlattener } from '../utils/upload';
5
+
6
+ registerFlattener('PlainInput', 'session');
4
7
 
5
8
  registerSimulation('PlainInput', (trialProps, _experimentState, simulators, participant) => {
6
9
  const result = simulators.respond(trialProps, participant);
@@ -1,7 +1,9 @@
1
1
  import { BaseComponentProps, getParam, registerComponentParams } from '../utils/common';
2
2
  import Text from '../components/text';
3
3
  import { registerSimulation, noopSimulate } from '../utils/simulation';
4
+ import { registerFlattener } from '../utils/upload';
4
5
 
6
+ registerFlattener('ProlificEnding', null);
5
7
  registerSimulation('ProlificEnding', noopSimulate, {});
6
8
 
7
9
  registerComponentParams('ProlificEnding', [
@@ -4,6 +4,9 @@ import { ReactQuestionFactory, Survey, SurveyQuestionElementBase } from 'survey-
4
4
  import { ContrastLight } from 'survey-core/themes';
5
5
  import 'survey-core/survey-core.min.css';
6
6
  import { registerSimulation } from '../utils/simulation';
7
+ import { registerFlattener } from '../utils/upload';
8
+
9
+ registerFlattener('Quest', 'session');
7
10
 
8
11
  registerSimulation('Quest', (trialProps, _experimentState, simulators, participant) => {
9
12
  const responseData: Record<string, any> = {};
@@ -1,6 +1,9 @@
1
1
  import { BaseComponentProps } from '../mod';
2
2
  import React, { useState, useEffect } from 'react';
3
3
  import { registerSimulation } from '../utils/simulation';
4
+ import { registerFlattener } from '../utils/upload';
5
+
6
+ registerFlattener('StoreUI', 'storeui');
4
7
 
5
8
  interface BaseFieldConfig {
6
9
  type: 'string' | 'integer' | 'float' | 'boolean';
@@ -1,6 +1,9 @@
1
1
  import React, { useEffect, useRef } from 'react';
2
2
  import { BaseComponentProps, now } from '../mod';
3
3
  import { registerSimulation } from '../utils/simulation';
4
+ import { registerFlattener } from '../utils/upload';
5
+
6
+ registerFlattener('Text', 'text');
4
7
 
5
8
  registerSimulation('Text', (trialProps, _experimentState, simulators, participant) => {
6
9
  const result = simulators.respond(trialProps, participant);
@@ -14,7 +14,7 @@ import {
14
14
  } from '../utils/common';
15
15
  import { BlobWriter, TextReader, ZipWriter } from '@zip.js/zip.js';
16
16
  import { Filesystem, Directory, Encoding } from '@capacitor/filesystem';
17
- import { buildUploadFiles, convertArrayOfObjectsToCSV, CSVBuilder } from '../utils/upload';
17
+ import { buildUploadFiles, convertArrayOfObjectsToCSV } from '../utils/upload';
18
18
  import { registerSimulation, getBackendUrl, getInitialParticipant } from '../utils/simulation';
19
19
 
20
20
  registerSimulation('Upload', async (trialProps, experimentState, _simulators, participant) => {
@@ -24,8 +24,7 @@ registerSimulation('Upload', async (trialProps, experimentState, _simulators, pa
24
24
  data: experimentState.data || [],
25
25
  store: experimentState.store,
26
26
  generateFiles: trialProps.generateFiles,
27
- sessionCSVBuilder: trialProps.sessionCSVBuilder,
28
- trialCSVBuilder: trialProps.trialCSVBuilder,
27
+ sessionData: trialProps.sessionData,
29
28
  uploadRaw: trialProps.uploadRaw ?? true,
30
29
  });
31
30
 
@@ -72,21 +71,21 @@ interface UploadResponse {
72
71
  message?: string;
73
72
  }
74
73
 
75
- // TODO: deduplicate values with upload function below
76
- registerComponentParams('Upload', [
74
+ const UPLOAD_PARAMS = [
77
75
  {
78
76
  name: 'upload',
79
77
  defaultValue: true,
80
- type: 'boolean',
78
+ type: 'boolean' as const,
81
79
  description: 'Upload the data at the end of the experiment?',
82
80
  },
83
81
  {
84
82
  name: 'download',
85
83
  defaultValue: false,
86
- type: 'boolean',
84
+ type: 'boolean' as const,
87
85
  description: 'Locally download the data at the end of the experiment?',
88
86
  },
89
- ]);
87
+ ];
88
+ registerComponentParams('Upload', UPLOAD_PARAMS);
90
89
 
91
90
 
92
91
  interface FileBackend {
@@ -224,18 +223,16 @@ export default function Upload({
224
223
  store,
225
224
  sessionID,
226
225
  generateFiles,
227
- sessionCSVBuilder,
228
- trialCSVBuilder,
226
+ sessionData,
229
227
  uploadRaw = true,
230
228
  autoUpload = false,
231
229
  androidFolderName,
232
230
  }: BaseComponentProps & {
233
231
  sessionID?: string | null;
234
- generateFiles: (sessionID: string, data: TrialData[], store?: Store) => FileUpload[];
235
- sessionCSVBuilder: CSVBuilder;
236
- trialCSVBuilder: {flatteners: Record<string, ((item: TrialData) => Record<string, any>[] | Record<string, Record<string, any>[]>)>, builders: CSVBuilder[]};
237
- uploadRaw: boolean;
238
- autoUpload: boolean;
232
+ generateFiles?: (sessionID: string, data: TrialData[], store?: Store) => FileUpload[];
233
+ sessionData?: Record<string, any>;
234
+ uploadRaw?: boolean;
235
+ autoUpload?: boolean;
239
236
  androidFolderName?: string;
240
237
  }) {
241
238
  const [uploadState, setUploadState] = useState<'initial' | 'uploading' | 'success' | 'error'>(
@@ -243,8 +240,10 @@ export default function Upload({
243
240
  );
244
241
  const uploadInitiatedRef = useRef(false);
245
242
 
246
- const shouldUpload = getParam('upload', true, 'boolean');
247
- const shouldDownload = getParam('download', false, 'boolean');
243
+ const uploadParam = UPLOAD_PARAMS.find(p => p.name === 'upload')!;
244
+ const downloadParam = UPLOAD_PARAMS.find(p => p.name === 'download')!;
245
+ const shouldUpload = getParam(uploadParam.name, uploadParam.defaultValue, uploadParam.type);
246
+ const shouldDownload = getParam(downloadParam.name, downloadParam.defaultValue, downloadParam.type);
248
247
 
249
248
  const uploadData = useMutation({
250
249
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -299,8 +298,7 @@ export default function Upload({
299
298
  data,
300
299
  store,
301
300
  generateFiles,
302
- sessionCSVBuilder,
303
- trialCSVBuilder,
301
+ sessionData,
304
302
  uploadRaw,
305
303
  });
306
304
 
@@ -401,7 +399,7 @@ export default function Upload({
401
399
  </div>
402
400
  <button
403
401
  onClick={handleUpload}
404
- className='px-4 py-2 cursor-pointer bg-blue-500 text-white rounded-sm hover:bg-blue-600 transition-colors'
402
+ className='cursor-pointer bg-white px-8 py-3 border-2 border-black font-bold text-black text-lg rounded-xl shadow-[2px_2px_0px_rgba(0,0,0,1)] hover:translate-x-[2px] hover:translate-y-[2px] hover:shadow-none'
405
403
  >
406
404
  Try Again
407
405
  </button>
package/src/index.css CHANGED
@@ -31,26 +31,6 @@
31
31
  }
32
32
 
33
33
 
34
- @keyframes slideDown {
35
- 0% {
36
- transform: translateY(-10px);
37
- opacity: 0;
38
- }
39
- 100% {
40
- transform: translateY(0);
41
- opacity: 1;
42
- }
43
- }
44
-
45
- @keyframes fadeIn {
46
- 0% {
47
- opacity: 0;
48
- }
49
- 100% {
50
- opacity: 1;
51
- }
52
- }
53
-
54
34
  /*
55
35
  The default border color has changed to `currentColor` in Tailwind CSS v4,
56
36
  so we've added these compatibility styles to make sure everything still
package/src/mod.tsx CHANGED
@@ -5,6 +5,7 @@ export type { BaseComponentProps, ExperimentConfig };
5
5
  export * from './utils/array';
6
6
  export * from './utils/common';
7
7
  export * from './utils/simulation';
8
+ export { registerFlattener, arrayFlattener } from './utils/upload';
8
9
  export * from './components';
9
10
 
10
11
  export * from 'react-toastify';
@@ -11,6 +11,8 @@ type BaseTrialData = {
11
11
  export type ComponentResultData = BaseTrialData & {
12
12
  type: string;
13
13
  name: string;
14
+ /** Per-trial override for which CSV file(s) this trial's data goes into. When set on a timeline item, overrides the component type's default from the flattener registry. */
15
+ csv?: string | string[];
14
16
  responseData?: any;
15
17
  metadata?: Record<string, any>;
16
18
  };
@@ -21,16 +23,16 @@ export type CanvasResultData = BaseTrialData & {
21
23
  reactionTime: number | null;
22
24
  };
23
25
 
24
- export type RefinedTrialData = ComponentResultData | CanvasResultData;
26
+ export type TrialResult = ComponentResultData | CanvasResultData;
25
27
 
26
28
  export interface MarkerItem {
27
29
  type: 'MARKER';
28
30
  id: string;
29
31
  }
30
32
 
31
- export type ConditionalFunction = (data?: RefinedTrialData[], store?: Store) => boolean;
33
+ export type ConditionalFunction = (data?: TrialResult[], store?: Store) => boolean;
32
34
 
33
- export type StoreUpdateFunction = (data?: RefinedTrialData[], store?: Store) => Record<string, any>;
35
+ export type StoreUpdateFunction = (data?: TrialResult[], store?: Store) => Record<string, any>;
34
36
 
35
37
  export interface IfGotoItem {
36
38
  type: 'IF_GOTO';
@@ -65,12 +67,12 @@ export interface ExecuteContentInstruction {
65
67
  }
66
68
  export interface IfGotoInstruction {
67
69
  type: 'IfGoto';
68
- cond: (store: Store, data: RefinedTrialData[]) => boolean;
70
+ cond: (store: Store, data: TrialResult[]) => boolean;
69
71
  marker: string;
70
72
  }
71
73
  export interface UpdateStoreInstruction {
72
74
  type: 'UpdateStore';
73
- fun: (store: Store, data: RefinedTrialData[]) => Store;
75
+ fun: (store: Store, data: TrialResult[]) => Store;
74
76
  }
75
77
  export type UnifiedBytecodeInstruction =
76
78
  | ExecuteContentInstruction
@@ -95,16 +97,16 @@ export function compileTimeline(timeline: TimelineItem[]): {
95
97
 
96
98
  function adaptCondition(
97
99
  userCondition: ConditionalFunction,
98
- ): (store: Store, data: RefinedTrialData[]) => boolean {
99
- return (runtimeStore: Store, runtimeData: RefinedTrialData[]): boolean => {
100
+ ): (store: Store, data: TrialResult[]) => boolean {
101
+ return (runtimeStore: Store, runtimeData: TrialResult[]): boolean => {
100
102
  return userCondition(runtimeData, runtimeStore);
101
103
  };
102
104
  }
103
105
 
104
106
  function adaptUpdate(
105
107
  userUpdateFunction: StoreUpdateFunction,
106
- ): (store: Store, data: RefinedTrialData[]) => Store {
107
- return (runtimeStore: Store, runtimeData: RefinedTrialData[]): Store => {
108
+ ): (store: Store, data: TrialResult[]) => Store {
109
+ return (runtimeStore: Store, runtimeData: TrialResult[]): Store => {
108
110
  const updates = userUpdateFunction(runtimeData, runtimeStore);
109
111
  if (typeof updates === 'object' && updates !== null) {
110
112
  return {
@@ -215,7 +217,7 @@ export function compileTimeline(timeline: TimelineItem[]): {
215
217
  export function applyMetadata<T extends Record<string, any>>(
216
218
  trialData: T,
217
219
  content: { metadata?: any; nestMetadata?: boolean },
218
- data: RefinedTrialData[],
220
+ data: TrialResult[],
219
221
  store: Store,
220
222
  ): T {
221
223
  const metadata = typeof content.metadata === 'function' ? content.metadata(data, store) : content.metadata;
@@ -228,7 +230,7 @@ export function advanceToNextContent(
228
230
  bytecode: { instructions: UnifiedBytecodeInstruction[]; markers: Record<string, number> },
229
231
  fromPointer: number,
230
232
  getStore: () => Store,
231
- getData: () => RefinedTrialData[],
233
+ getData: () => TrialResult[],
232
234
  onUpdateStore: (newStore: Store) => void,
233
235
  ): number {
234
236
  let pointer = fromPointer;
@@ -24,6 +24,8 @@ export interface TrialData {
24
24
  trialNumber: number;
25
25
  type: string;
26
26
  name: string;
27
+ /** Populated from the timeline item's csv field. Overrides the component type's default CSV target from the flattener registry. */
28
+ csv?: string | string[];
27
29
  responseData: any;
28
30
  start: number;
29
31
  end: number;
@@ -68,13 +70,14 @@ export function getParam<T extends ParamType>(
68
70
  defaultValue: ParamValue<T>,
69
71
  type: T = 'string' as T,
70
72
  description?: string,
73
+ uiDefault?: string,
71
74
  ): ParamValue<T> {
72
75
  let registryEntry = sharedRegistry.find((p) => p.name === name);
73
76
 
74
77
  if (!registryEntry) {
75
78
  registryEntry = {
76
79
  name,
77
- defaultValue,
80
+ defaultValue: uiDefault !== undefined ? uiDefault : defaultValue,
78
81
  type,
79
82
  description,
80
83
  value: undefined,
@@ -4,7 +4,7 @@ import {
4
4
  compileTimeline,
5
5
  advanceToNextContent,
6
6
  applyMetadata,
7
- RefinedTrialData,
7
+ TrialResult,
8
8
  ComponentResultData,
9
9
  TimelineItem,
10
10
  Store,
@@ -23,7 +23,7 @@ export type SimulatorResult = {
23
23
  export type SimulateFunction = (
24
24
  trialProps: Record<string, any>,
25
25
  experimentState: {
26
- data: RefinedTrialData[];
26
+ data: TrialResult[];
27
27
  store: Store;
28
28
  },
29
29
  simulators: Record<string, any>,
@@ -55,7 +55,7 @@ export const noopSimulate: SimulateFunction = (_trialProps, _experimentState, _s
55
55
  participantState: participant,
56
56
  });
57
57
 
58
- export function resolveSimulation(content: any, data: RefinedTrialData[], store: Store) {
58
+ export function resolveSimulation(content: any, data: TrialResult[], store: Store) {
59
59
  const trialProps =
60
60
  typeof content.props === 'function' ? content.props(data, store) : content.props || {};
61
61
  const registration = simulationRegistry[content.type];
@@ -80,12 +80,12 @@ export function getInitialParticipant() { return _initialParticipant; }
80
80
  export async function simulateParticipant(
81
81
  timeline: TimelineItem[],
82
82
  participant: ParticipantState,
83
- ): Promise<RefinedTrialData[]> {
83
+ ): Promise<TrialResult[]> {
84
84
  _initialParticipant = { ...participant };
85
85
  let currentParticipantState = { ...participant };
86
86
  const bytecode = compileTimeline(timeline);
87
87
  let store: Store = {};
88
- const data: RefinedTrialData[] = [
88
+ const data: TrialResult[] = [
89
89
  {
90
90
  index: -1,
91
91
  trialNumber: -1,
@@ -138,6 +138,7 @@ export async function simulateParticipant(
138
138
  duration,
139
139
  type: content.type,
140
140
  name: content.name ?? '',
141
+ ...(content.csv !== undefined ? { csv: content.csv } : {}),
141
142
  responseData: result.responseData,
142
143
  };
143
144