@empirica/core
Version:
Empirica Core
873 lines (858 loc) • 29.3 kB
JavaScript
import {
ErrNotConnected,
TajribaConnection,
bs,
bsu,
subscribeAsync
} from "./chunk-WGYNSNUC.js";
import {
TajribaProvider,
createNewParticipant,
isDevelopment
} from "./chunk-6SEN3GDC.js";
import {
Globals
} from "./chunk-2TT3WJZY.js";
import {
error,
warn
} from "./chunk-TIKLWCJI.js";
// src/player/context.ts
import { BehaviorSubject as BehaviorSubject2, Subject } from "rxjs";
// src/player/connection.ts
import { merge } from "rxjs";
var ParticipantConnection = class {
constructor(taj, sessions, resetSession) {
this.resetSession = resetSession;
this._tajribaPart = bsu();
this._connected = bs(false);
this._connecting = bs(false);
this._stopped = bs(false);
let session;
let connected = false;
this._sessionsSub = subscribeAsync(
merge(taj.connected, sessions),
async (sessionOrConnected) => {
if (typeof sessionOrConnected === "boolean") {
connected = sessionOrConnected;
} else {
session = sessionOrConnected;
}
if (!session || !connected) {
return;
}
if (this._connected.getValue() || this._connecting.getValue()) {
return;
}
this._connecting.next(true);
try {
const tajPart = await taj.sessionParticipant(
session.token,
session.participant
);
this._tajribaPart.next(tajPart);
if (tajPart.connected) {
this._connected.next(true);
this._connecting.next(false);
}
tajPart.on("connected", () => {
if (!this._connected.getValue()) {
this._connected.next(true);
this._connecting.next(false);
}
});
tajPart.on("disconnected", () => {
if (this._connected.getValue()) {
this._connected.next(false);
}
if (this._connecting.getValue()) {
this._connecting.next(false);
}
});
tajPart.on("error", (err) => {
error("connection error", err);
});
tajPart.on("accessDenied", () => {
if (this._connected.getValue()) {
this._connected.next(false);
}
if (this._connecting.getValue()) {
this._connecting.next(false);
}
console.log(
"accessDenied",
session?.participant.id,
session?.token
);
this.resetSession();
});
} catch (err) {
if (err !== ErrNotConnected) {
error("new conn error", err);
this.resetSession();
}
}
}
);
}
stop() {
if (this._stopped.getValue()) {
return;
}
const taj = this._tajribaPart.getValue();
if (taj) {
taj.removeAllListeners("connected");
taj.removeAllListeners("disconnected");
taj.stop();
this._tajribaPart.next(void 0);
}
this._sessionsSub.unsubscribe();
this._connecting.next(false);
this._connected.next(false);
this._stopped.next(true);
}
get connecting() {
return this._connecting;
}
get connected() {
return this._connected;
}
get stopped() {
return this._stopped;
}
get participant() {
return this._tajribaPart;
}
};
var MemStorage = class {
static clear() {
this.vals = {};
}
static getItem(key) {
return this.vals[key];
}
static removeItem(key) {
delete this.vals[key];
}
static setItem(key, value) {
this.vals[key] = value;
}
};
MemStorage.vals = {};
var isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined";
var storage;
if (isBrowser) {
storage = window.localStorage;
}
var _ParticipantSession = class {
constructor(ns, resetSession) {
this.ns = ns;
this._token = this.strg.getItem(this.tokenKey) || void 0;
const participantStr = this.strg.getItem(this.partKey) || void 0;
if (participantStr) {
this._participant = JSON.parse(participantStr);
}
const sess = this.calcSession();
this._sessions = bsu(sess);
resetSession.subscribe({
next: () => {
this.clearSession();
}
});
}
get sessions() {
return this._sessions;
}
get session() {
return this._sessions.getValue();
}
get token() {
return this._token;
}
get participant() {
return this._participant;
}
get tokenKey() {
return `${_ParticipantSession.tokenKey}:${this.ns}`;
}
get partKey() {
return `${_ParticipantSession.partKey}:${this.ns}`;
}
updateSession(token, participant) {
this.strg.setItem(this.tokenKey, token);
this.strg.setItem(this.partKey, JSON.stringify(participant));
this._token = token;
this._participant = participant;
this._sessions.next(this.calcSession());
}
clearSession() {
delete this._token;
delete this._participant;
this.strg.removeItem(this.tokenKey);
this.strg.removeItem(this.partKey);
this._sessions.next(void 0);
}
calcSession() {
if (this._token && this._participant) {
return {
token: this._token,
participant: this._participant
};
}
return void 0;
}
get strg() {
return _ParticipantSession.storage;
}
};
var ParticipantSession = _ParticipantSession;
ParticipantSession.tokenKey = "empirica:token";
ParticipantSession.partKey = "empirica:participant";
ParticipantSession.storage = storage;
// src/player/context.ts
var ParticipantContext = class {
constructor(url, ns) {
/** @internal */
this.provider = bsu();
/** @internal */
this.globals = bsu();
this.tajriba = new TajribaConnection(url);
this.resetSession = new Subject();
this.session = new ParticipantSession(ns, this.resetSession);
this.participant = new ParticipantConnection(
this.tajriba,
this.session.sessions,
this.resetSession.next.bind(this.resetSession)
);
subscribeAsync(this.participant.connected, async (connected) => {
const part = this.participant.participant.getValue();
if (connected && part) {
if (!this.provider.getValue()) {
this.provider.next(
new TajribaProvider(
part.changes(),
this.tajriba.tajriba.globalAttributes(),
part.setAttributes.bind(part)
)
);
}
} else {
const provider = this.provider.getValue();
if (provider) {
this.provider.next(void 0);
}
}
});
subscribeAsync(this.tajriba.connected, async (connected) => {
if (connected) {
this.globals.next(new Globals(this.tajriba.tajriba.globalAttributes()));
} else {
const glob = this.globals.getValue();
if (glob) {
this.globals.next(void 0);
}
}
});
}
get connecting() {
return this.participant.connecting;
}
get connected() {
return this.participant.connected;
}
async register(playerIdentifier) {
if (!this.tajriba.connected.getValue()) {
throw ErrNotConnected;
}
const [token, participant] = await this.tajriba.tajriba.registerParticipant(
playerIdentifier
);
if (!token) {
throw new Error("invalid registration");
}
this.session.updateSession(token, participant);
}
stop() {
this.tajriba.stop();
this.participant.stop();
}
};
var ParticipantMode = class {
constructor(participant, provider, modeFunc) {
this._mode = new BehaviorSubject2(void 0);
subscribeAsync(provider, async (provider2) => {
const id = participant.getValue()?.id;
if (id && provider2 && this._mode.getValue()) {
warn("spurious provider condition");
window.location.reload();
}
if (id && provider2) {
this._mode.next(modeFunc(id, provider2));
} else {
const mode = this._mode.getValue();
if (mode) {
this._mode.next(void 0);
}
}
});
}
get mode() {
return this._mode;
}
};
var ParticipantModeContext = class extends ParticipantContext {
constructor(url, ns, modeFunc) {
super(url, ns);
this._mode = new ParticipantMode(
this.participant.participant,
this.provider,
modeFunc
);
}
get mode() {
return this._mode.mode;
}
};
// src/player/react/Consent.tsx
import React from "react";
var defaultTitle = "Do you consent to participate in this experiment?";
var defaultText = `This experiment is part of a scientific project. Your decision
to participate in this experiment is entirely voluntary. There
are no known or anticipated risks to participating in this
experiment. There is no way for us to identify you. The only
information we will have, in addition to your responses, is
the timestamps of your interactions with our site. The results
of our research may be presented at scientific meetings or
published in scientific journals. Clicking on the "I AGREE"
button indicates that you are at least 18 years of age, and
agree to participate voluntary.`;
var defaultButtonText = "I AGREE";
function Consent({
title = defaultTitle,
text = defaultText,
buttonText = defaultButtonText,
onConsent
}) {
return /* @__PURE__ */ React.createElement(
"div",
{
className: "relative h-full z-10 overflow-y-auto",
"aria-labelledby": "modal-title",
role: "dialog",
"aria-modal": "true"
},
/* @__PURE__ */ React.createElement("div", { className: "flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" }, /* @__PURE__ */ React.createElement(
"div",
{
className: "absolute inset-0 bg-gray-500 bg-opacity-75 transition-opacity",
"aria-hidden": "true"
}
), /* @__PURE__ */ React.createElement(
"span",
{
className: "hidden sm:inline-block sm:align-middle sm:h-screen",
"aria-hidden": "true"
},
"\u200B"
), /* @__PURE__ */ React.createElement("div", { className: "inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { className: "mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-green-100" }, /* @__PURE__ */ React.createElement(
"svg",
{
className: "h-6 w-6 text-green-600",
xmlns: "http://www.w3.org/2000/svg",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
"aria-hidden": "true"
},
/* @__PURE__ */ React.createElement(
"path",
{
strokeLinecap: "round",
strokeLinejoin: "round",
strokeWidth: "2",
d: "M5 13l4 4L19 7"
}
)
)), /* @__PURE__ */ React.createElement("div", { className: "mt-3 sm:mt-5" }, /* @__PURE__ */ React.createElement(
"h3",
{
className: "text-lg text-center leading-6 font-medium text-gray-900",
id: "modal-title"
},
title
), /* @__PURE__ */ React.createElement("div", { className: "mt-2" }, /* @__PURE__ */ React.createElement("div", { className: "text-sm text-gray-500 text-justify" }, text)))), /* @__PURE__ */ React.createElement("div", { className: "mt-5 sm:mt-6" }, /* @__PURE__ */ React.createElement(
"button",
{
type: "button",
className: "inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 bg-empirica-600 text-base font-medium text-white hover:bg-empirica-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-empirica-500 sm:text-sm",
onClick: onConsent
},
buttonText
))))
);
}
// src/player/react/EmpiricaMenu.tsx
import React4 from "react";
// src/player/react/Logo.tsx
import React2 from "react";
function Logo() {
return /* @__PURE__ */ React2.createElement(
"svg",
{
className: "h-full w-full fill-current",
xmlns: "http://www.w3.org/2000/svg",
viewBox: "0 0 195 185"
},
/* @__PURE__ */ React2.createElement("path", { d: "M25.164 81.9737C22.31 81.9737 19.998 84.2877 20 87.1417L20.028 128.458C20.03 131.309 22.341 133.619 25.192 133.619C28.046 133.619 30.359 131.304 30.357 128.451L30.328 87.1347C30.326 84.2837 28.015 81.9737 25.164 81.9737Z" }),
/* @__PURE__ */ React2.createElement("path", { d: "M87.1367 61.3158C84.2837 61.3158 81.9707 63.6298 81.9727 66.4828L82.0017 118.128C82.0037 120.979 84.3147 123.29 87.1667 123.29C90.0197 123.29 92.3327 120.976 92.3307 118.122L92.3007 66.4778C92.2997 63.6258 89.9877 61.3158 87.1367 61.3158Z" }),
/* @__PURE__ */ React2.createElement("path", { d: "M107.793 20C104.94 20 102.628 22.313 102.629 25.166L102.661 159.442C102.662 162.294 104.974 164.605 107.826 164.605C110.679 164.605 112.991 162.293 112.99 159.44L112.957 25.163C112.957 22.311 110.645 20 107.793 20Z" }),
/* @__PURE__ */ React2.createElement("path", { d: "M128.451 20C125.598 20 123.286 22.313 123.287 25.166L123.319 159.442C123.32 162.294 125.632 164.605 128.484 164.605C131.337 164.605 133.649 162.293 133.648 159.44L133.615 25.163C133.615 22.311 131.303 20 128.451 20Z" }),
/* @__PURE__ */ React2.createElement("path", { d: "M149.11 20C146.257 20 143.944 22.313 143.946 25.167L143.977 102.634C143.978 105.485 146.29 107.796 149.141 107.796C151.994 107.796 154.307 105.483 154.306 102.63L154.274 25.162C154.273 22.311 151.961 20 149.11 20Z" }),
/* @__PURE__ */ React2.createElement("path", { d: "M169.75 40.6579C166.897 40.6579 164.585 42.9709 164.586 45.8239L164.617 138.785C164.618 141.637 166.93 143.948 169.782 143.948C172.635 143.948 174.947 141.634 174.946 138.781L174.914 45.8209C174.914 42.9689 172.602 40.6579 169.75 40.6579Z" }),
/* @__PURE__ */ React2.createElement("path", { d: "M45.8203 61.3158C42.9673 61.3158 40.6553 63.6288 40.6563 66.4818L40.6873 159.443C40.6883 162.295 43.0003 164.606 45.8523 164.606C48.7053 164.606 51.0173 162.292 51.0163 159.439L50.9843 66.4788C50.9843 63.6268 48.6723 61.3158 45.8203 61.3158Z" }),
/* @__PURE__ */ React2.createElement("path", { d: "M66.4785 61.3158C63.6255 61.3158 61.3135 63.6288 61.3145 66.4818L61.3455 159.443C61.3465 162.295 63.6585 164.606 66.5105 164.606C69.3635 164.606 71.6755 162.292 71.6745 159.439L71.6425 66.4788C71.6415 63.6268 69.3305 61.3158 66.4785 61.3158Z" })
);
}
// src/player/react/hooks.ts
import { useContext, useEffect, useState } from "react";
import { merge as merge2 } from "rxjs";
// src/player/react/EmpiricaParticipant.tsx
import React3 from "react";
var ParticipantCtx = React3.createContext(void 0);
var contexts = {};
function EmpiricaParticipant({
url,
ns,
modeFunc,
children
}) {
let partCtx;
if (ns in contexts) {
partCtx = contexts[ns];
} else {
if (modeFunc) {
partCtx = new ParticipantModeContext(url, ns, modeFunc);
} else {
partCtx = new ParticipantContext(url, ns);
}
contexts[ns] = partCtx;
}
return /* @__PURE__ */ React3.createElement(ParticipantCtx.Provider, { value: partCtx }, children);
}
// src/player/react/hooks.ts
function useParticipantContext() {
return useContext(ParticipantCtx);
}
function useTajribaConnecting() {
return useTajribaCtxKey("connecting");
}
function useTajribaConnected() {
return useTajribaCtxKey("connected");
}
function usePartConnected() {
return usePartCtxKey("connected");
}
function useTajriba() {
const ctx = useParticipantContext();
return ctx?.tajriba;
}
function useGlobal() {
const ctx = usePartCtxKey("globals");
const [val, setVal] = useState({ g: void 0 });
useEffect(() => {
if (!ctx || !ctx.self) {
return;
}
const sub = ctx.self.subscribe({
next(g) {
setVal({ g });
}
});
return sub.unsubscribe.bind(sub);
}, [ctx]);
return val.g;
}
var defaultConsentKey = "empirica:consent";
function useConsent(ns = "") {
const key = `${defaultConsentKey}${ns ? `:${ns}` : ""}`;
const getConsented = () => Boolean(window.localStorage[key]);
const [consented, setConsented] = useState(getConsented());
function onConsent() {
window.localStorage[key] = true;
setConsented(true);
}
return [consented, consented ? void 0 : onConsent];
}
function usePlayerID() {
const ctx = useParticipantContext();
const [connecting, setConnecting] = useState(true);
const [playerID, setPlayerID] = useState(void 0);
const [changePlayerID, setChangePlayerID] = useState(void 0);
useEffect(() => {
if (!ctx) {
return;
}
let _connecting = true;
let session;
const sub = merge2(
ctx.participant.connecting,
ctx.session.sessions
).subscribe({
next(sessionOrConnecting) {
if (typeof sessionOrConnecting === "boolean") {
setConnecting(sessionOrConnecting);
_connecting = sessionOrConnecting;
} else {
session = sessionOrConnecting;
}
if (_connecting) {
setPlayerID(void 0);
setChangePlayerID(void 0);
} else if (!session) {
setPlayerID(void 0);
setChangePlayerID(() => async (playerIdentifier) => {
await ctx.register(playerIdentifier);
});
} else {
setPlayerID(session.participant.identifier);
setChangePlayerID(void 0);
}
}
});
return sub.unsubscribe.bind(sub);
}, [ctx]);
return [connecting, playerID, changePlayerID];
}
function useTajribaCtxKey(name) {
return useCtxKey(useTajriba, name);
}
function usePartCtxKey(name) {
return useCtxKey(useParticipantContext, name);
}
function useCtxKey(ctxFunc, name) {
const ctx = ctxFunc();
const [val, setVal] = useState(void 0);
useEffect(() => {
if (!ctx || !ctx[name]) {
return;
}
const obs = ctx[name];
const sub = obs.subscribe({
next(g) {
setVal(g);
}
});
return sub.unsubscribe.bind(sub);
}, [ctx]);
return val;
}
// src/player/react/EmpiricaMenu.tsx
function EmpiricaMenu({ position = "bottom-left" }) {
const ctx = useParticipantContext();
if (!ctx) {
return null;
}
function resetSession() {
ctx.session.clearSession();
window.location.reload();
}
let className = "backdrop-blur-md bg-gray-200/50 rounded fixed z-20 flex space-x-1 text-gray-500";
switch (position) {
case "top":
className += " top-0 mt-2 ml-1/2 -translate-x-1/2";
break;
case "top-left":
className += " top-0 left-0 mt-2 ml-2";
break;
case "top-right":
className += " top-0 right-0 mt-2 mr-2";
break;
case "bottom":
className += " bottom-0 mb-2 ml-1/2 -translate-x-1/2";
break;
case "bottom-right":
className += " bottom-0 right-0 mb-2 mr-2";
break;
case "bottom-left":
default:
className += " bottom-0 left-0 mb-2 ml-2";
break;
}
const buttons = [
{
onClick: () => {
window.open("https://empirica.ly", "_blank");
},
icon: /* @__PURE__ */ React4.createElement(Logo, null),
title: "Empirica",
inDevOnly: position === "top" || position === "bottom"
},
{
onClick: () => createNewParticipant(),
icon: /* @__PURE__ */ React4.createElement(
"svg",
{
xmlns: "http://www.w3.org/2000/svg",
viewBox: "0 0 24 24",
fill: "none",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round",
className: "h-full w-full stroke-current"
},
/* @__PURE__ */ React4.createElement("path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }),
/* @__PURE__ */ React4.createElement("circle", { cx: "9", cy: "7", r: "4" }),
/* @__PURE__ */ React4.createElement("line", { x1: "19", x2: "19", y1: "8", y2: "14" }),
/* @__PURE__ */ React4.createElement("line", { x1: "22", x2: "16", y1: "11", y2: "11" })
),
inDevOnly: true,
title: "New Participant"
},
{
onClick: resetSession,
icon: /* @__PURE__ */ React4.createElement(
"svg",
{
xmlns: "http://www.w3.org/2000/svg",
viewBox: "0 0 24 24",
fill: "none",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round",
className: "h-full w-full stroke-current"
},
/* @__PURE__ */ React4.createElement("path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
/* @__PURE__ */ React4.createElement("path", { d: "M3 3v5h5" })
),
inDevOnly: true,
title: "Reset Session"
},
{
onClick: () => {
window.open("/admin", "_blank");
},
icon: /* @__PURE__ */ React4.createElement(
"svg",
{
xmlns: "http://www.w3.org/2000/svg",
viewBox: "0 0 24 24",
fill: "none",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round",
className: "h-full w-full stroke-current"
},
/* @__PURE__ */ React4.createElement("path", { d: "M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z" })
),
inDevOnly: true,
title: "Admin"
},
{
onClick: () => {
window.open("https://docs.empirica.ly", "_blank");
},
icon: /* @__PURE__ */ React4.createElement(
"svg",
{
xmlns: "http://www.w3.org/2000/svg",
viewBox: "0 0 24 24",
fill: "none",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round",
className: "h-full w-full stroke-current"
},
/* @__PURE__ */ React4.createElement("path", { d: "M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z" }),
/* @__PURE__ */ React4.createElement("path", { d: "M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z" })
),
inDevOnly: true,
title: "Documentation"
}
];
return /* @__PURE__ */ React4.createElement("div", { className }, buttons.map((button, i) => {
let sizing = "";
if (i === 0) {
sizing = "w-9 h-8 p-1.5 pl-2.5";
if (buttons.length === 0) {
sizing += " pr-2.5";
}
} else if (i === buttons.length - 1) {
sizing += "w-8.5 h-8 p-2 pr-2.5";
}
return /* @__PURE__ */ React4.createElement(ToolButton, { key: i, ...button, sizing });
}));
}
function ToolButton({
onClick,
icon,
title,
sizing = "",
inDevOnly = false
}) {
if (inDevOnly && !isDevelopment) {
return /* @__PURE__ */ React4.createElement(React4.Fragment, null);
}
let size = "w-8 h-8 p-2";
if (sizing) {
size = sizing;
}
let className = "block bg-transparent hover:text-empirica-600 hover:bg-gray-300 rounded " + size;
return /* @__PURE__ */ React4.createElement("button", { onClick, className, title }, icon);
}
// src/player/react/Finished.tsx
import React5 from "react";
function Finished() {
return /* @__PURE__ */ React5.createElement("div", { className: "h-full flex flex-col items-center justify-center" }, /* @__PURE__ */ React5.createElement("h2", { className: "font-medium text-gray-700" }, "Finished"), /* @__PURE__ */ React5.createElement("p", { className: "mt-2 text-gray-400" }, "Thank you for participating"));
}
// src/player/react/Loading.tsx
import React6 from "react";
function Loading() {
return /* @__PURE__ */ React6.createElement("div", { className: "h-full w-full flex items-center justify-center" }, /* @__PURE__ */ React6.createElement(
"svg",
{
width: "44",
height: "44",
viewBox: "0 0 44 44",
xmlns: "http://www.w3.org/2000/svg",
className: "text-empirica-200 stroke-current"
},
/* @__PURE__ */ React6.createElement("g", { fill: "none", fillRule: "evenodd", strokeWidth: "2" }, /* @__PURE__ */ React6.createElement("circle", { cx: "22", cy: "22", r: "1" }, /* @__PURE__ */ React6.createElement(
"animate",
{
attributeName: "r",
begin: "0s",
dur: "1.8s",
values: "1; 20",
calcMode: "spline",
keyTimes: "0; 1",
keySplines: "0.165, 0.84, 0.44, 1",
repeatCount: "indefinite"
}
), /* @__PURE__ */ React6.createElement(
"animate",
{
attributeName: "stroke-opacity",
begin: "0s",
dur: "1.8s",
values: "1; 0",
calcMode: "spline",
keyTimes: "0; 1",
keySplines: "0.3, 0.61, 0.355, 1",
repeatCount: "indefinite"
}
)), /* @__PURE__ */ React6.createElement("circle", { cx: "22", cy: "22", r: "1" }, /* @__PURE__ */ React6.createElement(
"animate",
{
attributeName: "r",
begin: "-0.9s",
dur: "1.8s",
values: "1; 20",
calcMode: "spline",
keyTimes: "0; 1",
keySplines: "0.165, 0.84, 0.44, 1",
repeatCount: "indefinite"
}
), /* @__PURE__ */ React6.createElement(
"animate",
{
attributeName: "stroke-opacity",
begin: "-0.9s",
dur: "1.8s",
values: "1; 0",
calcMode: "spline",
keyTimes: "0; 1",
keySplines: "0.3, 0.61, 0.355, 1",
repeatCount: "indefinite"
}
)))
));
}
// src/player/react/NoGames.tsx
import React7 from "react";
function NoGames() {
return /* @__PURE__ */ React7.createElement("div", { className: "h-screen flex items-center justify-center" }, /* @__PURE__ */ React7.createElement("div", { className: "w-92 flex flex-col items-center" }, /* @__PURE__ */ React7.createElement("h2", { className: "text-gray-700 font-medium" }, "No experiments available"), /* @__PURE__ */ React7.createElement("p", { className: "mt-2 text-gray-400 text-justify" }, "There are currently no available experiments. Please wait until an experiment becomes available or come back at a later date."), isDevelopment ? /* @__PURE__ */ React7.createElement("p", { className: "mt-4 text-gray-700" }, "Go to", " ", /* @__PURE__ */ React7.createElement(
"a",
{
href: "/admin",
target: "empirica-admin",
className: "text-empirica-500"
},
"Admin"
), " ", "to get started") : ""));
}
// src/player/react/PlayerCreate.tsx
import React8, { useState as useState2 } from "react";
function PlayerCreate({ onPlayerID, connecting }) {
const [playerID, setPlayerID] = useState2("");
const handleSubmit = (evt) => {
evt.preventDefault();
if (!playerID || playerID.trim() === "") {
return;
}
onPlayerID(playerID);
};
return /* @__PURE__ */ React8.createElement("div", { className: "min-h-screen bg-empirica-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8" }, /* @__PURE__ */ React8.createElement("div", { className: "sm:mx-auto sm:w-full sm:max-w-md" }, /* @__PURE__ */ React8.createElement("h2", { className: "mt-6 text-center text-3xl font-extrabold text-gray-900" }, "Enter your Player Identifier")), /* @__PURE__ */ React8.createElement("div", { className: "mt-8 sm:mx-auto sm:w-full sm:max-w-md" }, /* @__PURE__ */ React8.createElement("div", { className: "bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10" }, /* @__PURE__ */ React8.createElement(
"form",
{
className: "space-y-6",
action: "#",
method: "POST",
onSubmit: handleSubmit
},
/* @__PURE__ */ React8.createElement("fieldset", { disabled: connecting }, /* @__PURE__ */ React8.createElement("div", null, /* @__PURE__ */ React8.createElement(
"label",
{
htmlFor: "email",
className: "block text-sm font-medium text-gray-700"
},
"Identifier"
), /* @__PURE__ */ React8.createElement("div", { className: "mt-1" }, /* @__PURE__ */ React8.createElement(
"input",
{
id: "playerID",
name: "playerID",
type: "text",
autoComplete: "off",
required: true,
autoFocus: true,
className: "appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-empirica-500 focus:border-empirica-500 sm:text-sm",
value: playerID,
onChange: (e) => setPlayerID(e.target.value)
}
), /* @__PURE__ */ React8.createElement(
"p",
{
className: "mt-2 text-sm text-gray-500",
id: "playerID-description"
},
"This should be given to you. E.g. email, code..."
))), /* @__PURE__ */ React8.createElement("div", null, /* @__PURE__ */ React8.createElement(
"button",
{
type: "submit",
className: "w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-empirica-600 hover:bg-empirica-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-empirica-500"
},
"Enter"
)))
))));
}
export {
Consent,
Finished,
Loading,
NoGames,
PlayerCreate,
ParticipantContext,
EmpiricaParticipant,
useParticipantContext,
useTajribaConnecting,
useTajribaConnected,
usePartConnected,
useTajriba,
useGlobal,
useConsent,
usePlayerID,
Logo,
EmpiricaMenu
};
//# sourceMappingURL=chunk-UMPSA52E.js.map