@adriansteffan/reactive 0.0.42 → 0.0.44

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 (37) hide show
  1. package/.claude/settings.local.json +11 -2
  2. package/README.md +106 -3
  3. package/dist/{mod-UqYdghJl.js → mod-D6DlS3ur.js} +6483 -6120
  4. package/dist/mod.d.ts +54 -2
  5. package/dist/reactive.es.js +42 -33
  6. package/dist/reactive.umd.js +38 -36
  7. package/dist/style.css +1 -1
  8. package/dist/{web-pL-YTTVv.js → web-D7VcCd-t.js} +1 -1
  9. package/dist/{web-eGzX65_f.js → web-o3I0sgwu.js} +1 -1
  10. package/package.json +1 -1
  11. package/src/components/canvasblock.tsx +112 -70
  12. package/src/components/checkdevice.tsx +15 -0
  13. package/src/components/enterfullscreen.tsx +5 -3
  14. package/src/components/exitfullscreen.tsx +4 -1
  15. package/src/components/experimentprovider.tsx +7 -2
  16. package/src/components/experimentrunner.tsx +66 -52
  17. package/src/components/microphonecheck.tsx +3 -0
  18. package/src/components/mobilefilepermission.tsx +3 -0
  19. package/src/components/plaininput.tsx +17 -0
  20. package/src/components/prolificending.tsx +3 -0
  21. package/src/components/quest.tsx +58 -8
  22. package/src/components/storeui.tsx +15 -11
  23. package/src/components/text.tsx +11 -0
  24. package/src/components/upload.tsx +56 -271
  25. package/src/mod.tsx +1 -0
  26. package/src/utils/bytecode.ts +50 -0
  27. package/src/utils/simulation.ts +268 -0
  28. package/src/utils/upload.ts +299 -0
  29. package/template/README.md +59 -0
  30. package/template/backend/src/backend.ts +1 -0
  31. package/template/package.json +2 -0
  32. package/template/simulate.ts +15 -0
  33. package/template/src/Experiment.tsx +58 -5
  34. package/template/src/main.tsx +1 -1
  35. package/template/tsconfig.json +2 -3
  36. package/tsconfig.json +1 -0
  37. package/vite.config.ts +1 -1
@@ -1,12 +1,15 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { useState } from 'react';
3
- import { ExperimentRunner, BaseComponentProps, ExperimentConfig } from '@adriansteffan/reactive';
2
+ import { useState, useRef } from 'react';
3
+ import { ExperimentRunner, BaseComponentProps, ExperimentConfig, registerSimulation } from '@adriansteffan/reactive';
4
4
 
5
5
 
6
6
  const config: ExperimentConfig = { showProgressBar: true };
7
7
 
8
+ // --- Custom Components ---
9
+
8
10
  const CustomTrial = ({ next, maxCount }: BaseComponentProps & { maxCount: number }) => {
9
11
  const [count, setCount] = useState(0);
12
+ const startTime = useRef(performance.now());
10
13
 
11
14
  return (
12
15
  <>
@@ -20,7 +23,7 @@ const CustomTrial = ({ next, maxCount }: BaseComponentProps & { maxCount: number
20
23
  onClick={() => {
21
24
  setCount(count + 1);
22
25
  if (count + 1 === maxCount) {
23
- next({});
26
+ next({ totalTime: performance.now() - startTime.current, clicks: maxCount });
24
27
  }
25
28
  }}
26
29
  className='mt-4 px-4 py-2 bg-blue-500 text-white rounded-sm hover:bg-blue-600 transition-colors'
@@ -31,6 +34,24 @@ const CustomTrial = ({ next, maxCount }: BaseComponentProps & { maxCount: number
31
34
  );
32
35
  };
33
36
 
37
+ // Register a simulation for the custom trial.
38
+ // The decision function determines how fast the participant clicks.
39
+ // The simulate function uses the trial logic (clicking maxCount times) to produce response data.
40
+ registerSimulation('CustomTrial', (trialProps, _experimentState, simulators, participant) => {
41
+ let totalTime = 0;
42
+ for (let i = 0; i < (trialProps.maxCount || 1); i++) {
43
+ const result = simulators.click(trialProps, participant);
44
+ participant = result.participantState;
45
+ totalTime += result.value;
46
+ }
47
+ return { responseData: { totalTime, clicks: trialProps.maxCount }, participantState: participant, duration: totalTime };
48
+ }, {
49
+ click: (_trialProps: any, participant: any) => ({
50
+ value: 200 + Math.random() * 500,
51
+ participantState: participant,
52
+ }),
53
+ });
54
+
34
55
  const CustomQuestion = () => {
35
56
  return (
36
57
  <>
@@ -39,7 +60,9 @@ const CustomQuestion = () => {
39
60
  );
40
61
  };
41
62
 
42
- const experiment = [
63
+ // --- Timeline ---
64
+
65
+ export const experiment = [
43
66
  {
44
67
  name: 'introtext',
45
68
  type: 'Text',
@@ -57,9 +80,25 @@ const experiment = [
57
80
  ),
58
81
  },
59
82
  },
83
+ {
84
+ name: 'nickname',
85
+ type: 'PlainInput',
86
+ props: {
87
+ content: <p>What is your nickname?</p>,
88
+ buttonText: 'Submit',
89
+ placeholder: 'Enter your nickname',
90
+ },
91
+ simulators: {
92
+ respond: (_trialProps: any, participant: any) => ({
93
+ value: participant.nickname,
94
+ participantState: participant,
95
+ }),
96
+ },
97
+ },
60
98
  {
61
99
  name: 'customtrial',
62
100
  type: 'CustomTrial',
101
+ simulate: true,
63
102
  props: {
64
103
  maxCount: 5,
65
104
  },
@@ -115,6 +154,20 @@ export default function Experiment() {
115
154
  timeline={experiment}
116
155
  components={{CustomTrial}}
117
156
  questions={{CustomQuestion}}
157
+ hybridParticipant={{ id: 0, nickname: 'test' }}
118
158
  />
119
159
  );
120
- }
160
+ }
161
+
162
+ // --- Simulation config ---
163
+ // Define how simulated participants are generated.
164
+ // Each participant is an object whose properties are available in simulator decision functions.
165
+ export const simulationConfig = {
166
+ participants: {
167
+ generator: (i: number) => ({
168
+ id: i,
169
+ nickname: `participant_${i}`,
170
+ }),
171
+ count: 10,
172
+ },
173
+ };
@@ -6,7 +6,7 @@ import { ExperimentProvider } from "@adriansteffan/reactive";
6
6
 
7
7
  ReactDOM.createRoot(document.getElementById("root")!).render(
8
8
  <React.StrictMode>
9
- <ExperimentProvider disableSettings={import.meta.env.VITE_DISABLE_SETTINGS}>
9
+ <ExperimentProvider disableSettings={import.meta.env.VITE_DISABLE_SETTINGS} disableHybridSimulation={!!import.meta.env.VITE_DISABLE_HYBRID_SIMULATION}>
10
10
  <Experiment />
11
11
  </ExperimentProvider>
12
12
  </React.StrictMode>
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "noImplicitAny": false,
4
- "target": "ES5",
4
+ "target": "ES2020",
5
5
  "useDefineForClassFields": true,
6
- "lib": ["ES2020", "DOM", "DOM.Iterable", "ES2015", "ES2016", "ES2017"],
6
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
7
7
  "module": "ESNext",
8
- "downlevelIteration": true,
9
8
  "skipLibCheck": true,
10
9
 
11
10
  /* Bundler mode */
package/tsconfig.json CHANGED
@@ -4,6 +4,7 @@
4
4
  "target": "ES2020",
5
5
  "useDefineForClassFields": true,
6
6
  "lib": ["ES2020", "DOM", "DOM.Iterable"],
7
+ "types": ["node"],
7
8
  "module": "ESNext",
8
9
  "skipLibCheck": true,
9
10
  "declaration": true,
package/vite.config.ts CHANGED
@@ -26,7 +26,7 @@ export default defineConfig(() => {
26
26
  fileName: (format: string) => `reactive.${format}.js`,
27
27
  },
28
28
  rollupOptions: {
29
- external: ['react', 'react-dom'],
29
+ external: ['react', 'react-dom', 'child_process', 'os'],
30
30
  output: {
31
31
  globals: {
32
32
  react: 'React',