@adriansteffan/reactive 0.0.26 → 0.0.27
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.
- package/dist/{mod-Dqf5zajq.js → mod-CbGhKi2f.js} +11238 -10012
- package/dist/mod.d.ts +187 -49
- package/dist/reactive.es.js +26 -16
- package/dist/reactive.umd.js +37 -39
- package/dist/style.css +1 -1
- package/dist/{web-CnAMKrLX.js → web-BFGLx41c.js} +1 -1
- package/dist/{web-6wmUWZwq.js → web-DOFokKz7.js} +1 -1
- package/package.json +7 -2
- package/src/components/canvasblock.tsx +519 -0
- package/src/components/checkdevice.tsx +158 -0
- package/src/components/enterfullscreen.tsx +114 -31
- package/src/components/exitfullscreen.tsx +98 -21
- package/src/components/experimentprovider.tsx +34 -20
- package/src/components/experimentrunner.tsx +387 -0
- package/src/components/index.ts +13 -0
- package/src/components/mobilefilepermission.tsx +12 -19
- package/src/components/plaininput.tsx +7 -8
- package/src/components/prolificending.tsx +10 -4
- package/src/components/quest.tsx +27 -31
- package/src/components/settingsscreen.tsx +770 -0
- package/src/components/text.tsx +48 -3
- package/src/components/upload.tsx +218 -47
- package/src/mod.tsx +3 -12
- package/src/types/array.d.ts +6 -0
- package/src/utils/array.ts +79 -0
- package/src/utils/bytecode.ts +178 -0
- package/src/utils/common.ts +170 -39
- package/template/.env.template +2 -1
- package/template/src/{App.tsx → Experiment.tsx} +4 -4
- package/template/src/main.tsx +4 -4
- package/template/tsconfig.json +1 -0
- package/src/components/experiment.tsx +0 -371
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { BaseComponentProps } from '../mod';
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
|
|
4
|
+
interface DeviceInfo {
|
|
5
|
+
windowWidth: number;
|
|
6
|
+
windowHeight: number;
|
|
7
|
+
screenWidth: number;
|
|
8
|
+
screenHeight: number;
|
|
9
|
+
browser: string;
|
|
10
|
+
browserVersion: string;
|
|
11
|
+
isMobile: boolean;
|
|
12
|
+
operatingSystem: string;
|
|
13
|
+
hasWebAudio: boolean;
|
|
14
|
+
hasFullscreen: boolean;
|
|
15
|
+
hasWebcam: boolean;
|
|
16
|
+
hasMicrophone: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function CheckDevice({
|
|
20
|
+
check,
|
|
21
|
+
content = <div>Your device doesn't meet the requirements for this experiment.</div>,
|
|
22
|
+
data,
|
|
23
|
+
store,
|
|
24
|
+
updateStore,
|
|
25
|
+
next,
|
|
26
|
+
}: {
|
|
27
|
+
check: (deviceInfo: DeviceInfo, data: any, store: any) => boolean;
|
|
28
|
+
content?: React.ReactNode;
|
|
29
|
+
} & BaseComponentProps) {
|
|
30
|
+
const [showContent, setShowContent] = useState<boolean>(false);
|
|
31
|
+
|
|
32
|
+
const hasNavigatedRef = useRef(false);
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (hasNavigatedRef.current) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const gatherDeviceInfo = async () => {
|
|
40
|
+
const windowWidth = window.innerWidth;
|
|
41
|
+
const windowHeight = window.innerHeight;
|
|
42
|
+
|
|
43
|
+
const screenWidth = window.screen.width;
|
|
44
|
+
const screenHeight = window.screen.height;
|
|
45
|
+
|
|
46
|
+
const userAgent = navigator.userAgent;
|
|
47
|
+
let browser = 'Unknown';
|
|
48
|
+
let browserVersion = 'Unknown';
|
|
49
|
+
|
|
50
|
+
if (userAgent.indexOf('Chrome') > -1) {
|
|
51
|
+
browser = 'Chrome';
|
|
52
|
+
const match = userAgent.match(/Chrome\/(\d+\.\d+)/);
|
|
53
|
+
browserVersion = match ? match[1] : 'Unknown';
|
|
54
|
+
} else if (userAgent.indexOf('Firefox') > -1) {
|
|
55
|
+
browser = 'Firefox';
|
|
56
|
+
const match = userAgent.match(/Firefox\/(\d+\.\d+)/);
|
|
57
|
+
browserVersion = match ? match[1] : 'Unknown';
|
|
58
|
+
} else if (userAgent.indexOf('Safari') > -1) {
|
|
59
|
+
browser = 'Safari';
|
|
60
|
+
const match = userAgent.match(/Version\/(\d+\.\d+)/);
|
|
61
|
+
browserVersion = match ? match[1] : 'Unknown';
|
|
62
|
+
} else if (userAgent.indexOf('Edge') > -1) {
|
|
63
|
+
browser = 'Edge';
|
|
64
|
+
const match = userAgent.match(/Edge\/(\d+\.\d+)/);
|
|
65
|
+
browserVersion = match ? match[1] : 'Unknown';
|
|
66
|
+
} else if (userAgent.indexOf('MSIE') > -1 || userAgent.indexOf('Trident/') > -1) {
|
|
67
|
+
browser = 'Internet Explorer';
|
|
68
|
+
const match = userAgent.match(/(?:MSIE |rv:)(\d+\.\d+)/);
|
|
69
|
+
browserVersion = match ? match[1] : 'Unknown';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
73
|
+
userAgent,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
let operatingSystem = 'Unknown';
|
|
77
|
+
if (/Windows/.test(userAgent)) {
|
|
78
|
+
operatingSystem = 'Windows';
|
|
79
|
+
} else if (/Macintosh|Mac OS X/.test(userAgent)) {
|
|
80
|
+
operatingSystem = 'MacOS';
|
|
81
|
+
} else if (/Linux/.test(userAgent)) {
|
|
82
|
+
operatingSystem = 'Linux';
|
|
83
|
+
} else if (/Android/.test(userAgent)) {
|
|
84
|
+
operatingSystem = 'Android';
|
|
85
|
+
} else if (/iOS|iPhone|iPad|iPod/.test(userAgent)) {
|
|
86
|
+
operatingSystem = 'iOS';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const hasWebAudio = !!(
|
|
90
|
+
window.AudioContext ||
|
|
91
|
+
(window as any).webkitAudioContext ||
|
|
92
|
+
(window as any).mozAudioContext ||
|
|
93
|
+
(window as any).oAudioContext ||
|
|
94
|
+
(window as any).msAudioContext
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const hasFullscreen = !!(
|
|
98
|
+
document.exitFullscreen ||
|
|
99
|
+
(document as any).webkitExitFullscreen ||
|
|
100
|
+
(document as any).mozCancelFullScreen ||
|
|
101
|
+
(document as any).msExitFullscreen ||
|
|
102
|
+
document.fullscreenEnabled ||
|
|
103
|
+
(document as any).webkitFullscreenEnabled ||
|
|
104
|
+
(document as any).mozFullScreenEnabled ||
|
|
105
|
+
(document as any).msFullscreenEnabled
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
let hasWebcam = false;
|
|
109
|
+
let hasMicrophone = false;
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
113
|
+
hasWebcam = devices.some((device) => device.kind === 'videoinput');
|
|
114
|
+
hasMicrophone = devices.some((device) => device.kind === 'audioinput');
|
|
115
|
+
} catch (error) {
|
|
116
|
+
console.error('Error checking media devices:', error);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const deviceInfo: DeviceInfo = {
|
|
120
|
+
windowWidth,
|
|
121
|
+
windowHeight,
|
|
122
|
+
screenWidth,
|
|
123
|
+
screenHeight,
|
|
124
|
+
browser,
|
|
125
|
+
browserVersion,
|
|
126
|
+
isMobile,
|
|
127
|
+
operatingSystem,
|
|
128
|
+
hasWebAudio,
|
|
129
|
+
hasFullscreen,
|
|
130
|
+
hasWebcam,
|
|
131
|
+
hasMicrophone,
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
updateStore({ _reactiveDeviceInfo: deviceInfo });
|
|
135
|
+
|
|
136
|
+
const checkResult = check ? check(deviceInfo, data, store) : true;
|
|
137
|
+
|
|
138
|
+
if (checkResult && !hasNavigatedRef.current) {
|
|
139
|
+
hasNavigatedRef.current = true;
|
|
140
|
+
next(deviceInfo);
|
|
141
|
+
} else {
|
|
142
|
+
setShowContent(true);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
gatherDeviceInfo();
|
|
147
|
+
}, [check, data, updateStore, next]);
|
|
148
|
+
|
|
149
|
+
return showContent ? (
|
|
150
|
+
<div className='max-w-prose mx-auto mt-20 mb-20 px-4'>
|
|
151
|
+
<article className='prose prose-2xl prose-slate text-xl prose-a:text-blue-600 prose-a:underline prose-h1:text-4xl prose-h1:mb-10 prose-h1:font-bold prose-p:mb-4 prose-strong:font-bold text-black leading-relaxed'>
|
|
152
|
+
{content}
|
|
153
|
+
</article>
|
|
154
|
+
</div>
|
|
155
|
+
) : null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export default CheckDevice;
|
|
@@ -1,52 +1,135 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import React, { useState, useCallback, useRef, useEffect } from 'react'; // Import useState
|
|
2
|
+
import { BaseComponentProps, getPlatform, isFullscreen } from '../utils/common';
|
|
2
3
|
import Text from '../components/text';
|
|
3
4
|
|
|
4
5
|
import { StatusBar } from '@capacitor/status-bar';
|
|
5
6
|
import { ImmersiveMode } from '@adriansteffan/immersive-mode';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
function enterFullscreen(element: any) {
|
|
9
|
-
|
|
10
|
-
// Android
|
|
11
|
-
StatusBar.hide();
|
|
12
|
-
ImmersiveMode.enable();
|
|
13
|
-
|
|
14
|
-
if (element.requestFullscreen) {
|
|
15
|
-
element.requestFullscreen();
|
|
16
|
-
} else if (element.mozRequestFullScreen) {
|
|
17
|
-
// Firefox
|
|
18
|
-
element.mozRequestFullScreen();
|
|
19
|
-
} else if (element.webkitRequestFullscreen) {
|
|
20
|
-
// Chrome, Safari and Opera
|
|
21
|
-
element.webkitRequestFullscreen();
|
|
22
|
-
} else if (element.msRequestFullscreen) {
|
|
23
|
-
// IE/Edge
|
|
24
|
-
element.msRequestFullscreen();
|
|
25
|
-
}
|
|
26
|
-
}
|
|
7
|
+
import { Capacitor } from '@capacitor/core';
|
|
27
8
|
|
|
28
9
|
export default function EnterFullscreen({
|
|
29
10
|
content,
|
|
30
11
|
buttonText,
|
|
31
12
|
next,
|
|
32
|
-
|
|
13
|
+
data,
|
|
14
|
+
updateStore,
|
|
15
|
+
delayMs = 0,
|
|
16
|
+
}: {
|
|
17
|
+
prolificCode?: string;
|
|
18
|
+
content?: React.ReactNode;
|
|
19
|
+
buttonText?: string;
|
|
20
|
+
delayMs?: number;
|
|
21
|
+
} & BaseComponentProps) {
|
|
33
22
|
const contentWrap = (
|
|
34
23
|
<div className='flex flex-col items-center'>
|
|
35
24
|
{!!content && content}
|
|
36
|
-
{!content &&
|
|
37
|
-
<p className=''>Please click the Button below to enter Fullscreen mode.</p>
|
|
38
|
-
)}
|
|
25
|
+
{!content && <p className=''>Please click the Button below to enter Fullscreen mode.</p>}
|
|
39
26
|
</div>
|
|
40
27
|
);
|
|
41
28
|
|
|
29
|
+
const [isWaiting, setIsWaiting] = useState(false);
|
|
30
|
+
const listenerFallbackActive = useRef(false);
|
|
31
|
+
const timeoutId = useRef<NodeJS.Timeout | null>(null);
|
|
32
|
+
|
|
33
|
+
const cancelPendingTimeout = useCallback(() => {
|
|
34
|
+
if (timeoutId.current) {
|
|
35
|
+
clearTimeout(timeoutId.current);
|
|
36
|
+
timeoutId.current = null;
|
|
37
|
+
}
|
|
38
|
+
}, []);
|
|
39
|
+
|
|
40
|
+
const removeListenersAndTimeout = useCallback(() => {
|
|
41
|
+
document.removeEventListener('fullscreenchange', handleFullscreenChangeForFallback);
|
|
42
|
+
document.removeEventListener('webkitfullscreenchange', handleFullscreenChangeForFallback);
|
|
43
|
+
document.removeEventListener('mozfullscreenchange', handleFullscreenChangeForFallback);
|
|
44
|
+
document.removeEventListener('MSFullscreenChange', handleFullscreenChangeForFallback);
|
|
45
|
+
cancelPendingTimeout();
|
|
46
|
+
listenerFallbackActive.current = false;
|
|
47
|
+
}, [cancelPendingTimeout]);
|
|
48
|
+
|
|
49
|
+
const proceedWithDelay = useCallback(() => {
|
|
50
|
+
cancelPendingTimeout();
|
|
51
|
+
setIsWaiting(true);
|
|
52
|
+
timeoutId.current = setTimeout(() => {
|
|
53
|
+
timeoutId.current = null;
|
|
54
|
+
|
|
55
|
+
next({});
|
|
56
|
+
}, delayMs);
|
|
57
|
+
}, [next, delayMs, cancelPendingTimeout]);
|
|
58
|
+
|
|
59
|
+
const handleFullscreenChangeForFallback = useCallback(() => {
|
|
60
|
+
if (!listenerFallbackActive.current) return;
|
|
61
|
+
const currentlyFullscreen = isFullscreen();
|
|
62
|
+
removeListenersAndTimeout();
|
|
63
|
+
if (currentlyFullscreen) {
|
|
64
|
+
proceedWithDelay();
|
|
65
|
+
} else {
|
|
66
|
+
setIsWaiting(false);
|
|
67
|
+
}
|
|
68
|
+
}, [proceedWithDelay, removeListenersAndTimeout]);
|
|
69
|
+
|
|
70
|
+
const addListenersForFallback = useCallback(() => {
|
|
71
|
+
removeListenersAndTimeout();
|
|
72
|
+
listenerFallbackActive.current = true;
|
|
73
|
+
document.addEventListener('fullscreenchange', handleFullscreenChangeForFallback);
|
|
74
|
+
document.addEventListener('webkitfullscreenchange', handleFullscreenChangeForFallback);
|
|
75
|
+
document.addEventListener('mozfullscreenchange', handleFullscreenChangeForFallback);
|
|
76
|
+
document.addEventListener('MSFullscreenChange', handleFullscreenChangeForFallback);
|
|
77
|
+
}, [handleFullscreenChangeForFallback, removeListenersAndTimeout]);
|
|
78
|
+
|
|
79
|
+
const handleEnterFullscreenClick = useCallback(async () => {
|
|
80
|
+
setIsWaiting(true);
|
|
81
|
+
removeListenersAndTimeout();
|
|
82
|
+
|
|
83
|
+
const element = document.documentElement;
|
|
84
|
+
|
|
85
|
+
if (getPlatform() === 'mobile' && Capacitor.getPlatform() === 'android') {
|
|
86
|
+
StatusBar.hide();
|
|
87
|
+
ImmersiveMode.enable();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (element.requestFullscreen) {
|
|
91
|
+
try {
|
|
92
|
+
await element.requestFullscreen();
|
|
93
|
+
proceedWithDelay();
|
|
94
|
+
return;
|
|
95
|
+
} catch (err) {
|
|
96
|
+
console.error("Fullscreen request failed:", err);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if ((element as any).mozRequestFullScreen) {
|
|
102
|
+
(element as any).mozRequestFullScreen();
|
|
103
|
+
addListenersForFallback();
|
|
104
|
+
} else if ((element as any).webkitRequestFullscreen) {
|
|
105
|
+
(element as any).webkitRequestFullscreen();
|
|
106
|
+
addListenersForFallback();
|
|
107
|
+
} else if ((element as any).msRequestFullscreen) {
|
|
108
|
+
(element as any).msRequestFullscreen();
|
|
109
|
+
addListenersForFallback();
|
|
110
|
+
} else {
|
|
111
|
+
console.warn('Fullscreen API is not supported by this browser.');
|
|
112
|
+
}
|
|
113
|
+
}, [proceedWithDelay, addListenersForFallback, removeListenersAndTimeout]);
|
|
114
|
+
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
return () => {
|
|
117
|
+
removeListenersAndTimeout();
|
|
118
|
+
};
|
|
119
|
+
}, [removeListenersAndTimeout]);
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
if (isWaiting) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
|
|
42
126
|
return (
|
|
43
127
|
<Text
|
|
128
|
+
data={data}
|
|
129
|
+
updateStore={updateStore}
|
|
44
130
|
content={contentWrap}
|
|
45
131
|
buttonText={buttonText ?? 'Enter Fullscreen Mode'}
|
|
46
|
-
next={
|
|
47
|
-
enterFullscreen(document.documentElement);
|
|
48
|
-
next({});
|
|
49
|
-
}}
|
|
132
|
+
next={handleEnterFullscreenClick}
|
|
50
133
|
/>
|
|
51
134
|
);
|
|
52
|
-
}
|
|
135
|
+
}
|
|
@@ -1,29 +1,106 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useCallback, useRef, useEffect } from 'react';
|
|
2
|
+
import { BaseComponentProps, getPlatform, isFullscreen } from '../utils/common';
|
|
3
3
|
import { StatusBar } from '@capacitor/status-bar';
|
|
4
4
|
import { ImmersiveMode } from '@adriansteffan/immersive-mode';
|
|
5
|
+
import { Capacitor } from '@capacitor/core';
|
|
5
6
|
|
|
6
|
-
function
|
|
7
|
+
export default function ExitFullscreen({
|
|
8
|
+
next,
|
|
9
|
+
delayMs = 0,
|
|
10
|
+
}: {
|
|
11
|
+
delayMs?: number;
|
|
12
|
+
} & BaseComponentProps) {
|
|
13
|
+
|
|
14
|
+
const listenerFallbackActive = useRef(false);
|
|
15
|
+
const timeoutId = useRef<NodeJS.Timeout | null>(null);
|
|
7
16
|
|
|
8
|
-
|
|
9
|
-
|
|
17
|
+
const cancelPendingTimeout = useCallback(() => {
|
|
18
|
+
if (timeoutId.current) {
|
|
19
|
+
clearTimeout(timeoutId.current);
|
|
20
|
+
timeoutId.current = null;
|
|
21
|
+
}
|
|
22
|
+
}, []);
|
|
23
|
+
|
|
24
|
+
const removeListenersAndTimeout = useCallback(() => {
|
|
25
|
+
document.removeEventListener('fullscreenchange', handleFullscreenChangeForFallback);
|
|
26
|
+
document.removeEventListener('webkitfullscreenchange', handleFullscreenChangeForFallback);
|
|
27
|
+
document.removeEventListener('mozfullscreenchange', handleFullscreenChangeForFallback);
|
|
28
|
+
document.removeEventListener('MSFullscreenChange', handleFullscreenChangeForFallback);
|
|
29
|
+
cancelPendingTimeout();
|
|
30
|
+
listenerFallbackActive.current = false;
|
|
31
|
+
}, [cancelPendingTimeout]);
|
|
32
|
+
|
|
33
|
+
const proceedWithDelay = useCallback(() => {
|
|
34
|
+
cancelPendingTimeout();
|
|
35
|
+
timeoutId.current = setTimeout(() => {
|
|
36
|
+
timeoutId.current = null;
|
|
37
|
+
next({});
|
|
38
|
+
}, delayMs);
|
|
39
|
+
}, [next, delayMs, cancelPendingTimeout]);
|
|
40
|
+
|
|
41
|
+
const handleFullscreenChangeForFallback = useCallback(() => {
|
|
42
|
+
if (!listenerFallbackActive.current) return;
|
|
43
|
+
const currentlyFullscreen = isFullscreen();
|
|
44
|
+
removeListenersAndTimeout();
|
|
45
|
+
if (!currentlyFullscreen) {
|
|
46
|
+
proceedWithDelay();
|
|
47
|
+
}
|
|
48
|
+
}, [proceedWithDelay, removeListenersAndTimeout]);
|
|
10
49
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
}
|
|
50
|
+
const addListenersForFallback = useCallback(() => {
|
|
51
|
+
removeListenersAndTimeout();
|
|
52
|
+
listenerFallbackActive.current = true;
|
|
53
|
+
document.addEventListener('fullscreenchange', handleFullscreenChangeForFallback);
|
|
54
|
+
document.addEventListener('webkitfullscreenchange', handleFullscreenChangeForFallback);
|
|
55
|
+
document.addEventListener('mozfullscreenchange', handleFullscreenChangeForFallback);
|
|
56
|
+
document.addEventListener('MSFullscreenChange', handleFullscreenChangeForFallback);
|
|
57
|
+
}, [handleFullscreenChangeForFallback, removeListenersAndTimeout]);
|
|
21
58
|
|
|
22
|
-
export default function ExitFullscreen({ next }: BaseComponentProps) {
|
|
23
59
|
useEffect(() => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
60
|
+
const performExitFullscreen = async () => {
|
|
61
|
+
if (!isFullscreen()) {
|
|
62
|
+
next({});
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (getPlatform() === 'mobile' && Capacitor.getPlatform() === 'android') {
|
|
67
|
+
StatusBar.show();
|
|
68
|
+
ImmersiveMode.disable();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (document.exitFullscreen) {
|
|
72
|
+
try {
|
|
73
|
+
await document.exitFullscreen();
|
|
74
|
+
proceedWithDelay();
|
|
75
|
+
return;
|
|
76
|
+
} catch (err) {
|
|
77
|
+
console.error("Exiting fullscreen failed:", err);
|
|
78
|
+
next({});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if ((document as any).mozCancelFullScreen) {
|
|
84
|
+
(document as any).mozCancelFullScreen();
|
|
85
|
+
addListenersForFallback();
|
|
86
|
+
} else if ((document as any).webkitExitFullscreen) {
|
|
87
|
+
(document as any).webkitExitFullscreen();
|
|
88
|
+
addListenersForFallback();
|
|
89
|
+
} else if ((document as any).msExitFullscreen) {
|
|
90
|
+
(document as any).msExitFullscreen();
|
|
91
|
+
addListenersForFallback();
|
|
92
|
+
} else {
|
|
93
|
+
console.warn('Fullscreen API is not supported by this browser.');
|
|
94
|
+
next({});
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
performExitFullscreen();
|
|
99
|
+
|
|
100
|
+
return () => {
|
|
101
|
+
removeListenersAndTimeout();
|
|
102
|
+
};
|
|
103
|
+
}, [proceedWithDelay, addListenersForFallback, removeListenersAndTimeout]);
|
|
27
104
|
|
|
28
|
-
return
|
|
29
|
-
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
@@ -4,25 +4,39 @@ import { ToastContainer } from 'react-toastify';
|
|
|
4
4
|
const queryClient = new QueryClient();
|
|
5
5
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
6
6
|
import { ReactNode } from 'react';
|
|
7
|
+
import { SettingsScreen } from './settingsscreen';
|
|
8
|
+
import { Param } from '../utils/common';
|
|
7
9
|
|
|
8
|
-
export default function ExperimentProvider({children}: {children: ReactNode}){
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
'
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
10
|
+
export default function ExperimentProvider({ children, disableSettings }: { children: ReactNode, disableSettings?: boolean }) {
|
|
11
|
+
|
|
12
|
+
if (window.location.pathname.endsWith('/settings') && !disableSettings) {
|
|
13
|
+
return (
|
|
14
|
+
<SettingsScreen
|
|
15
|
+
paramRegistry={Param.getRegistry()}
|
|
16
|
+
timelineRepresentation={Param.getTimelineRepresentation()}
|
|
17
|
+
/>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<QueryClientProvider client={queryClient}>
|
|
23
|
+
{children}
|
|
24
|
+
<ToastContainer
|
|
25
|
+
position='top-center'
|
|
26
|
+
autoClose={3000}
|
|
27
|
+
hideProgressBar
|
|
28
|
+
newestOnTop={false}
|
|
29
|
+
closeOnClick
|
|
30
|
+
rtl={false}
|
|
31
|
+
pauseOnFocusLoss
|
|
32
|
+
draggable={false}
|
|
33
|
+
pauseOnHover
|
|
34
|
+
theme='light'
|
|
35
|
+
toastClassName={() =>
|
|
36
|
+
'relative flex p-4 min-h-10 rounded-none justify-between overflow-hidden cursor-pointer border-2 border-black shadow-[2px_2px_0px_rgba(0,0,0,1)] bg-white'
|
|
37
|
+
}
|
|
38
|
+
bodyClassName='text-black font-sans'
|
|
39
|
+
/>
|
|
40
|
+
</QueryClientProvider>
|
|
41
|
+
);
|
|
28
42
|
}
|