diff --git a/frontend/src/styles/test.scss b/frontend/src/styles/test.scss
index d0064f2c7c24..80b217b397c0 100644
--- a/frontend/src/styles/test.scss
+++ b/frontend/src/styles/test.scss
@@ -124,7 +124,6 @@
display: grid;
font-size: 10rem;
- opacity: 0;
width: 0;
height: 0;
justify-self: center;
@@ -163,8 +162,8 @@
}
}
- #liveStatsTextBottom.timerMain,
- #liveStatsTextTop.timerMain {
+ #liveStatsTextBottom .colorMain,
+ #liveStatsTextTop .colorMain {
color: var(--main-color);
}
@@ -172,8 +171,8 @@
background: var(--main-color);
}
- #liveStatsTextBottom.timerSub,
- #liveStatsTextTop.timerSub {
+ #liveStatsTextBottom .colorSub,
+ #liveStatsTextTop .colorSub {
color: var(--sub-color);
}
@@ -181,8 +180,8 @@
background: var(--sub-color);
}
- #liveStatsTextBottom.timerText,
- #liveStatsTextTop.timerText {
+ #liveStatsTextBottom .colorText,
+ #liveStatsTextTop .colorText {
color: var(--text-color);
}
@@ -1474,68 +1473,36 @@
}
}
#liveStatsMini {
- width: 0;
- justify-content: start;
- height: 0;
- margin-left: 0.25em;
- display: flex;
- margin-top: -1.25em;
- color: black;
-
- div {
- font-size: 1em;
- line-height: 1em;
- }
-
- .time,
- .speed,
- .acc {
- margin-right: 0.5em;
- }
+ .wrapper {
+ width: 0;
+ justify-content: start;
+ height: 0;
+ display: flex;
+ margin-top: -1.25em;
+ color: black;
- .time,
- .speed,
- .acc,
- .burst {
- opacity: 0;
- }
+ div {
+ font-size: 1em;
+ line-height: 1em;
+ }
- &.timerMain {
- color: var(--main-color);
- }
+ .time,
+ .speed,
+ .acc {
+ margin-right: 0.5em;
+ }
- &.timerSub {
- color: var(--sub-color);
- }
+ &.colorMain {
+ color: var(--main-color);
+ }
- &.timerText {
- color: var(--text-color);
- }
+ &.colorSub {
+ color: var(--sub-color);
+ }
- &.size125 {
- margin-top: -1.75rem;
- font-size: 1.25rem;
- line-height: 1.25rem;
- }
- &.size15 {
- margin-top: -2rem;
- font-size: 1.5rem;
- line-height: 1.5rem;
- }
- &.size2 {
- margin-top: -2.5rem;
- font-size: 2rem;
- line-height: 2rem;
- }
- &.size3 {
- margin-top: -3.5rem;
- font-size: 3rem;
- line-height: 3rem;
- }
- &.size4 {
- margin-top: -4.5rem;
- font-size: 4rem;
- line-height: 4rem;
+ &.colorText {
+ color: var(--text-color);
+ }
}
}
}
diff --git a/frontend/src/ts/components/mount.tsx b/frontend/src/ts/components/mount.tsx
new file mode 100644
index 000000000000..3387e85db644
--- /dev/null
+++ b/frontend/src/ts/components/mount.tsx
@@ -0,0 +1,30 @@
+import { render } from "solid-js/web";
+import { qsr } from "../utils/dom";
+import {
+ TextLiveStatsBottom,
+ MiniLiveStats,
+ TextLiveStatsTop,
+} from "./test/LiveStats";
+import { getAcc, getBurst, getProgress, getWpm } from "../signals/test";
+
+export function mountComponents(): void {
+ render(
+ () => (
+
+ ),
+ qsr("#liveStatsMini").native,
+ );
+ render(
+ () =>
,
+ qsr("#liveStatsTextBottom").native,
+ );
+ render(
+ () =>
,
+ qsr("#liveStatsTextTop").native,
+ );
+}
diff --git a/frontend/src/ts/components/test/LiveStats.tsx b/frontend/src/ts/components/test/LiveStats.tsx
new file mode 100644
index 000000000000..57fb14036b36
--- /dev/null
+++ b/frontend/src/ts/components/test/LiveStats.tsx
@@ -0,0 +1,203 @@
+import { Accessor, JSXElement } from "solid-js";
+
+import { isFocused } from "../../test/focus";
+import {
+ useVisibilityAnimation,
+ VisibilityAnimationOptions,
+} from "../../hooks/useVisibilityAnimation";
+import { useRefWithUtils } from "../../hooks/useRefWithUtils";
+import { getTestTime, statsVisible } from "../../signals/test";
+import Config from "../../config";
+import * as CustomText from "../../test/custom-text";
+import { getConfigSignal } from "../../signals/config";
+
+function Stat(props: {
+ value: Accessor
;
+ visibilityOptions: Accessor;
+ class?: string;
+ style?: Record;
+}): JSXElement {
+ const [ref, element] = useRefWithUtils();
+
+ useVisibilityAnimation(element, props.visibilityOptions);
+
+ return (
+
+ {props.value()}
+
+ );
+}
+
+const getStatsVisible = (
+ visible: Accessor,
+): Accessor => {
+ return () => ({
+ visible: statsVisible().visible && isFocused() && visible(),
+ animate: statsVisible().animate,
+ });
+};
+
+function getStatsColorClass(): string {
+ const cfg = getConfigSignal();
+ const configValue = cfg.timerColor;
+ if (configValue === "main") {
+ return "colorMain";
+ } else if (configValue === "sub") {
+ return "colorSub";
+ } else if (configValue === "text") {
+ return "colorText";
+ } else if (configValue === "black") {
+ return "colorBlack";
+ }
+ return "";
+}
+
+function getFlashTimerOpacity(): string {
+ let opacity = "1";
+ const time = getTestTime();
+ let maxtime = Config.time;
+ if (Config.mode === "custom" && CustomText.getLimitMode() === "time") {
+ maxtime = CustomText.getLimitValue();
+ }
+
+ const timedTest =
+ Config.mode === "time" ||
+ (Config.mode === "custom" && CustomText.getLimitMode() === "time");
+
+ if (
+ timedTest &&
+ (getConfigSignal().timerStyle === "flash_mini" ||
+ getConfigSignal().timerStyle === "flash_text")
+ ) {
+ if ((maxtime - time) % 15 !== 0) {
+ opacity = "0";
+ } else {
+ opacity = "1";
+ }
+ }
+ return opacity;
+}
+
+export function MiniLiveStats(props: {
+ progress: Accessor;
+ wpm: Accessor;
+ acc: Accessor;
+ burst: Accessor;
+}): JSXElement {
+ const isVisible = (
+ config: Accessor,
+ ): Accessor => {
+ return getStatsVisible(() => config() === props.mode);
+ };
+
+ return (
+
+
+ getConfigSignal().timerStyle === "mini" ||
+ getConfigSignal().timerStyle === "flash_mini",
+ )}
+ />
+ getConfigSignal().liveSpeedStyle === "mini",
+ )}
+ />
+ getConfigSignal().liveAccStyle === "mini",
+ )}
+ />
+ getConfigSignal().liveBurstStyle === "mini",
+ )}
+ />
+
+ );
+}
+
+export function TextLiveStatsTop(props: {
+ progress: Accessor;
+}): JSXElement {
+ return (
+
+
+ getConfigSignal().timerStyle === "text" ||
+ getConfigSignal().timerStyle === "flash_text",
+ )}
+ />
+
+ );
+}
+
+export function TextLiveStatsBottom(props: {
+ wpm: Accessor;
+ acc: Accessor;
+ burst: Accessor;
+}): JSXElement {
+ return (
+
+ getConfigSignal().liveSpeedStyle === "text",
+ )}
+ />
+ getConfigSignal().liveAccStyle === "text",
+ )}
+ />
+ getConfigSignal().liveBurstStyle === "text",
+ )}
+ />
+
+ );
+}
diff --git a/frontend/src/ts/config.ts b/frontend/src/ts/config.ts
index 271105df54d9..eef25f4bdbc1 100644
--- a/frontend/src/ts/config.ts
+++ b/frontend/src/ts/config.ts
@@ -79,7 +79,7 @@ export function saveFullConfigToLocalStorage(noDbCheck = false): void {
}
function isConfigChangeBlocked(): boolean {
- if (TestState.isActive && config.funbox.includes("no_quit")) {
+ if (TestState.isActive() && config.funbox.includes("no_quit")) {
Notifications.add("No quit funbox is active. Please finish the test.", 0, {
important: true,
});
@@ -112,7 +112,7 @@ export function setConfig(
if (
metadata.changeRequiresRestart &&
- TestState.isActive &&
+ TestState.isActive() &&
config.funbox.includes("no_quit")
) {
Notifications.add("No quit funbox is active. Please finish the test.", 0, {
diff --git a/frontend/src/ts/controllers/ad-controller.ts b/frontend/src/ts/controllers/ad-controller.ts
index 31bab3ca7659..d9c98545eceb 100644
--- a/frontend/src/ts/controllers/ad-controller.ts
+++ b/frontend/src/ts/controllers/ad-controller.ts
@@ -42,7 +42,7 @@ function init(): void {
}
setInterval(() => {
- if (TestState.isActive) {
+ if (TestState.isActive()) {
return;
}
if (choice === "eg") {
diff --git a/frontend/src/ts/controllers/route-controller.ts b/frontend/src/ts/controllers/route-controller.ts
index d9d4295251c4..5949cc683c3a 100644
--- a/frontend/src/ts/controllers/route-controller.ts
+++ b/frontend/src/ts/controllers/route-controller.ts
@@ -176,7 +176,7 @@ export async function navigate(
}
const noQuit = isFunboxActive("no_quit");
- if (TestState.isActive && noQuit) {
+ if (TestState.isActive() && noQuit) {
Notifications.add("No quit funbox is active. Please finish the test.", 0, {
important: true,
});
diff --git a/frontend/src/ts/elements/scroll-to-top.ts b/frontend/src/ts/elements/scroll-to-top.ts
index 2ebd2d48ea82..02791356baca 100644
--- a/frontend/src/ts/elements/scroll-to-top.ts
+++ b/frontend/src/ts/elements/scroll-to-top.ts
@@ -1,5 +1,5 @@
import * as ActivePage from "../states/active-page";
-import { prefersReducedMotion } from "../utils/misc";
+import { prefersReducedMotion } from "../utils/accessibility";
import { qsr } from "../utils/dom";
let visible = false;
diff --git a/frontend/src/ts/hooks/useRefWithUtils.ts b/frontend/src/ts/hooks/useRefWithUtils.ts
new file mode 100644
index 000000000000..32fc5232764f
--- /dev/null
+++ b/frontend/src/ts/hooks/useRefWithUtils.ts
@@ -0,0 +1,17 @@
+import { Accessor } from "solid-js";
+import { ElementWithUtils } from "../utils/dom";
+
+export function useRefWithUtils(): [
+ ref: (el: T) => void,
+ element: Accessor | undefined>,
+] {
+ let elementWithUtils: ElementWithUtils | undefined;
+
+ const ref = (el: T): void => {
+ elementWithUtils = new ElementWithUtils(el);
+ };
+
+ const element = (): ElementWithUtils | undefined => elementWithUtils;
+
+ return [ref, element];
+}
diff --git a/frontend/src/ts/hooks/useVisibilityAnimation.ts b/frontend/src/ts/hooks/useVisibilityAnimation.ts
new file mode 100644
index 000000000000..855280673c57
--- /dev/null
+++ b/frontend/src/ts/hooks/useVisibilityAnimation.ts
@@ -0,0 +1,46 @@
+import { Accessor, createEffect } from "solid-js";
+import { ElementWithUtils } from "../utils/dom";
+import { applyReducedMotion } from "../utils/accessibility";
+
+export type VisibilityAnimationOptions = {
+ visible: boolean;
+ animate?: boolean;
+};
+
+export function useVisibilityAnimation(
+ element: Accessor | undefined>,
+ options?: Accessor,
+): void {
+ if (!options) return;
+ createEffect(() => {
+ const el = element();
+ const opt = options();
+ if (!el) return;
+ el.setAttribute("data-visible", opt.visible ? "true" : "false");
+ if (opt.visible) {
+ if (opt.animate) {
+ el.show();
+ el.animate({
+ opacity: [0, 1],
+ duration: applyReducedMotion(125),
+ });
+ } else {
+ el.setStyle({ opacity: "1" });
+ el.show();
+ }
+ } else {
+ if (opt.animate) {
+ el.animate({
+ opacity: [1, 0],
+ duration: applyReducedMotion(125),
+ onComplete: () => {
+ el.hide();
+ },
+ });
+ } else {
+ el.setStyle({ opacity: "0" });
+ el.hide();
+ }
+ }
+ });
+}
diff --git a/frontend/src/ts/index.ts b/frontend/src/ts/index.ts
index f74f3104e236..0ad2ffc0a0d5 100644
--- a/frontend/src/ts/index.ts
+++ b/frontend/src/ts/index.ts
@@ -48,6 +48,7 @@ import "./utils/url-handler";
import "./modals/last-signed-out-result";
import { applyEngineSettings } from "./anim";
import { qs, qsa, qsr } from "./utils/dom";
+import { mountComponents } from "./components/mount";
// Lock Math.random
Object.defineProperty(Math, "random", {
@@ -107,3 +108,5 @@ if (isDevEnvironment()) {
module.appendButton();
});
}
+
+mountComponents();
diff --git a/frontend/src/ts/input/handlers/before-delete.ts b/frontend/src/ts/input/handlers/before-delete.ts
index 79fb28d77d50..c42d36517bf4 100644
--- a/frontend/src/ts/input/handlers/before-delete.ts
+++ b/frontend/src/ts/input/handlers/before-delete.ts
@@ -7,7 +7,7 @@ import * as TestUI from "../../test/test-ui";
import { isAwaitingNextWord } from "../state";
export function onBeforeDelete(event: InputEvent): void {
- if (!TestState.isActive) {
+ if (!TestState.isActive()) {
event.preventDefault();
return;
}
diff --git a/frontend/src/ts/input/handlers/insert-text.ts b/frontend/src/ts/input/handlers/insert-text.ts
index 00a0f7258522..6ecc39886d94 100644
--- a/frontend/src/ts/input/handlers/insert-text.ts
+++ b/frontend/src/ts/input/handlers/insert-text.ts
@@ -113,7 +113,7 @@ export async function onInsertText(options: OnInsertTextParams): Promise {
const data = normalizedData ?? options.data;
// start if needed
- if (!TestState.isActive) {
+ if (!TestState.isActive()) {
TestLogic.startTest(now);
}
diff --git a/frontend/src/ts/input/listeners/composition.ts b/frontend/src/ts/input/listeners/composition.ts
index e3388a557df7..4904651c1ee9 100644
--- a/frontend/src/ts/input/listeners/composition.ts
+++ b/frontend/src/ts/input/listeners/composition.ts
@@ -19,7 +19,7 @@ inputEl.addEventListener("compositionstart", (event) => {
CompositionState.setComposing(true);
CompositionState.setData("");
setLastInsertCompositionTextData("");
- if (!TestState.isActive) {
+ if (!TestState.isActive()) {
TestLogic.startTest(performance.now());
}
});
diff --git a/frontend/src/ts/pages/account.ts b/frontend/src/ts/pages/account.ts
index f57c3ade6b85..a4d72418dea4 100644
--- a/frontend/src/ts/pages/account.ts
+++ b/frontend/src/ts/pages/account.ts
@@ -36,7 +36,6 @@ import Ape from "../ape";
import { AccountChart } from "@monkeytype/schemas/configs";
import { SortedTableWithLimit } from "../utils/sorted-table";
import { qs, qsa, qsr, onWindowLoad, ElementWithUtils } from "../utils/dom";
-
let filterDebug = false;
//toggle filterdebug
export function toggleFilterDebug(): void {
@@ -564,7 +563,7 @@ async function fillContent(): Promise {
histogramChartData.push(0);
}
}
- (histogramChartData[bucket] as number)++;
+ (histogramChartData[bucket] as number) += 1;
let tt = 0;
if (
diff --git a/frontend/src/ts/signals/config.ts b/frontend/src/ts/signals/config.ts
new file mode 100644
index 000000000000..3a0a68cb2a19
--- /dev/null
+++ b/frontend/src/ts/signals/config.ts
@@ -0,0 +1,12 @@
+import { createSignal } from "solid-js";
+import * as ConfigEvent from "../observables/config-event";
+import config from "../config";
+import { Config } from "@monkeytype/schemas/configs";
+
+const [getConfigSignal, setConfigSignal] = createSignal(config);
+
+export { getConfigSignal };
+
+ConfigEvent.subscribe(() => {
+ setConfigSignal(structuredClone(config));
+});
diff --git a/frontend/src/ts/signals/test.ts b/frontend/src/ts/signals/test.ts
new file mode 100644
index 000000000000..c3487ba86bf7
--- /dev/null
+++ b/frontend/src/ts/signals/test.ts
@@ -0,0 +1,120 @@
+import { createSignal } from "solid-js";
+import { VisibilityAnimationOptions } from "../hooks/useVisibilityAnimation";
+import * as Time from "../states/time";
+import Config from "../config";
+import * as CustomText from "../test/custom-text";
+import * as DateTime from "../utils/date-and-time";
+import * as TestWords from "../test/test-words";
+import * as TestInput from "../test/test-input";
+import * as TestState from "../test/test-state";
+
+export const [getTestTime, setTestTime] = createSignal(0);
+export const [getProgress, setLiveProgress] = createSignal("");
+export const [getWpm, setLiveStatWpm] = createSignal("0");
+export const [getAcc, setLiveStatAcc] = createSignal("100%");
+export const [getBurst, setLiveStatBurst] = createSignal("0");
+
+export const [statsVisible, setStatsVisible] =
+ createSignal({
+ visible: false,
+ animate: true,
+ });
+
+function getCurrentCount(): number {
+ if (Config.mode === "custom" && CustomText.getLimitMode() === "section") {
+ return (
+ (TestWords.words.sectionIndexList[TestState.activeWordIndex] as number) -
+ 1
+ );
+ } else {
+ return TestInput.input.getHistory().length;
+ }
+}
+
+export function updateProgressSignal(): void {
+ const time = Time.get();
+ if (
+ Config.mode === "time" ||
+ (Config.mode === "custom" && CustomText.getLimitMode() === "time")
+ ) {
+ let maxtime = Config.time;
+ if (Config.mode === "custom" && CustomText.getLimitMode() === "time") {
+ maxtime = CustomText.getLimitValue();
+ }
+ if (Config.timerStyle === "text") {
+ let displayTime = DateTime.secondsToString(maxtime - time);
+ if (maxtime === 0) {
+ displayTime = DateTime.secondsToString(time);
+ }
+ setLiveProgress(displayTime);
+ } else if (Config.timerStyle === "flash_mini") {
+ let displayTime = DateTime.secondsToString(maxtime - time);
+ if (maxtime === 0) {
+ displayTime = DateTime.secondsToString(time);
+ }
+ setLiveProgress(displayTime);
+ } else if (Config.timerStyle === "flash_text") {
+ let displayTime = DateTime.secondsToString(maxtime - time);
+ if (maxtime === 0) {
+ displayTime = DateTime.secondsToString(time);
+ }
+ setLiveProgress(displayTime);
+ } else if (Config.timerStyle === "mini") {
+ let displayTime = DateTime.secondsToString(maxtime - time);
+ if (maxtime === 0) {
+ displayTime = DateTime.secondsToString(time);
+ }
+ setLiveProgress(displayTime);
+ }
+ } else if (
+ Config.mode === "words" ||
+ Config.mode === "custom" ||
+ Config.mode === "quote"
+ ) {
+ let outof = TestWords.words.length;
+ if (Config.mode === "words") {
+ outof = Config.words;
+ }
+ if (Config.mode === "custom") {
+ outof = CustomText.getLimitValue();
+ }
+ if (Config.mode === "quote") {
+ outof = TestWords.currentQuote?.textSplit.length ?? 1;
+ }
+ if (Config.timerStyle === "text") {
+ if (outof === 0) {
+ setLiveProgress(`${TestInput.input.getHistory().length}`);
+ } else {
+ setLiveProgress(`${getCurrentCount()}/${outof}`);
+ }
+ } else if (Config.timerStyle === "flash_mini") {
+ if (outof === 0) {
+ setLiveProgress(`${TestInput.input.getHistory().length}`);
+ } else {
+ setLiveProgress(`${getCurrentCount()}/${outof}`);
+ }
+ } else if (Config.timerStyle === "flash_text") {
+ if (outof === 0) {
+ setLiveProgress(`${TestInput.input.getHistory().length}`);
+ } else {
+ setLiveProgress(`${getCurrentCount()}/${outof}`);
+ }
+ } else if (Config.timerStyle === "mini") {
+ if (outof === 0) {
+ setLiveProgress(`${TestInput.input.getHistory().length}`);
+ } else {
+ setLiveProgress(`${getCurrentCount()}/${outof}`);
+ }
+ }
+ } else if (Config.mode === "zen") {
+ if (Config.timerStyle === "text") {
+ setLiveProgress(`${TestInput.input.getHistory().length}`);
+ } else if (Config.timerStyle === "flash_mini") {
+ setLiveProgress(`${TestInput.input.getHistory().length}`);
+ } else if (Config.timerStyle === "flash_text") {
+ setLiveProgress(`${TestInput.input.getHistory().length}`);
+ } else {
+ setLiveProgress(`${TestInput.input.getHistory().length}`);
+ }
+ }
+}
diff --git a/frontend/src/ts/states/connection.ts b/frontend/src/ts/states/connection.ts
index efaeebd8f6a4..76bd47cfa287 100644
--- a/frontend/src/ts/states/connection.ts
+++ b/frontend/src/ts/states/connection.ts
@@ -39,7 +39,7 @@ const throttledHandleState = debounce(5000, () => {
)?.dispatch("click");
}
bannerAlreadyClosed = false;
- } else if (!TestState.isActive) {
+ } else if (!TestState.isActive()) {
showOfflineBanner();
}
});
diff --git a/frontend/src/ts/states/time.ts b/frontend/src/ts/states/time.ts
index c18761a1a208..35e3496def25 100644
--- a/frontend/src/ts/states/time.ts
+++ b/frontend/src/ts/states/time.ts
@@ -1,3 +1,5 @@
+import { setTestTime } from "../signals/test";
+
let time = 0;
export function get(): number {
@@ -6,8 +8,10 @@ export function get(): number {
export function set(number: number): void {
time = number;
+ setTestTime(time);
}
export function increment(): void {
time++;
+ setTestTime(time);
}
diff --git a/frontend/src/ts/test/focus.ts b/frontend/src/ts/test/focus.ts
index 7b9842e2f124..8cbd420234a0 100644
--- a/frontend/src/ts/test/focus.ts
+++ b/frontend/src/ts/test/focus.ts
@@ -1,13 +1,10 @@
import * as Caret from "./caret";
-import * as LiveSpeed from "./live-speed";
-import * as LiveBurst from "./live-burst";
-import * as LiveAcc from "./live-acc";
-import * as TimerProgress from "./timer-progress";
import * as PageTransition from "../states/page-transition";
import { requestDebouncedAnimationFrame } from "../utils/debounced-animation-frame";
+import { createSignal } from "solid-js";
const unfocusPx = 3;
-let state = false;
+let [state, setState] = createSignal(false);
let cacheReady = false;
let cache: {
@@ -15,6 +12,10 @@ let cache: {
cursor?: HTMLElement[];
} = {};
+export function isFocused(): boolean {
+ return state();
+}
+
function initializeCache(): void {
if (cacheReady) return;
@@ -45,8 +46,8 @@ export function set(value: boolean, withCursor = false): void {
requestDebouncedAnimationFrame("focus.set", () => {
initializeCache();
- if (value && !state) {
- state = true;
+ if (value && !state()) {
+ setState(true);
// batch DOM operations for better performance
if (cache.focus) {
@@ -61,12 +62,8 @@ export function set(value: boolean, withCursor = false): void {
}
Caret.stopAnimation();
- LiveSpeed.show();
- LiveBurst.show();
- LiveAcc.show();
- TimerProgress.show();
- } else if (!value && state) {
- state = false;
+ } else if (!value && state()) {
+ setState(false);
if (cache.focus) {
for (const el of cache.focus) {
@@ -80,17 +77,13 @@ export function set(value: boolean, withCursor = false): void {
}
Caret.startAnimation();
- LiveSpeed.hide();
- LiveBurst.hide();
- LiveAcc.hide();
- TimerProgress.hide();
}
});
}
$(document).on("mousemove", function (event) {
if (PageTransition.get()) return;
- if (!state) return;
+ if (!state()) return;
if (
event.originalEvent &&
// To avoid mouse/desk vibration from creating a flashy effect, we'll unfocus @ >5px instead of >0px
diff --git a/frontend/src/ts/test/live-acc.ts b/frontend/src/ts/test/live-acc.ts
deleted file mode 100644
index 3158d0e36928..000000000000
--- a/frontend/src/ts/test/live-acc.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-import Config from "../config";
-import * as TestState from "../test/test-state";
-import * as ConfigEvent from "../observables/config-event";
-import { applyReducedMotion } from "../utils/misc";
-import { animate } from "animejs";
-import { requestDebouncedAnimationFrame } from "../utils/debounced-animation-frame";
-
-const textEl = document.querySelector(
- "#liveStatsTextBottom .liveAcc",
-) as HTMLElement;
-const miniEl = document.querySelector("#liveStatsMini .acc") as HTMLElement;
-
-export function update(acc: number): void {
- requestDebouncedAnimationFrame("live-acc.update", () => {
- let number = Math.floor(acc);
- if (Config.blindMode) {
- number = 100;
- }
- miniEl.innerHTML = number + "%";
- textEl.innerHTML = number + "%";
- });
-}
-
-export function reset(): void {
- requestDebouncedAnimationFrame("live-acc.reset", () => {
- miniEl.innerHTML = "100%";
- textEl.innerHTML = "100%";
- });
-}
-
-let state = false;
-
-export function show(): void {
- if (Config.liveAccStyle === "off") return;
- if (!TestState.isActive) return;
- if (state) return;
- requestDebouncedAnimationFrame("live-acc.show", () => {
- if (Config.liveAccStyle === "mini") {
- miniEl.classList.remove("hidden");
- animate(miniEl, {
- opacity: [0, 1],
- duration: applyReducedMotion(125),
- });
- } else {
- textEl.classList.remove("hidden");
- animate(textEl, {
- opacity: [0, 1],
- duration: applyReducedMotion(125),
- });
- }
- state = true;
- });
-}
-
-export function hide(): void {
- if (!state) return;
- requestDebouncedAnimationFrame("live-acc.hide", () => {
- animate(textEl, {
- opacity: [1, 0],
- duration: applyReducedMotion(125),
- onComplete: () => {
- textEl.classList.add("hidden");
- },
- });
- animate(miniEl, {
- opacity: [1, 0],
- duration: applyReducedMotion(125),
- onComplete: () => {
- miniEl.classList.add("hidden");
- },
- });
- state = false;
- });
-}
-
-export function instantHide(): void {
- if (!state) return;
-
- textEl.classList.add("hidden");
- textEl.style.opacity = "0";
- miniEl.classList.add("hidden");
- miniEl.style.opacity = "0";
-
- state = false;
-}
-
-ConfigEvent.subscribe(({ key, newValue }) => {
- if (key === "liveAccStyle") newValue === "off" ? hide() : show();
-});
diff --git a/frontend/src/ts/test/live-burst.ts b/frontend/src/ts/test/live-burst.ts
deleted file mode 100644
index b37537d5de30..000000000000
--- a/frontend/src/ts/test/live-burst.ts
+++ /dev/null
@@ -1,87 +0,0 @@
-import Config from "../config";
-import * as TestState from "../test/test-state";
-import * as ConfigEvent from "../observables/config-event";
-import Format from "../utils/format";
-import { applyReducedMotion } from "../utils/misc";
-import { animate } from "animejs";
-import { requestDebouncedAnimationFrame } from "../utils/debounced-animation-frame";
-
-const textEl = document.querySelector(
- "#liveStatsTextBottom .liveBurst",
-) as HTMLElement;
-const miniEl = document.querySelector("#liveStatsMini .burst") as HTMLElement;
-
-export function reset(): void {
- requestDebouncedAnimationFrame("live-burst.reset", () => {
- textEl.innerHTML = "0";
- miniEl.innerHTML = "0";
- });
-}
-
-export async function update(burst: number): Promise {
- requestDebouncedAnimationFrame("live-burst.update", () => {
- const burstText = Format.typingSpeed(burst, { showDecimalPlaces: false });
- miniEl.innerHTML = burstText;
- textEl.innerHTML = burstText;
- });
-}
-
-let state = false;
-
-export function show(): void {
- if (Config.liveBurstStyle === "off") return;
- if (!TestState.isActive) return;
- if (state) return;
- requestDebouncedAnimationFrame("live-burst.show", () => {
- if (Config.liveBurstStyle === "mini") {
- miniEl.classList.remove("hidden");
- animate(miniEl, {
- opacity: [0, 1],
- duration: applyReducedMotion(125),
- });
- } else {
- textEl.classList.remove("hidden");
- animate(textEl, {
- opacity: [0, 1],
- duration: applyReducedMotion(125),
- });
- }
- state = true;
- });
-}
-
-export function hide(): void {
- if (!state) return;
- requestDebouncedAnimationFrame("live-burst.hide", () => {
- animate(textEl, {
- opacity: [1, 0],
- duration: applyReducedMotion(125),
- onComplete: () => {
- textEl.classList.add("hidden");
- },
- });
- animate(miniEl, {
- opacity: [1, 0],
- duration: applyReducedMotion(125),
- onComplete: () => {
- miniEl.classList.add("hidden");
- },
- });
- state = false;
- });
-}
-
-export function instantHide(): void {
- if (!state) return;
-
- textEl.classList.add("hidden");
- textEl.style.opacity = "0";
- miniEl.classList.add("hidden");
- miniEl.style.opacity = "0";
-
- state = false;
-}
-
-ConfigEvent.subscribe(({ key, newValue }) => {
- if (key === "liveBurstStyle") newValue === "off" ? hide() : show();
-});
diff --git a/frontend/src/ts/test/live-speed.ts b/frontend/src/ts/test/live-speed.ts
deleted file mode 100644
index cef8273e4c04..000000000000
--- a/frontend/src/ts/test/live-speed.ts
+++ /dev/null
@@ -1,91 +0,0 @@
-import Config from "../config";
-import * as TestState from "./test-state";
-import * as ConfigEvent from "../observables/config-event";
-import Format from "../utils/format";
-import { applyReducedMotion } from "../utils/misc";
-import { requestDebouncedAnimationFrame } from "../utils/debounced-animation-frame";
-import { animate } from "animejs";
-
-const textElement = document.querySelector(
- "#liveStatsTextBottom .liveSpeed",
-) as HTMLElement;
-const miniElement = document.querySelector(
- "#liveStatsMini .speed",
-) as HTMLElement;
-
-export function reset(): void {
- requestDebouncedAnimationFrame("live-speed.reset", () => {
- textElement.innerHTML = "0";
- miniElement.innerHTML = "0";
- });
-}
-
-export function update(wpm: number, raw: number): void {
- requestDebouncedAnimationFrame("live-speed.update", () => {
- let number = wpm;
- if (Config.blindMode) {
- number = raw;
- }
- const numberText = Format.typingSpeed(number, { showDecimalPlaces: false });
- textElement.innerHTML = numberText;
- miniElement.innerHTML = numberText;
- });
-}
-
-let state = false;
-
-export function show(): void {
- if (Config.liveSpeedStyle === "off") return;
- if (!TestState.isActive) return;
- if (state) return;
- requestDebouncedAnimationFrame("live-speed.show", () => {
- if (Config.liveSpeedStyle === "mini") {
- miniElement.classList.remove("hidden");
- animate(miniElement, {
- opacity: [0, 1],
- duration: applyReducedMotion(125),
- });
- } else {
- textElement.classList.remove("hidden");
- animate(textElement, {
- opacity: [0, 1],
- duration: applyReducedMotion(125),
- });
- }
- state = true;
- });
-}
-
-export function hide(): void {
- if (!state) return;
- requestDebouncedAnimationFrame("live-speed.hide", () => {
- animate(miniElement, {
- opacity: [1, 0],
- duration: applyReducedMotion(125),
- onComplete: () => {
- miniElement.classList.add("hidden");
- },
- });
- animate(textElement, {
- opacity: [1, 0],
- duration: applyReducedMotion(125),
- onComplete: () => {
- textElement.classList.add("hidden");
- },
- });
- state = false;
- });
-}
-
-export function instantHide(): void {
- if (!state) return;
- miniElement.classList.add("hidden");
- miniElement.style.opacity = "0";
- textElement.classList.add("hidden");
- textElement.style.opacity = "0";
- state = false;
-}
-
-ConfigEvent.subscribe(({ key, newValue }) => {
- if (key === "liveSpeedStyle") newValue === "off" ? hide() : show();
-});
diff --git a/frontend/src/ts/test/monkey.ts b/frontend/src/ts/test/monkey.ts
index b1966c3e4c86..f05a6f0e2980 100644
--- a/frontend/src/ts/test/monkey.ts
+++ b/frontend/src/ts/test/monkey.ts
@@ -9,7 +9,7 @@ const monkeyEl = document.querySelector("#monkey") as HTMLElement;
const monkeyFastEl = document.querySelector("#monkey .fast") as HTMLElement;
ConfigEvent.subscribe(({ key }) => {
- if (key === "monkey" && TestState.isActive) {
+ if (key === "monkey" && TestState.isActive()) {
if (Config.monkey) {
monkeyEl.classList.remove("hidden");
} else {
diff --git a/frontend/src/ts/test/pace-caret.ts b/frontend/src/ts/test/pace-caret.ts
index da0b4d01cd40..8308495896d4 100644
--- a/frontend/src/ts/test/pace-caret.ts
+++ b/frontend/src/ts/test/pace-caret.ts
@@ -133,7 +133,7 @@ export async function update(expectedStepEnd: number): Promise {
const currentSettings = settings;
if (
currentSettings === null ||
- !TestState.isActive ||
+ !TestState.isActive() ||
TestState.resultVisible
) {
return;
diff --git a/frontend/src/ts/test/test-logic.ts b/frontend/src/ts/test/test-logic.ts
index 90138cefa18f..a01ef91b568b 100644
--- a/frontend/src/ts/test/test-logic.ts
+++ b/frontend/src/ts/test/test-logic.ts
@@ -151,7 +151,7 @@ export function restart(options = {} as RestartOptions): void {
const animationTime = options.noAnim ? 0 : Misc.applyReducedMotion(125);
const noQuit = isFunboxActive("no_quit");
- if (TestState.isActive && noQuit) {
+ if (TestState.isActive() && noQuit) {
Notifications.add("No quit funbox is active. Please finish the test.", 0, {
important: true,
});
@@ -196,7 +196,7 @@ export function restart(options = {} as RestartOptions): void {
}
}
- if (TestState.isActive) {
+ if (TestState.isActive()) {
if (TestState.isRepeated) {
options.withSameWordset = true;
}
@@ -221,7 +221,7 @@ export function restart(options = {} as RestartOptions): void {
TestWords.currentQuote !== null &&
Config.language.startsWith(TestWords.currentQuote.language) &&
Config.repeatQuotes === "typing" &&
- (TestState.isActive || failReason !== "")
+ (TestState.isActive() || failReason !== "")
) {
options.withSameWordset = true;
}
@@ -854,7 +854,7 @@ function buildCompletedEvent(
}
export async function finish(difficultyFailed = false): Promise {
- if (!TestState.isActive) return;
+ if (!TestState.isActive()) return;
TestUI.setResultCalculating(true);
const now = performance.now();
TestTimer.clear();
@@ -1404,7 +1404,7 @@ $(".pageTest").on("click", "#restartTestButton", () => {
ManualRestart.set();
if (TestUI.resultCalculating) return;
if (
- TestState.isActive &&
+ TestState.isActive() &&
Config.repeatQuotes === "typing" &&
Config.mode === "quote"
) {
diff --git a/frontend/src/ts/test/test-state.ts b/frontend/src/ts/test/test-state.ts
index 1b5079d9d377..6616b717c536 100644
--- a/frontend/src/ts/test/test-state.ts
+++ b/frontend/src/ts/test/test-state.ts
@@ -1,9 +1,10 @@
import { Challenge } from "@monkeytype/schemas/challenges";
import { promiseWithResolvers } from "../utils/misc";
+import { createSignal } from "solid-js";
export let isRepeated = false;
export let isPaceRepeat = false;
-export let isActive = false;
+export const [isActive, setActive] = createSignal(false);
export let activeChallenge: null | Challenge = null;
export let savingEnabled = true;
export let bailedOut = false;
@@ -23,10 +24,6 @@ export function setPaceRepeat(tf: boolean): void {
isPaceRepeat = tf;
}
-export function setActive(tf: boolean): void {
- isActive = tf;
-}
-
export function setActiveChallenge(val: null | Challenge): void {
activeChallenge = val;
}
diff --git a/frontend/src/ts/test/test-stats.ts b/frontend/src/ts/test/test-stats.ts
index 2644e4ee6a88..9d27941de477 100644
--- a/frontend/src/ts/test/test-stats.ts
+++ b/frontend/src/ts/test/test-stats.ts
@@ -160,7 +160,7 @@ export function calculateWpmAndRaw(
raw: number;
} {
const testSeconds = calculateTestSeconds(
- TestState.isActive ? performance.now() : end,
+ TestState.isActive() ? performance.now() : end,
);
const chars = countChars(final);
const wpm = Numbers.roundTo2(
@@ -256,7 +256,7 @@ function getInputWords(): string[] {
let inputWords = [...TestInput.input.getHistory()];
- if (TestState.isActive) {
+ if (TestState.isActive()) {
inputWords.push(TestInput.input.current);
}
@@ -276,7 +276,7 @@ function getTargetWords(): string[] {
: TestWords.words.list),
];
- if (TestState.isActive) {
+ if (TestState.isActive()) {
targetWords.push(
Config.mode === "zen"
? TestInput.input.current
diff --git a/frontend/src/ts/test/test-timer.ts b/frontend/src/ts/test/test-timer.ts
index d0921a0f9db8..093a3511dd9a 100644
--- a/frontend/src/ts/test/test-timer.ts
+++ b/frontend/src/ts/test/test-timer.ts
@@ -3,8 +3,6 @@
import Config, { setConfig } from "../config";
import * as CustomText from "./custom-text";
-import * as TimerProgress from "./timer-progress";
-import * as LiveSpeed from "./live-speed";
import * as TestStats from "./test-stats";
import * as TestInput from "./test-input";
import * as Monkey from "./monkey";
@@ -21,6 +19,8 @@ import * as SoundController from "../controllers/sound-controller";
import { clearLowFpsMode, setLowFpsMode } from "../anim";
import { createTimer } from "animejs";
import { requestDebouncedAnimationFrame } from "../utils/debounced-animation-frame";
+import Format from "../utils/format";
+import { setLiveStatWpm, updateProgressSignal } from "../signals/test";
let lastLoop = 0;
const newTimer = createTimer({
@@ -234,8 +234,12 @@ function timerStep(): void {
});
// already using raf
- TimerProgress.update();
- LiveSpeed.update(wpmAndRaw.wpm, wpmAndRaw.raw);
+ updateProgressSignal();
+ setLiveStatWpm(
+ Format.typingSpeed(Config.blindMode ? wpmAndRaw.raw : wpmAndRaw.wpm, {
+ showDecimalPlaces: false,
+ }),
+ );
//logic
if (Config.playTimeWarning !== "off") playTimeWarning();
@@ -303,7 +307,7 @@ async function _startOld(): Promise {
const drift = Math.abs(interval - delay);
checkIfTimerIsSlow(drift);
timer = setTimeout(function () {
- if (!TestState.isActive) {
+ if (!TestState.isActive()) {
if (timer !== null) clearTimeout(timer);
SlowTimer.clear();
slowTimerCount = 0;
diff --git a/frontend/src/ts/test/test-ui.ts b/frontend/src/ts/test/test-ui.ts
index 73c0110ff816..f5850d322541 100644
--- a/frontend/src/ts/test/test-ui.ts
+++ b/frontend/src/ts/test/test-ui.ts
@@ -16,7 +16,6 @@ import * as Hangul from "hangul-js";
import * as ResultWordHighlight from "../elements/result-word-highlight";
import * as ActivePage from "../states/active-page";
import Format from "../utils/format";
-import { TimerColor, TimerOpacity } from "@monkeytype/schemas/configs";
import { convertRemToPixels } from "../utils/numbers";
import {
findSingleActiveFunboxWithFunction,
@@ -32,11 +31,7 @@ import * as SoundController from "../controllers/sound-controller";
import * as Numbers from "@monkeytype/util/numbers";
import * as TestStats from "./test-stats";
import * as KeymapEvent from "../observables/keymap-event";
-import * as LiveAcc from "./live-acc";
import * as Focus from "../test/focus";
-import * as TimerProgress from "../test/timer-progress";
-import * as LiveBurst from "./live-burst";
-import * as LiveSpeed from "./live-speed";
import * as Monkey from "./monkey";
import { animate } from "animejs";
import {
@@ -58,6 +53,14 @@ import * as ModesNotice from "../elements/modes-notice";
import * as Last10Average from "../elements/last-10-average";
import * as MemoryFunboxTimer from "./funbox/memory-funbox-timer";
import { qsr } from "../utils/dom";
+import {
+ setLiveProgress,
+ setLiveStatAcc,
+ setLiveStatBurst,
+ setLiveStatWpm,
+ setStatsVisible,
+ updateProgressSignal,
+} from "../signals/test";
export const updateHintsPositionDebounced = Misc.debounceUntilResolved(
updateHintsPosition,
@@ -85,7 +88,7 @@ export function focusWords(force = false): void {
blurInputElement();
}
focusInputElement(true);
- if (TestState.isActive) {
+ if (TestState.isActive()) {
keepWordsInputInTheCenter(true);
} else {
const typingTest = document.querySelector("#typingTest");
@@ -1583,48 +1586,6 @@ function updateLiveStatsMargin(): void {
}
}
-function updateLiveStatsOpacity(value: TimerOpacity): void {
- $("#barTimerProgress").css("opacity", parseFloat(value as string));
- $("#liveStatsTextTop").css("opacity", parseFloat(value as string));
- $("#liveStatsTextBottom").css("opacity", parseFloat(value as string));
- $("#liveStatsMini").css("opacity", parseFloat(value as string));
-}
-
-function updateLiveStatsColor(value: TimerColor): void {
- $("#barTimerProgress").removeClass("timerSub");
- $("#barTimerProgress").removeClass("timerText");
- $("#barTimerProgress").removeClass("timerMain");
-
- $("#liveStatsTextTop").removeClass("timerSub");
- $("#liveStatsTextTop").removeClass("timerText");
- $("#liveStatsTextTop").removeClass("timerMain");
-
- $("#liveStatsTextBottom").removeClass("timerSub");
- $("#liveStatsTextBottom").removeClass("timerText");
- $("#liveStatsTextBottom").removeClass("timerMain");
-
- $("#liveStatsMini").removeClass("timerSub");
- $("#liveStatsMini").removeClass("timerText");
- $("#liveStatsMini").removeClass("timerMain");
-
- if (value === "main") {
- $("#barTimerProgress").addClass("timerMain");
- $("#liveStatsTextTop").addClass("timerMain");
- $("#liveStatsTextBottom").addClass("timerMain");
- $("#liveStatsMini").addClass("timerMain");
- } else if (value === "sub") {
- $("#barTimerProgress").addClass("timerSub");
- $("#liveStatsTextTop").addClass("timerSub");
- $("#liveStatsTextBottom").addClass("timerSub");
- $("#liveStatsMini").addClass("timerSub");
- } else if (value === "text") {
- $("#barTimerProgress").addClass("timerText");
- $("#liveStatsTextTop").addClass("timerText");
- $("#liveStatsTextBottom").addClass("timerText");
- $("#liveStatsMini").addClass("timerText");
- }
-}
-
function showHideTestRestartButton(showHide: boolean): void {
if (showHide) {
$(".pageTest #restartTestButton").removeClass("hidden");
@@ -1680,10 +1641,13 @@ function afterAnyTestInput(
}
const acc: number = Numbers.roundTo2(TestStats.calculateAccuracy());
- if (!isNaN(acc)) LiveAcc.update(acc);
+ if (!isNaN(acc)) {
+ setLiveStatAcc(Format.percentage(Config.blindMode ? 100 : acc));
+ }
if (Config.mode !== "time") {
- TimerProgress.update();
+ // TimerProgress.update();
+ updateProgressSignal();
}
if (Config.keymapMode === "next") {
@@ -1784,7 +1748,9 @@ export async function afterTestWordChange(
const lastBurst = TestInput.burstHistory[TestInput.burstHistory.length - 1];
if (Numbers.isSafeNumber(lastBurst)) {
- void LiveBurst.update(Math.round(lastBurst));
+ setLiveStatBurst(
+ Format.typingSpeed(lastBurst, { showDecimalPlaces: false }),
+ );
}
if (direction === "forward") {
//
@@ -1812,11 +1778,11 @@ export async function afterTestWordChange(
export function onTestStart(): void {
Focus.set(true);
Monkey.show();
- TimerProgress.show();
- LiveSpeed.show();
- LiveAcc.show();
- LiveBurst.show();
- TimerProgress.update();
+ updateProgressSignal();
+ setStatsVisible({
+ visible: true,
+ animate: true,
+ });
}
export function onTestRestart(source: "testPage" | "resultPage"): void {
@@ -1825,14 +1791,14 @@ export function onTestRestart(source: "testPage" | "resultPage"): void {
getInputElement().style.left = "0";
TestConfig.show();
Focus.set(false);
- LiveSpeed.instantHide();
- LiveSpeed.reset();
- LiveBurst.instantHide();
- LiveBurst.reset();
- LiveAcc.instantHide();
- LiveAcc.reset();
- TimerProgress.instantHide();
- TimerProgress.reset();
+ setStatsVisible({
+ visible: false,
+ animate: false,
+ });
+ setLiveProgress("0");
+ setLiveStatWpm("0");
+ setLiveStatBurst("0");
+ setLiveStatAcc("100%");
Monkey.instantHide();
LayoutfluidFunboxTimer.instantHide();
updatePremid();
@@ -1875,15 +1841,15 @@ export function onTestRestart(source: "testPage" | "resultPage"): void {
export function onTestFinish(): void {
Caret.hide();
- LiveSpeed.hide();
- LiveAcc.hide();
- LiveBurst.hide();
- TimerProgress.hide();
OutOfFocus.hide();
Monkey.hide();
if (Config.playSoundOnClick === "16") {
void SoundController.playFartReverb();
}
+ setStatsVisible({
+ visible: false,
+ animate: true,
+ });
}
$(".pageTest #copyWordsListButton").on("click", async () => {
@@ -1994,12 +1960,6 @@ ConfigEvent.subscribe(({ key, newValue }) => {
if (key === "quickRestart") {
showHideTestRestartButton(newValue === "off");
}
- if (key === "timerOpacity") {
- updateLiveStatsOpacity(newValue);
- }
- if (key === "timerColor") {
- updateLiveStatsColor(newValue);
- }
if (key === "showOutOfFocusWarning" && !newValue) {
OutOfFocus.hide();
}
diff --git a/frontend/src/ts/test/timer-progress.ts b/frontend/src/ts/test/timer-progress.ts
deleted file mode 100644
index a1fe882caa08..000000000000
--- a/frontend/src/ts/test/timer-progress.ts
+++ /dev/null
@@ -1,269 +0,0 @@
-import Config from "../config";
-import * as CustomText from "./custom-text";
-import * as DateTime from "../utils/date-and-time";
-import * as TestWords from "./test-words";
-import * as TestInput from "./test-input";
-import * as Time from "../states/time";
-import * as TestState from "./test-state";
-import * as ConfigEvent from "../observables/config-event";
-import { applyReducedMotion } from "../utils/misc";
-import { requestDebouncedAnimationFrame } from "../utils/debounced-animation-frame";
-import { animate } from "animejs";
-
-const barEl = document.querySelector("#barTimerProgress .bar") as HTMLElement;
-const barOpacityEl = document.querySelector(
- "#barTimerProgress .opacityWrapper",
-) as HTMLElement;
-const textEl = document.querySelector(
- "#liveStatsTextTop .timerProgress",
-) as HTMLElement;
-const miniEl = document.querySelector("#liveStatsMini .time") as HTMLElement;
-
-export function show(): void {
- if (!TestState.isActive) return;
- requestDebouncedAnimationFrame("timer-progress.show", () => {
- if (Config.mode !== "zen" && Config.timerStyle === "bar") {
- animate(barOpacityEl, {
- opacity: [0, 1],
- duration: applyReducedMotion(125),
- onBegin: () => {
- barOpacityEl.classList.remove("hidden");
- },
- });
- } else if (Config.timerStyle === "text") {
- animate(textEl, {
- opacity: [0, 1],
- duration: applyReducedMotion(125),
- onBegin: () => {
- textEl.classList.remove("hidden");
- },
- });
- } else if (Config.timerStyle === "flash_mini") {
- animate(miniEl, {
- opacity: [0, 1],
- duration: applyReducedMotion(125),
- onBegin: () => {
- miniEl.classList.remove("hidden");
- },
- });
- } else if (Config.timerStyle === "flash_text") {
- animate(textEl, {
- opacity: [0, 1],
- duration: applyReducedMotion(125),
- onBegin: () => {
- textEl.classList.remove("hidden");
- },
- });
- } else if (Config.mode === "zen" || Config.timerStyle === "mini") {
- animate(miniEl, {
- opacity: [0, 1],
- duration: applyReducedMotion(125),
- onBegin: () => {
- miniEl.classList.remove("hidden");
- },
- });
- }
- });
-}
-
-export function reset(): void {
- requestDebouncedAnimationFrame("timer-progress.reset", () => {
- let width = "0vw";
- if (
- Config.mode === "time" ||
- (Config.mode === "custom" && CustomText.getLimitMode() === "time")
- ) {
- width = "100vw";
- }
-
- animate(barEl, {
- width,
- duration: 0,
- });
- miniEl.textContent = "0";
- textEl.textContent = "0";
- });
-}
-
-export function hide(): void {
- requestDebouncedAnimationFrame("timer-progress.hide", () => {
- animate(barOpacityEl, {
- opacity: 0,
- duration: applyReducedMotion(125),
- });
-
- animate(miniEl, {
- opacity: 0,
- duration: applyReducedMotion(125),
- onComplete: () => {
- miniEl.classList.add("hidden");
- },
- });
-
- animate(textEl, {
- opacity: 0,
- duration: applyReducedMotion(125),
- onComplete: () => {
- textEl.classList.add("hidden");
- },
- });
- });
-}
-
-export function instantHide(): void {
- barOpacityEl.style.opacity = "0";
-
- miniEl.classList.add("hidden");
- miniEl.style.opacity = "0";
-
- textEl.classList.add("hidden");
- textEl.style.opacity = "0";
-}
-
-function getCurrentCount(): number {
- if (Config.mode === "custom" && CustomText.getLimitMode() === "section") {
- return (
- (TestWords.words.sectionIndexList[TestState.activeWordIndex] as number) -
- 1
- );
- } else {
- return TestInput.input.getHistory().length;
- }
-}
-
-export function update(): void {
- requestDebouncedAnimationFrame("timer-progress.update", () => {
- const time = Time.get();
- if (
- Config.mode === "time" ||
- (Config.mode === "custom" && CustomText.getLimitMode() === "time")
- ) {
- let maxtime = Config.time;
- if (Config.mode === "custom" && CustomText.getLimitMode() === "time") {
- maxtime = CustomText.getLimitValue();
- }
- if (Config.timerStyle === "bar") {
- const percent = 100 - ((time + 1) / maxtime) * 100;
-
- animate(barEl, {
- width: percent + "vw",
- duration: 1000,
- ease: "linear",
- });
- } else if (Config.timerStyle === "text") {
- let displayTime = DateTime.secondsToString(maxtime - time);
- if (maxtime === 0) {
- displayTime = DateTime.secondsToString(time);
- }
- if (textEl !== null) {
- textEl.innerHTML = "" + displayTime + "
";
- }
- } else if (Config.timerStyle === "flash_mini") {
- let displayTime = DateTime.secondsToString(maxtime - time);
- if (maxtime === 0) {
- displayTime = DateTime.secondsToString(time);
- }
- if (miniEl !== null) {
- if ((maxtime - time) % 15 !== 0) {
- miniEl.style.opacity = "0";
- } else {
- miniEl.style.opacity = "1";
- }
- miniEl.innerHTML = "" + displayTime + "
";
- }
- } else if (Config.timerStyle === "flash_text") {
- let displayTime = DateTime.secondsToString(maxtime - time);
- if (maxtime === 0) {
- displayTime = DateTime.secondsToString(time);
- }
- if (textEl !== null) {
- textEl.innerHTML =
- "" +
- `${(maxtime - time) % 15 !== 0 ? "" : displayTime}` +
- "
";
- }
- } else if (Config.timerStyle === "mini") {
- let displayTime = DateTime.secondsToString(maxtime - time);
- if (maxtime === 0) {
- displayTime = DateTime.secondsToString(time);
- }
- if (miniEl !== null) {
- miniEl.innerHTML = displayTime;
- }
- }
- } else if (
- Config.mode === "words" ||
- Config.mode === "custom" ||
- Config.mode === "quote"
- ) {
- let outof = TestWords.words.length;
- if (Config.mode === "words") {
- outof = Config.words;
- }
- if (Config.mode === "custom") {
- outof = CustomText.getLimitValue();
- }
- if (Config.mode === "quote") {
- outof = TestWords.currentQuote?.textSplit.length ?? 1;
- }
- if (Config.timerStyle === "bar") {
- const percent = Math.floor(
- ((TestState.activeWordIndex + 1) / outof) * 100,
- );
-
- animate(barEl, {
- width: percent + "vw",
- duration: 250,
- });
- } else if (Config.timerStyle === "text") {
- if (outof === 0) {
- textEl.innerHTML = `${TestInput.input.getHistory().length}
`;
- } else {
- textEl.innerHTML = `${getCurrentCount()}/${outof}
`;
- }
- } else if (Config.timerStyle === "flash_mini") {
- if (outof === 0) {
- miniEl.innerHTML = `${TestInput.input.getHistory().length}`;
- } else {
- miniEl.innerHTML = `${getCurrentCount()}/${outof}`;
- }
- } else if (Config.timerStyle === "flash_text") {
- if (outof === 0) {
- textEl.innerHTML = `${TestInput.input.getHistory().length}
`;
- } else {
- textEl.innerHTML = `${getCurrentCount()}/${outof}
`;
- }
- } else if (Config.timerStyle === "mini") {
- if (outof === 0) {
- miniEl.innerHTML = `${TestInput.input.getHistory().length}`;
- } else {
- miniEl.innerHTML = `${getCurrentCount()}/${outof}`;
- }
- }
- } else if (Config.mode === "zen") {
- if (Config.timerStyle === "text") {
- textEl.innerHTML = `${TestInput.input.getHistory().length}
`;
- } else if (Config.timerStyle === "flash_mini") {
- miniEl.innerHTML = `${TestInput.input.getHistory().length}`;
- } else if (Config.timerStyle === "flash_text") {
- textEl.innerHTML = `${TestInput.input.getHistory().length}
`;
- } else {
- miniEl.innerHTML = `${TestInput.input.getHistory().length}`;
- }
- }
- });
-}
-
-export function updateStyle(): void {
- if (!TestState.isActive) return;
- hide();
- update();
- if (Config.timerStyle === "off") return;
- setTimeout(() => {
- show();
- }, 125);
-}
-
-ConfigEvent.subscribe(({ key }) => {
- if (key === "timerStyle") updateStyle();
-});
diff --git a/frontend/src/ts/ui.ts b/frontend/src/ts/ui.ts
index 568a21cb1f50..39d2ed126dee 100644
--- a/frontend/src/ts/ui.ts
+++ b/frontend/src/ts/ui.ts
@@ -81,7 +81,7 @@ window.addEventListener("beforeunload", (event) => {
) {
//ignore
} else {
- if (TestState.isActive) {
+ if (TestState.isActive()) {
event.preventDefault();
// Included for legacy support, e.g. Chrome/Edge < 119
// oxlint-disable-next-line no-deprecated
diff --git a/frontend/src/ts/utils/accessibility.ts b/frontend/src/ts/utils/accessibility.ts
new file mode 100644
index 000000000000..9e9387b8d683
--- /dev/null
+++ b/frontend/src/ts/utils/accessibility.ts
@@ -0,0 +1,12 @@
+export function prefersReducedMotion(): boolean {
+ return matchMedia?.("(prefers-reduced-motion)")?.matches;
+}
+
+/**
+ * Reduce the animation time based on the browser preference `prefers-reduced-motion`.
+ * @param animationTime
+ * @returns `0` if user prefers reduced-motion, else the given animationTime
+ */
+export function applyReducedMotion(animationTime: number): number {
+ return prefersReducedMotion() ? 0 : animationTime;
+}
diff --git a/frontend/src/ts/utils/misc.ts b/frontend/src/ts/utils/misc.ts
index 6e6ea8fca4ca..a6f034115c40 100644
--- a/frontend/src/ts/utils/misc.ts
+++ b/frontend/src/ts/utils/misc.ts
@@ -8,6 +8,7 @@ import { RankAndCount } from "@monkeytype/schemas/users";
import { roundTo2 } from "@monkeytype/util/numbers";
import { animate, AnimationParams } from "animejs";
import { ElementWithUtils } from "./dom";
+import * as Accessibility from "./accessibility";
export function whorf(speed: number, wordlen: number): number {
return Math.min(
@@ -581,17 +582,13 @@ export function isObject(obj: unknown): obj is Record {
return typeof obj === "object" && !Array.isArray(obj) && obj !== null;
}
-export function prefersReducedMotion(): boolean {
- return matchMedia?.("(prefers-reduced-motion)")?.matches;
-}
-
/**
* Reduce the animation time based on the browser preference `prefers-reduced-motion`.
* @param animationTime
* @returns `0` if user prefers reduced-motion, else the given animationTime
*/
export function applyReducedMotion(animationTime: number): number {
- return prefersReducedMotion() ? 0 : animationTime;
+ return Accessibility.applyReducedMotion(animationTime);
}
/**
diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json
index df28ff992246..6c428d580e54 100644
--- a/frontend/tsconfig.json
+++ b/frontend/tsconfig.json
@@ -13,13 +13,16 @@
"./src/ts/types/virtual-language-hashes.d.ts"
],
"virtual:env-config": ["./src/ts/types/virtual-env-config.d.ts"]
- }
+ },
+ "jsx": "preserve",
+ "jsxImportSource": "solid-js"
},
"include": [
"./src/**/*.ts",
+ "./src/**/*.tsx",
"./scripts/**/*.ts",
"vite-plugins/**/*.ts",
"vite.config.ts"
],
- "exclude": ["node_modules", "build", "setup-tests.ts", "**/*.spec.ts"]
+ "exclude": ["node_modules", "build", "setup-tests.ts", "./__tests__/**/*.*"]
}
diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts
index 0b81b5466492..7f8e9c047c55 100644
--- a/frontend/vite.config.ts
+++ b/frontend/vite.config.ts
@@ -28,6 +28,7 @@ import replace from "vite-plugin-filter-replace";
// eslint-disable-next-line import/no-unresolved
import UnpluginInjectPreload from "unplugin-inject-preload/vite";
import { KnownFontName } from "@monkeytype/schemas/fonts";
+import solid from "vite-plugin-solid";
export default defineConfig(({ mode }): UserConfig => {
const env = loadEnv(mode, process.cwd(), "");
@@ -88,6 +89,7 @@ function getPlugins({
}),
jqueryInject(),
injectHTML(),
+ solid(),
];
const devPlugins: PluginOption[] = [Inspect()];
diff --git a/frontend/vitest.config.ts b/frontend/vitest.config.ts
index 1b720dddc1b0..05081b32ecef 100644
--- a/frontend/vitest.config.ts
+++ b/frontend/vitest.config.ts
@@ -1,10 +1,12 @@
import { defineConfig, UserWorkspaceConfig } from "vitest/config";
import { languageHashes } from "./vite-plugins/language-hashes";
import { envConfig } from "./vite-plugins/env-config";
+import solidPlugin from "vite-plugin-solid";
const plugins = [
languageHashes({ skip: true }),
envConfig({ isDevelopment: true, clientVersion: "TESTING", env: {} }),
+ solidPlugin(),
];
export const projects: UserWorkspaceConfig[] = [
@@ -12,7 +14,7 @@ export const projects: UserWorkspaceConfig[] = [
test: {
name: { label: "unit", color: "blue" },
include: ["__tests__/**/*.spec.ts"],
- exclude: ["__tests__/**/*.jsdom-spec.ts"],
+ exclude: ["__tests__/**/*.jsdom-spec.{ts,tsx}"],
environment: "happy-dom",
globalSetup: "__tests__/global-setup.ts",
setupFiles: ["__tests__/setup-tests.ts"],
@@ -22,20 +24,22 @@ export const projects: UserWorkspaceConfig[] = [
{
test: {
name: { label: "jsdom", color: "yellow" },
- include: ["__tests__/**/*.jsdom-spec.ts"],
+ include: ["__tests__/**/*.jsdom-spec.{ts,tsx}"],
exclude: ["__tests__/**/*.spec.ts"],
environment: "happy-dom",
globalSetup: "__tests__/global-setup.ts",
setupFiles: ["__tests__/setup-jsdom.ts"],
+ globals: true,
},
- plugins,
+ plugins: [solidPlugin()],
},
];
export default defineConfig({
+ plugins,
test: {
projects: projects,
coverage: {
- include: ["**/*.ts"],
+ include: ["**/*.{ts,tsx}"],
},
deps: {
optimizer: {
diff --git a/package.json b/package.json
index aa1d0b896aa2..a69cd880458f 100644
--- a/package.json
+++ b/package.json
@@ -76,7 +76,7 @@
"*": [
"oxfmt --no-error-on-unmatched-pattern"
],
- "*.{ts,js}": [
+ "*.{ts,tsx,js}": [
"oxlint --type-aware --type-check"
]
},
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 83e4030ce3af..c8a7514ad98b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -19,7 +19,7 @@ importers:
version: link:packages/release
'@vitest/coverage-v8':
specifier: 4.0.15
- version: 4.0.15(vitest@4.0.15(@types/node@20.5.1)(happy-dom@20.0.10)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1))
+ version: 4.0.15(vitest@4.0.15(@types/node@20.5.1)(happy-dom@20.0.10)(jsdom@27.4.0)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1))
conventional-changelog:
specifier: 6.0.0
version: 6.0.0(conventional-commits-filter@5.0.0)
@@ -52,7 +52,7 @@ importers:
version: 2.5.6
vitest:
specifier: 4.0.15
- version: 4.0.15(@types/node@20.5.1)(happy-dom@20.0.10)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
+ version: 4.0.15(@types/node@20.5.1)(happy-dom@20.0.10)(jsdom@27.4.0)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
backend:
dependencies:
@@ -224,7 +224,7 @@ importers:
version: 10.0.0
'@vitest/coverage-v8':
specifier: 4.0.15
- version: 4.0.15(vitest@4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1))
+ version: 4.0.15(vitest@4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(jsdom@27.4.0)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1))
concurrently:
specifier: 8.2.2
version: 8.2.2
@@ -254,7 +254,7 @@ importers:
version: 5.9.3
vitest:
specifier: 4.0.15
- version: 4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
+ version: 4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(jsdom@27.4.0)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
frontend:
dependencies:
@@ -370,9 +370,15 @@ importers:
'@monkeytype/typescript-config':
specifier: workspace:*
version: link:../packages/typescript-config
+ '@solidjs/testing-library':
+ specifier: 0.8.10
+ version: 0.8.10(solid-js@1.9.10)
'@testing-library/dom':
specifier: 10.4.1
version: 10.4.1
+ '@testing-library/jest-dom':
+ specifier: 6.9.1
+ version: 6.9.1
'@testing-library/user-event':
specifier: 14.6.1
version: 14.6.1(@testing-library/dom@10.4.1)
@@ -405,7 +411,7 @@ importers:
version: 5.0.2
'@vitest/coverage-v8':
specifier: 4.0.15
- version: 4.0.15(vitest@4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1))
+ version: 4.0.15(vitest@4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(jsdom@27.4.0)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1))
autoprefixer:
specifier: 10.4.20
version: 10.4.20(postcss@8.4.31)
@@ -448,6 +454,9 @@ importers:
sass:
specifier: 1.70.0
version: 1.70.0
+ solid-js:
+ specifier: 1.9.10
+ version: 1.9.10
subset-font:
specifier: 2.3.0
version: 2.3.0
@@ -480,10 +489,13 @@ importers:
version: 2.1.0(vite@7.1.12(@types/node@24.9.1)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1))
vite-plugin-pwa:
specifier: 1.1.0
- version: 1.1.0(vite@7.1.12(@types/node@24.9.1)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1))(workbox-build@7.1.1)(workbox-window@7.1.0)
+ version: 1.1.0(vite@7.1.12(@types/node@24.9.1)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.1.0)
+ vite-plugin-solid:
+ specifier: 2.11.10
+ version: 2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.10)(vite@7.1.12(@types/node@24.9.1)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1))
vitest:
specifier: 4.0.15
- version: 4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
+ version: 4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(jsdom@27.4.0)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
packages/contracts:
dependencies:
@@ -520,7 +532,7 @@ importers:
version: 5.9.3
vitest:
specifier: 4.0.15
- version: 4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
+ version: 4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(jsdom@27.4.0)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
packages/funbox:
dependencies:
@@ -554,7 +566,7 @@ importers:
version: 5.9.3
vitest:
specifier: 4.0.15
- version: 4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
+ version: 4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(jsdom@27.4.0)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
packages/oxlint-config: {}
@@ -609,7 +621,7 @@ importers:
version: 5.9.3
vitest:
specifier: 4.0.15
- version: 4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
+ version: 4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(jsdom@27.4.0)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
packages/tsup-config:
dependencies:
@@ -657,16 +669,18 @@ importers:
version: 5.9.3
vitest:
specifier: 4.0.15
- version: 4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
+ version: 4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(jsdom@27.4.0)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
zod:
specifier: 3.23.8
version: 3.23.8
packages:
- '@ampproject/remapping@2.3.0':
- resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
- engines: {node: '>=6.0.0'}
+ '@acemir/cssom@0.9.30':
+ resolution: {integrity: sha512-9CnlMCI0LmCIq0olalQqdWrJHPzm0/tw3gzOA9zJSgvFX7Xau3D24mAGa4BtwxwY69nsuJW6kQqqCzf/mEcQgg==}
+
+ '@adobe/css-tools@4.4.4':
+ resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==}
'@anatine/zod-openapi@1.14.2':
resolution: {integrity: sha512-q0qHfnuNYVKu0Swrnnvfj9971AEyW7c8v9jCOZGCl5ZbyGMNG4RPyJkRcMi/JC8CRfdOe0IDfNm1nNsi2avprg==}
@@ -683,30 +697,27 @@ packages:
'@apidevtools/json-schema-ref-parser@9.1.2':
resolution: {integrity: sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==}
+ '@asamuzakjp/css-color@4.1.1':
+ resolution: {integrity: sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ==}
+
+ '@asamuzakjp/dom-selector@6.7.6':
+ resolution: {integrity: sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg==}
+
+ '@asamuzakjp/nwsapi@2.3.9':
+ resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==}
+
'@babel/code-frame@7.27.1':
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
engines: {node: '>=6.9.0'}
- '@babel/compat-data@7.25.2':
- resolution: {integrity: sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==}
- engines: {node: '>=6.9.0'}
-
'@babel/compat-data@7.28.5':
resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==}
engines: {node: '>=6.9.0'}
- '@babel/core@7.25.2':
- resolution: {integrity: sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==}
- engines: {node: '>=6.9.0'}
-
'@babel/core@7.28.5':
resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==}
engines: {node: '>=6.9.0'}
- '@babel/generator@7.25.0':
- resolution: {integrity: sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==}
- engines: {node: '>=6.9.0'}
-
'@babel/generator@7.28.5':
resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==}
engines: {node: '>=6.9.0'}
@@ -715,10 +726,6 @@ packages:
resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==}
engines: {node: '>=6.9.0'}
- '@babel/helper-compilation-targets@7.25.2':
- resolution: {integrity: sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==}
- engines: {node: '>=6.9.0'}
-
'@babel/helper-compilation-targets@7.27.2':
resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==}
engines: {node: '>=6.9.0'}
@@ -748,20 +755,14 @@ packages:
resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==}
engines: {node: '>=6.9.0'}
- '@babel/helper-module-imports@7.24.7':
- resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==}
+ '@babel/helper-module-imports@7.18.6':
+ resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==}
engines: {node: '>=6.9.0'}
'@babel/helper-module-imports@7.27.1':
resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==}
engines: {node: '>=6.9.0'}
- '@babel/helper-module-transforms@7.25.2':
- resolution: {integrity: sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0
-
'@babel/helper-module-transforms@7.28.3':
resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==}
engines: {node: '>=6.9.0'}
@@ -788,10 +789,6 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0
- '@babel/helper-simple-access@7.24.7':
- resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==}
- engines: {node: '>=6.9.0'}
-
'@babel/helper-skip-transparent-expression-wrappers@7.27.1':
resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==}
engines: {node: '>=6.9.0'}
@@ -804,10 +801,6 @@ packages:
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
engines: {node: '>=6.9.0'}
- '@babel/helper-validator-option@7.24.8':
- resolution: {integrity: sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==}
- engines: {node: '>=6.9.0'}
-
'@babel/helper-validator-option@7.27.1':
resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
engines: {node: '>=6.9.0'}
@@ -816,10 +809,6 @@ packages:
resolution: {integrity: sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==}
engines: {node: '>=6.9.0'}
- '@babel/helpers@7.25.0':
- resolution: {integrity: sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==}
- engines: {node: '>=6.9.0'}
-
'@babel/helpers@7.28.4':
resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==}
engines: {node: '>=6.9.0'}
@@ -877,6 +866,12 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
+ '@babel/plugin-syntax-jsx@7.27.1':
+ resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
'@babel/plugin-syntax-unicode-sets-regex@7.18.6':
resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==}
engines: {node: '>=6.9.0'}
@@ -1208,18 +1203,10 @@ packages:
resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==}
engines: {node: '>=6.9.0'}
- '@babel/template@7.25.0':
- resolution: {integrity: sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==}
- engines: {node: '>=6.9.0'}
-
'@babel/template@7.27.2':
resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
engines: {node: '>=6.9.0'}
- '@babel/traverse@7.25.2':
- resolution: {integrity: sha512-s4/r+a7xTnny2O6FcZzqgT6nE4/GHEdcqj4qAeglbUOh0TeglEfmNJFAd/OLoVtGd6ZhAO8GCVvCNUO5t/VJVQ==}
- engines: {node: '>=6.9.0'}
-
'@babel/traverse@7.28.5':
resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==}
engines: {node: '>=6.9.0'}
@@ -1332,6 +1319,38 @@ packages:
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
engines: {node: '>=12'}
+ '@csstools/color-helpers@5.1.0':
+ resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==}
+ engines: {node: '>=18'}
+
+ '@csstools/css-calc@2.1.4':
+ resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^3.0.5
+ '@csstools/css-tokenizer': ^3.0.4
+
+ '@csstools/css-color-parser@3.1.0':
+ resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^3.0.5
+ '@csstools/css-tokenizer': ^3.0.4
+
+ '@csstools/css-parser-algorithms@3.0.5':
+ resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@csstools/css-tokenizer': ^3.0.4
+
+ '@csstools/css-syntax-patches-for-csstree@1.0.23':
+ resolution: {integrity: sha512-YEmgyklR6l/oKUltidNVYdjSmLSW88vMsKx0pmiS3r71s8ZZRpd8A0Yf0U+6p/RzElmMnPBv27hNWjDQMSZRtQ==}
+ engines: {node: '>=18'}
+
+ '@csstools/css-tokenizer@3.0.4':
+ resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==}
+ engines: {node: '>=18'}
+
'@dabh/diagnostics@2.0.3':
resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==}
@@ -1842,6 +1861,15 @@ packages:
resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@exodus/bytes@1.8.0':
+ resolution: {integrity: sha512-8JPn18Bcp8Uo1T82gR8lh2guEOa5KKU/IEKvvdp0sgmi7coPBWf1Doi1EXsGZb2ehc8ym/StJCjffYV+ne7sXQ==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+ peerDependencies:
+ '@exodus/crypto': ^1.0.0-rc.4
+ peerDependenciesMeta:
+ '@exodus/crypto':
+ optional: true
+
'@exodus/schemasafe@1.3.0':
resolution: {integrity: sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==}
@@ -3107,6 +3135,16 @@ packages:
engines: {node: '>=8.10'}
hasBin: true
+ '@solidjs/testing-library@0.8.10':
+ resolution: {integrity: sha512-qdeuIerwyq7oQTIrrKvV0aL9aFeuwTd86VYD3afdq5HYEwoox1OBTJy4y8A3TFZr8oAR0nujYgCzY/8wgHGfeQ==}
+ engines: {node: '>= 14'}
+ peerDependencies:
+ '@solidjs/router': '>=0.9.0'
+ solid-js: '>=1.0.0'
+ peerDependenciesMeta:
+ '@solidjs/router':
+ optional: true
+
'@standard-schema/spec@1.0.0':
resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==}
@@ -3117,6 +3155,10 @@ packages:
resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==}
engines: {node: '>=18'}
+ '@testing-library/jest-dom@6.9.1':
+ resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==}
+ engines: {node: '>=14', npm: '>=6', yarn: '>=1'}
+
'@testing-library/user-event@14.6.1':
resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==}
engines: {node: '>=12', npm: '>=6'}
@@ -3188,6 +3230,18 @@ packages:
'@types/aria-query@5.0.4':
resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
+ '@types/babel__core@7.20.5':
+ resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
+
+ '@types/babel__generator@7.27.0':
+ resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==}
+
+ '@types/babel__template@7.4.4':
+ resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
+
+ '@types/babel__traverse@7.28.0':
+ resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==}
+
'@types/bcrypt@5.0.2':
resolution: {integrity: sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ==}
@@ -3524,6 +3578,10 @@ packages:
resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==}
engines: {node: '>= 14'}
+ agent-base@7.1.4:
+ resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
+ engines: {node: '>= 14'}
+
aggregate-error@3.1.0:
resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
engines: {node: '>=8'}
@@ -3742,6 +3800,11 @@ packages:
b4a@1.6.6:
resolution: {integrity: sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==}
+ babel-plugin-jsx-dom-expressions@0.40.3:
+ resolution: {integrity: sha512-5HOwwt0BYiv/zxl7j8Pf2bGL6rDXfV6nUhLs8ygBX+EFJXzBPHM/euj9j/6deMZ6wa52Wb2PBaAV5U/jKwIY1w==}
+ peerDependencies:
+ '@babel/core': ^7.20.12
+
babel-plugin-polyfill-corejs2@0.4.14:
resolution: {integrity: sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==}
peerDependencies:
@@ -3757,6 +3820,15 @@ packages:
peerDependencies:
'@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
+ babel-preset-solid@1.9.10:
+ resolution: {integrity: sha512-HCelrgua/Y+kqO8RyL04JBWS/cVdrtUv/h45GntgQY+cJl4eBcKkCDV3TdMjtKx1nXwRaR9QXslM/Npm1dxdZQ==}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ solid-js: ^1.9.10
+ peerDependenciesMeta:
+ solid-js:
+ optional: true
+
babylon@6.18.0:
resolution: {integrity: sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==}
hasBin: true
@@ -3831,6 +3903,9 @@ packages:
peerDependencies:
ajv: 4.11.8 - 8
+ bidi-js@1.0.3:
+ resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==}
+
bignumber.js@9.1.2:
resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==}
@@ -4467,10 +4542,21 @@ packages:
css-to-react-native@3.2.0:
resolution: {integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==}
+ css-tree@3.1.0:
+ resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==}
+ engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
+
css-what@6.1.0:
resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
engines: {node: '>= 6'}
+ css.escape@1.5.1:
+ resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
+
+ cssstyle@5.3.7:
+ resolution: {integrity: sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==}
+ engines: {node: '>=20'}
+
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
@@ -4488,6 +4574,10 @@ packages:
resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==}
engines: {node: '>= 14'}
+ data-urls@6.0.0:
+ resolution: {integrity: sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==}
+ engines: {node: '>=20'}
+
data-view-buffer@1.0.2:
resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
engines: {node: '>= 0.4'}
@@ -4567,6 +4657,9 @@ packages:
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
engines: {node: '>=0.10.0'}
+ decimal.js@10.6.0:
+ resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==}
+
decko@1.2.0:
resolution: {integrity: sha512-m8FnyHXV1QX+S1cl+KPFDIl6NMkxtKsy6+U/aYyjrOqWMuwAwYWu7ePqrsUHtDR5Y8Yk2pi/KIDSgF+vT4cPOQ==}
@@ -4736,6 +4829,9 @@ packages:
dom-accessibility-api@0.5.16:
resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==}
+ dom-accessibility-api@0.6.3:
+ resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==}
+
dom-serializer@1.4.1:
resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==}
@@ -4860,6 +4956,10 @@ packages:
resolution: {integrity: sha512-BeJFvFRJddxobhvEdm5GqHzRV/X+ACeuw0/BuuxsCh1EUZcAIz8+kYmBp/LrQuloy6K1f3a0M7+IhmZ7QnkISA==}
engines: {node: '>=0.12'}
+ entities@6.0.1:
+ resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
+ engines: {node: '>=0.12'}
+
env-paths@2.2.1:
resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
engines: {node: '>=6'}
@@ -5474,10 +5574,6 @@ packages:
resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==}
engines: {node: '>=10'}
- globals@11.12.0:
- resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
- engines: {node: '>=4'}
-
globals@14.0.0:
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
engines: {node: '>=18'}
@@ -5618,6 +5714,13 @@ packages:
howler@2.2.3:
resolution: {integrity: sha512-QM0FFkw0LRX1PR8pNzJVAY25JhIWvbKMBFM4gqk+QdV+kPXOhleWGCB6AiAF/goGjIHK2e/nIElplvjQwhr0jg==}
+ html-encoding-sniffer@6.0.0:
+ resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
+ html-entities@2.3.3:
+ resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==}
+
html-entities@2.5.2:
resolution: {integrity: sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==}
@@ -5672,6 +5775,10 @@ packages:
resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==}
engines: {node: '>= 14'}
+ https-proxy-agent@7.0.6:
+ resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
+ engines: {node: '>= 14'}
+
human-signals@2.1.0:
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
engines: {node: '>=10.17.0'}
@@ -5941,6 +6048,9 @@ packages:
resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==}
engines: {node: '>=0.10.0'}
+ is-potential-custom-element-name@1.0.1:
+ resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
+
is-promise@4.0.0:
resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
@@ -6013,6 +6123,10 @@ packages:
resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==}
engines: {node: '>= 0.4'}
+ is-what@4.1.16:
+ resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==}
+ engines: {node: '>=12.13'}
+
is-wsl@1.1.0:
resolution: {integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==}
engines: {node: '>=4'}
@@ -6148,15 +6262,19 @@ packages:
jsbn@1.1.0:
resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==}
+ jsdom@27.4.0:
+ resolution: {integrity: sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+ peerDependencies:
+ canvas: ^3.0.0
+ peerDependenciesMeta:
+ canvas:
+ optional: true
+
jsep@1.4.0:
resolution: {integrity: sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==}
engines: {node: '>= 10.16.0'}
- jsesc@2.5.2:
- resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
- engines: {node: '>=4'}
- hasBin: true
-
jsesc@3.1.0:
resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
engines: {node: '>=6'}
@@ -6445,8 +6563,8 @@ packages:
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
- lru-cache@11.1.0:
- resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==}
+ lru-cache@11.2.4:
+ resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==}
engines: {node: 20 || >=22}
lru-cache@5.1.1:
@@ -6560,6 +6678,9 @@ packages:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
+ mdn-data@2.12.2:
+ resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==}
+
media-typer@0.3.0:
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
engines: {node: '>= 0.6'}
@@ -6582,6 +6703,10 @@ packages:
resolution: {integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==}
engines: {node: '>=10'}
+ merge-anything@5.1.7:
+ resolution: {integrity: sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==}
+ engines: {node: '>=12.13'}
+
merge-descriptors@1.0.3:
resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==}
@@ -7352,6 +7477,9 @@ packages:
parse5@7.1.2:
resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==}
+ parse5@8.0.0:
+ resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==}
+
parseurl@1.3.3:
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
engines: {node: '>= 0.8'}
@@ -8053,6 +8181,10 @@ packages:
engines: {node: '>=14.0.0'}
hasBin: true
+ saxes@6.0.0:
+ resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
+ engines: {node: '>=v12.22.7'}
+
scheduler@0.23.2:
resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
@@ -8109,6 +8241,16 @@ packages:
serialize-javascript@6.0.2:
resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==}
+ seroval-plugins@1.3.3:
+ resolution: {integrity: sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ seroval: ^1.0
+
+ seroval@1.3.2:
+ resolution: {integrity: sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==}
+ engines: {node: '>=10'}
+
serve-static@1.16.2:
resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==}
engines: {node: '>= 0.8.0'}
@@ -8277,6 +8419,14 @@ packages:
resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==}
engines: {node: '>= 10.0.0', npm: '>= 3.0.0'}
+ solid-js@1.9.10:
+ resolution: {integrity: sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==}
+
+ solid-refresh@0.6.3:
+ resolution: {integrity: sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA==}
+ peerDependencies:
+ solid-js: ^1.3
+
sonic-boom@1.4.1:
resolution: {integrity: sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==}
@@ -8576,6 +8726,9 @@ packages:
resolution: {integrity: sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==}
hasBin: true
+ symbol-tree@3.2.4:
+ resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
+
tapable@2.2.1:
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
engines: {node: '>=6'}
@@ -8688,6 +8841,13 @@ packages:
resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==}
engines: {node: '>=14.0.0'}
+ tldts-core@7.0.19:
+ resolution: {integrity: sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==}
+
+ tldts@7.0.19:
+ resolution: {integrity: sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA==}
+ hasBin: true
+
tmp@0.0.33:
resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
engines: {node: '>=0.6.0'}
@@ -8725,6 +8885,10 @@ packages:
resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==}
hasBin: true
+ tough-cookie@6.0.0:
+ resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==}
+ engines: {node: '>=16'}
+
toxic@1.0.1:
resolution: {integrity: sha512-WI3rIGdcaKULYg7KVoB0zcjikqvcYYvcuT6D89bFPz2rVR0Rl0PK6x8/X62rtdLtBKIE985NzVf/auTtGegIIg==}
@@ -8738,6 +8902,10 @@ packages:
resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==}
engines: {node: '>=14'}
+ tr46@6.0.0:
+ resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==}
+ engines: {node: '>=20'}
+
tree-kill@1.2.2:
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
hasBin: true
@@ -9159,6 +9327,16 @@ packages:
'@vite-pwa/assets-generator':
optional: true
+ vite-plugin-solid@2.11.10:
+ resolution: {integrity: sha512-Yr1dQybmtDtDAHkii6hXuc1oVH9CPcS/Zb2jN/P36qqcrkNnVPsMTzQ06jyzFPFjj3U1IYKMVt/9ZqcwGCEbjw==}
+ peerDependencies:
+ '@testing-library/jest-dom': ^5.16.6 || ^5.17.0 || ^6.*
+ solid-js: ^1.7.2
+ vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
+ peerDependenciesMeta:
+ '@testing-library/jest-dom':
+ optional: true
+
vite@7.1.12:
resolution: {integrity: sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -9199,6 +9377,14 @@ packages:
yaml:
optional: true
+ vitefu@1.1.1:
+ resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==}
+ peerDependencies:
+ vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0
+ peerDependenciesMeta:
+ vite:
+ optional: true
+
vitest@4.0.15:
resolution: {integrity: sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==}
engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0}
@@ -9236,6 +9422,10 @@ packages:
vlq@0.2.3:
resolution: {integrity: sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==}
+ w3c-xmlserializer@5.0.0:
+ resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
+ engines: {node: '>=18'}
+
walkdir@0.4.1:
resolution: {integrity: sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==}
engines: {node: '>=6.0.0'}
@@ -9264,6 +9454,10 @@ packages:
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
engines: {node: '>=12'}
+ webidl-conversions@8.0.1:
+ resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==}
+ engines: {node: '>=20'}
+
webpack-sources@3.2.3:
resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==}
engines: {node: '>=10.13.0'}
@@ -9289,10 +9483,18 @@ packages:
resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==}
engines: {node: '>=12'}
+ whatwg-mimetype@4.0.0:
+ resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
+ engines: {node: '>=18'}
+
whatwg-url@13.0.0:
resolution: {integrity: sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==}
engines: {node: '>=16'}
+ whatwg-url@15.1.0:
+ resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==}
+ engines: {node: '>=20'}
+
whatwg-url@5.0.0:
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
@@ -9442,6 +9644,18 @@ packages:
utf-8-validate:
optional: true
+ ws@8.19.0:
+ resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==}
+ engines: {node: '>=10.0.0'}
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: '>=5.0.2'
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+
wsl-utils@0.1.0:
resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==}
engines: {node: '>=18'}
@@ -9450,6 +9664,13 @@ packages:
resolution: {integrity: sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==}
engines: {node: '>=8'}
+ xml-name-validator@5.0.0:
+ resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
+ engines: {node: '>=18'}
+
+ xmlchars@2.2.0:
+ resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
+
xtend@4.0.2:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}
@@ -9532,10 +9753,10 @@ packages:
snapshots:
- '@ampproject/remapping@2.3.0':
- dependencies:
- '@jridgewell/gen-mapping': 0.3.13
- '@jridgewell/trace-mapping': 0.3.31
+ '@acemir/cssom@0.9.30':
+ optional: true
+
+ '@adobe/css-tools@4.4.4': {}
'@anatine/zod-openapi@1.14.2(openapi3-ts@2.0.2)(zod@3.23.8)':
dependencies:
@@ -9557,36 +9778,35 @@ snapshots:
call-me-maybe: 1.0.2
js-yaml: 4.1.0
+ '@asamuzakjp/css-color@4.1.1':
+ dependencies:
+ '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-tokenizer': 3.0.4
+ lru-cache: 11.2.4
+ optional: true
+
+ '@asamuzakjp/dom-selector@6.7.6':
+ dependencies:
+ '@asamuzakjp/nwsapi': 2.3.9
+ bidi-js: 1.0.3
+ css-tree: 3.1.0
+ is-potential-custom-element-name: 1.0.1
+ lru-cache: 11.2.4
+ optional: true
+
+ '@asamuzakjp/nwsapi@2.3.9':
+ optional: true
+
'@babel/code-frame@7.27.1':
dependencies:
'@babel/helper-validator-identifier': 7.28.5
js-tokens: 4.0.0
picocolors: 1.1.1
- '@babel/compat-data@7.25.2': {}
-
'@babel/compat-data@7.28.5': {}
- '@babel/core@7.25.2':
- dependencies:
- '@ampproject/remapping': 2.3.0
- '@babel/code-frame': 7.27.1
- '@babel/generator': 7.25.0
- '@babel/helper-compilation-targets': 7.25.2
- '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2)
- '@babel/helpers': 7.25.0
- '@babel/parser': 7.28.5
- '@babel/template': 7.25.0
- '@babel/traverse': 7.25.2
- '@babel/types': 7.28.5
- convert-source-map: 2.0.0
- debug: 4.4.3
- gensync: 1.0.0-beta.2
- json5: 2.2.3
- semver: 6.3.1
- transitivePeerDependencies:
- - supports-color
-
'@babel/core@7.28.5':
dependencies:
'@babel/code-frame': 7.27.1
@@ -9607,13 +9827,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@babel/generator@7.25.0':
- dependencies:
- '@babel/types': 7.28.5
- '@jridgewell/gen-mapping': 0.3.13
- '@jridgewell/trace-mapping': 0.3.31
- jsesc: 2.5.2
-
'@babel/generator@7.28.5':
dependencies:
'@babel/parser': 7.28.5
@@ -9626,14 +9839,6 @@ snapshots:
dependencies:
'@babel/types': 7.28.5
- '@babel/helper-compilation-targets@7.25.2':
- dependencies:
- '@babel/compat-data': 7.25.2
- '@babel/helper-validator-option': 7.24.8
- browserslist: 4.24.4
- lru-cache: 5.1.1
- semver: 6.3.1
-
'@babel/helper-compilation-targets@7.27.2':
dependencies:
'@babel/compat-data': 7.28.5
@@ -9682,12 +9887,9 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@babel/helper-module-imports@7.24.7':
+ '@babel/helper-module-imports@7.18.6':
dependencies:
- '@babel/traverse': 7.25.2
'@babel/types': 7.28.5
- transitivePeerDependencies:
- - supports-color
'@babel/helper-module-imports@7.27.1':
dependencies:
@@ -9696,16 +9898,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2)':
- dependencies:
- '@babel/core': 7.25.2
- '@babel/helper-module-imports': 7.24.7
- '@babel/helper-simple-access': 7.24.7
- '@babel/helper-validator-identifier': 7.28.5
- '@babel/traverse': 7.25.2
- transitivePeerDependencies:
- - supports-color
-
'@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)':
dependencies:
'@babel/core': 7.28.5
@@ -9739,13 +9931,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@babel/helper-simple-access@7.24.7':
- dependencies:
- '@babel/traverse': 7.25.2
- '@babel/types': 7.28.5
- transitivePeerDependencies:
- - supports-color
-
'@babel/helper-skip-transparent-expression-wrappers@7.27.1':
dependencies:
'@babel/traverse': 7.28.5
@@ -9757,8 +9942,6 @@ snapshots:
'@babel/helper-validator-identifier@7.28.5': {}
- '@babel/helper-validator-option@7.24.8': {}
-
'@babel/helper-validator-option@7.27.1': {}
'@babel/helper-wrap-function@7.28.3':
@@ -9769,11 +9952,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@babel/helpers@7.25.0':
- dependencies:
- '@babel/template': 7.25.0
- '@babel/types': 7.28.5
-
'@babel/helpers@7.28.4':
dependencies:
'@babel/template': 7.27.2
@@ -9832,6 +10010,11 @@ snapshots:
'@babel/core': 7.28.5
'@babel/helper-plugin-utils': 7.27.1
+ '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)':
+ dependencies:
+ '@babel/core': 7.28.5
+ '@babel/helper-plugin-utils': 7.27.1
+
'@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.5)':
dependencies:
'@babel/core': 7.28.5
@@ -10260,30 +10443,12 @@ snapshots:
'@babel/runtime@7.28.4': {}
- '@babel/template@7.25.0':
- dependencies:
- '@babel/code-frame': 7.27.1
- '@babel/parser': 7.28.5
- '@babel/types': 7.28.5
-
'@babel/template@7.27.2':
dependencies:
'@babel/code-frame': 7.27.1
'@babel/parser': 7.28.5
'@babel/types': 7.28.5
- '@babel/traverse@7.25.2':
- dependencies:
- '@babel/code-frame': 7.27.1
- '@babel/generator': 7.25.0
- '@babel/parser': 7.28.5
- '@babel/template': 7.25.0
- '@babel/types': 7.28.5
- debug: 4.4.3
- globals: 11.12.0
- transitivePeerDependencies:
- - supports-color
-
'@babel/traverse@7.28.5':
dependencies:
'@babel/code-frame': 7.27.1
@@ -10444,6 +10609,34 @@ snapshots:
dependencies:
'@jridgewell/trace-mapping': 0.3.9
+ '@csstools/color-helpers@5.1.0':
+ optional: true
+
+ '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
+ dependencies:
+ '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-tokenizer': 3.0.4
+ optional: true
+
+ '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
+ dependencies:
+ '@csstools/color-helpers': 5.1.0
+ '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-tokenizer': 3.0.4
+ optional: true
+
+ '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)':
+ dependencies:
+ '@csstools/css-tokenizer': 3.0.4
+ optional: true
+
+ '@csstools/css-syntax-patches-for-csstree@1.0.23':
+ optional: true
+
+ '@csstools/css-tokenizer@3.0.4':
+ optional: true
+
'@dabh/diagnostics@2.0.3':
dependencies:
colorspace: 1.1.4
@@ -10760,6 +10953,9 @@ snapshots:
'@eslint/core': 0.17.0
levn: 0.4.1
+ '@exodus/bytes@1.8.0':
+ optional: true
+
'@exodus/schemasafe@1.3.0': {}
'@faker-js/faker@7.6.0': {}
@@ -11555,9 +11751,9 @@ snapshots:
'@npmcli/agent@2.2.2':
dependencies:
- agent-base: 7.1.1
+ agent-base: 7.1.4
http-proxy-agent: 7.0.2
- https-proxy-agent: 7.0.5
+ https-proxy-agent: 7.0.6
lru-cache: 10.4.3
socks-proxy-agent: 8.0.4
transitivePeerDependencies:
@@ -11892,7 +12088,7 @@ snapshots:
'@redocly/ajv': 8.11.2
'@redocly/config': 0.20.3
colorette: 1.4.0
- https-proxy-agent: 7.0.5
+ https-proxy-agent: 7.0.6
js-levenshtein: 1.1.6
js-yaml: 4.1.0
minimatch: 5.1.6
@@ -11932,12 +12128,14 @@ snapshots:
transitivePeerDependencies:
- ajv
- '@rollup/plugin-babel@5.3.1(@babel/core@7.28.5)(rollup@2.79.2)':
+ '@rollup/plugin-babel@5.3.1(@babel/core@7.28.5)(@types/babel__core@7.20.5)(rollup@2.79.2)':
dependencies:
'@babel/core': 7.28.5
'@babel/helper-module-imports': 7.27.1
'@rollup/pluginutils': 3.1.0(rollup@2.79.2)
rollup: 2.79.2
+ optionalDependencies:
+ '@types/babel__core': 7.20.5
transitivePeerDependencies:
- supports-color
@@ -12136,7 +12334,7 @@ snapshots:
'@sentry/bundler-plugin-core@3.3.1(encoding@0.1.13)':
dependencies:
- '@babel/core': 7.25.2
+ '@babel/core': 7.28.5
'@sentry/babel-plugin-component-annotate': 3.3.1
'@sentry/cli': 2.42.2(encoding@0.1.13)
dotenv: 16.4.5
@@ -12216,6 +12414,11 @@ snapshots:
ignore: 5.3.2
p-map: 4.0.0
+ '@solidjs/testing-library@0.8.10(solid-js@1.9.10)':
+ dependencies:
+ '@testing-library/dom': 10.4.1
+ solid-js: 1.9.10
+
'@standard-schema/spec@1.0.0': {}
'@surma/rollup-plugin-off-main-thread@2.2.3':
@@ -12236,6 +12439,15 @@ snapshots:
picocolors: 1.1.1
pretty-format: 27.5.1
+ '@testing-library/jest-dom@6.9.1':
+ dependencies:
+ '@adobe/css-tools': 4.4.4
+ aria-query: 5.3.0
+ css.escape: 1.5.1
+ dom-accessibility-api: 0.6.3
+ picocolors: 1.1.1
+ redent: 3.0.0
+
'@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)':
dependencies:
'@testing-library/dom': 10.4.1
@@ -12288,6 +12500,27 @@ snapshots:
'@types/aria-query@5.0.4': {}
+ '@types/babel__core@7.20.5':
+ dependencies:
+ '@babel/parser': 7.28.5
+ '@babel/types': 7.28.5
+ '@types/babel__generator': 7.27.0
+ '@types/babel__template': 7.4.4
+ '@types/babel__traverse': 7.28.0
+
+ '@types/babel__generator@7.27.0':
+ dependencies:
+ '@babel/types': 7.28.5
+
+ '@types/babel__template@7.4.4':
+ dependencies:
+ '@babel/parser': 7.28.5
+ '@babel/types': 7.28.5
+
+ '@types/babel__traverse@7.28.0':
+ dependencies:
+ '@babel/types': 7.28.5
+
'@types/bcrypt@5.0.2':
dependencies:
'@types/node': 24.9.1
@@ -12549,7 +12782,7 @@ snapshots:
'@typescript-eslint/types': 7.18.0
eslint-visitor-keys: 3.4.3
- '@vitest/coverage-v8@4.0.15(vitest@4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1))':
+ '@vitest/coverage-v8@4.0.15(vitest@4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(jsdom@27.4.0)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1))':
dependencies:
'@bcoe/v8-coverage': 1.0.2
'@vitest/utils': 4.0.15
@@ -12562,11 +12795,11 @@ snapshots:
obug: 2.1.1
std-env: 3.10.0
tinyrainbow: 3.0.3
- vitest: 4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
+ vitest: 4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(jsdom@27.4.0)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
transitivePeerDependencies:
- supports-color
- '@vitest/coverage-v8@4.0.15(vitest@4.0.15(@types/node@20.5.1)(happy-dom@20.0.10)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1))':
+ '@vitest/coverage-v8@4.0.15(vitest@4.0.15(@types/node@20.5.1)(happy-dom@20.0.10)(jsdom@27.4.0)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1))':
dependencies:
'@bcoe/v8-coverage': 1.0.2
'@vitest/utils': 4.0.15
@@ -12579,7 +12812,7 @@ snapshots:
obug: 2.1.1
std-env: 3.10.0
tinyrainbow: 3.0.3
- vitest: 4.0.15(@types/node@20.5.1)(happy-dom@20.0.10)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
+ vitest: 4.0.15(@types/node@20.5.1)(happy-dom@20.0.10)(jsdom@27.4.0)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
transitivePeerDependencies:
- supports-color
@@ -12713,6 +12946,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ agent-base@7.1.4: {}
+
aggregate-error@3.1.0:
dependencies:
clean-stack: 2.2.0
@@ -12940,6 +13175,15 @@ snapshots:
b4a@1.6.6: {}
+ babel-plugin-jsx-dom-expressions@0.40.3(@babel/core@7.28.5):
+ dependencies:
+ '@babel/core': 7.28.5
+ '@babel/helper-module-imports': 7.18.6
+ '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5)
+ '@babel/types': 7.28.5
+ html-entities: 2.3.3
+ parse5: 7.1.2
+
babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.5):
dependencies:
'@babel/compat-data': 7.28.5
@@ -12964,6 +13208,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ babel-preset-solid@1.9.10(@babel/core@7.28.5)(solid-js@1.9.10):
+ dependencies:
+ '@babel/core': 7.28.5
+ babel-plugin-jsx-dom-expressions: 0.40.3(@babel/core@7.28.5)
+ optionalDependencies:
+ solid-js: 1.9.10
+
babylon@6.18.0: {}
balanced-match@1.0.2: {}
@@ -13030,6 +13281,11 @@ snapshots:
jsonpointer: 5.0.1
leven: 3.1.0
+ bidi-js@1.0.3:
+ dependencies:
+ require-from-string: 2.0.2
+ optional: true
+
bignumber.js@9.1.2: {}
binary-extensions@2.3.0: {}
@@ -13750,8 +14006,24 @@ snapshots:
css-color-keywords: 1.0.0
postcss-value-parser: 4.2.0
+ css-tree@3.1.0:
+ dependencies:
+ mdn-data: 2.12.2
+ source-map-js: 1.2.1
+ optional: true
+
css-what@6.1.0: {}
+ css.escape@1.5.1: {}
+
+ cssstyle@5.3.7:
+ dependencies:
+ '@asamuzakjp/css-color': 4.1.1
+ '@csstools/css-syntax-patches-for-csstree': 1.0.23
+ css-tree: 3.1.0
+ lru-cache: 11.2.4
+ optional: true
+
csstype@3.1.3: {}
csv-parse@5.5.6: {}
@@ -13762,6 +14034,12 @@ snapshots:
data-uri-to-buffer@6.0.2: {}
+ data-urls@6.0.0:
+ dependencies:
+ whatwg-mimetype: 4.0.0
+ whatwg-url: 15.1.0
+ optional: true
+
data-view-buffer@1.0.2:
dependencies:
call-bound: 1.0.4
@@ -13819,6 +14097,9 @@ snapshots:
decamelize@1.2.0: {}
+ decimal.js@10.6.0:
+ optional: true
+
decko@1.2.0: {}
deep-equal-in-any-order@2.0.6:
@@ -13993,6 +14274,8 @@ snapshots:
dom-accessibility-api@0.5.16: {}
+ dom-accessibility-api@0.6.3: {}
+
dom-serializer@1.4.1:
dependencies:
domelementtype: 2.3.0
@@ -14124,6 +14407,9 @@ snapshots:
entities@5.0.0: {}
+ entities@6.0.1:
+ optional: true
+
env-paths@2.2.1:
optional: true
@@ -15001,7 +15287,7 @@ snapshots:
gaxios@6.7.0(encoding@0.1.13):
dependencies:
extend: 3.0.2
- https-proxy-agent: 7.0.5
+ https-proxy-agent: 7.0.6
is-stream: 2.0.1
node-fetch: 2.7.0(encoding@0.1.13)
uuid: 10.0.0
@@ -15165,8 +15451,6 @@ snapshots:
dependencies:
ini: 2.0.0
- globals@11.12.0: {}
-
globals@14.0.0: {}
globals@15.15.0: {}
@@ -15324,6 +15608,15 @@ snapshots:
howler@2.2.3: {}
+ html-encoding-sniffer@6.0.0:
+ dependencies:
+ '@exodus/bytes': 1.8.0
+ transitivePeerDependencies:
+ - '@exodus/crypto'
+ optional: true
+
+ html-entities@2.3.3: {}
+
html-entities@2.5.2:
optional: true
@@ -15393,7 +15686,7 @@ snapshots:
http-proxy-agent@7.0.2:
dependencies:
- agent-base: 7.1.1
+ agent-base: 7.1.4
debug: 4.4.3
transitivePeerDependencies:
- supports-color
@@ -15414,6 +15707,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ https-proxy-agent@7.0.6:
+ dependencies:
+ agent-base: 7.1.4
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
human-signals@2.1.0: {}
human-signals@4.3.1: {}
@@ -15674,6 +15974,9 @@ snapshots:
is-plain-obj@1.1.0: {}
+ is-potential-custom-element-name@1.0.1:
+ optional: true
+
is-promise@4.0.0: {}
is-regex@1.2.1:
@@ -15735,6 +16038,8 @@ snapshots:
call-bound: 1.0.4
get-intrinsic: 1.3.0
+ is-what@4.1.16: {}
+
is-wsl@1.1.0: {}
is-wsl@2.2.0:
@@ -15876,9 +16181,36 @@ snapshots:
jsbn@1.1.0: {}
- jsep@1.4.0: {}
+ jsdom@27.4.0:
+ dependencies:
+ '@acemir/cssom': 0.9.30
+ '@asamuzakjp/dom-selector': 6.7.6
+ '@exodus/bytes': 1.8.0
+ cssstyle: 5.3.7
+ data-urls: 6.0.0
+ decimal.js: 10.6.0
+ html-encoding-sniffer: 6.0.0
+ http-proxy-agent: 7.0.2
+ https-proxy-agent: 7.0.6
+ is-potential-custom-element-name: 1.0.1
+ parse5: 8.0.0
+ saxes: 6.0.0
+ symbol-tree: 3.2.4
+ tough-cookie: 6.0.0
+ w3c-xmlserializer: 5.0.0
+ webidl-conversions: 8.0.1
+ whatwg-mimetype: 4.0.0
+ whatwg-url: 15.1.0
+ ws: 8.19.0
+ xml-name-validator: 5.0.0
+ transitivePeerDependencies:
+ - '@exodus/crypto'
+ - bufferutil
+ - supports-color
+ - utf-8-validate
+ optional: true
- jsesc@2.5.2: {}
+ jsep@1.4.0: {}
jsesc@3.1.0: {}
@@ -16195,7 +16527,7 @@ snapshots:
lru-cache@10.4.3: {}
- lru-cache@11.1.0: {}
+ lru-cache@11.2.4: {}
lru-cache@5.1.1:
dependencies:
@@ -16319,6 +16651,9 @@ snapshots:
math-intrinsics@1.1.0: {}
+ mdn-data@2.12.2:
+ optional: true
+
media-typer@0.3.0: {}
media-typer@1.1.0: {}
@@ -16343,6 +16678,10 @@ snapshots:
type-fest: 0.18.1
yargs-parser: 20.2.9
+ merge-anything@5.1.7:
+ dependencies:
+ is-what: 4.1.16
+
merge-descriptors@1.0.3: {}
merge-descriptors@2.0.0: {}
@@ -17252,11 +17591,11 @@ snapshots:
pac-proxy-agent@7.0.2:
dependencies:
'@tootallnate/quickjs-emscripten': 0.23.0
- agent-base: 7.1.1
+ agent-base: 7.1.4
debug: 4.4.3
get-uri: 6.0.3
http-proxy-agent: 7.0.2
- https-proxy-agent: 7.0.5
+ https-proxy-agent: 7.0.6
pac-resolver: 7.0.1
socks-proxy-agent: 8.0.4
transitivePeerDependencies:
@@ -17318,6 +17657,11 @@ snapshots:
dependencies:
entities: 4.5.0
+ parse5@8.0.0:
+ dependencies:
+ entities: 6.0.1
+ optional: true
+
parseurl@1.3.3: {}
pascal-case@3.1.2:
@@ -17346,7 +17690,7 @@ snapshots:
path-scurry@2.0.0:
dependencies:
- lru-cache: 11.1.0
+ lru-cache: 11.2.4
minipass: 7.1.2
path-to-regexp@0.1.12: {}
@@ -17610,7 +17954,7 @@ snapshots:
agent-base: 7.1.1
debug: 4.4.3
http-proxy-agent: 7.0.2
- https-proxy-agent: 7.0.5
+ https-proxy-agent: 7.0.6
lru-cache: 7.18.3
pac-proxy-agent: 7.0.2
proxy-from-env: 1.1.0
@@ -18108,6 +18452,11 @@ snapshots:
immutable: 4.3.7
source-map-js: 1.2.1
+ saxes@6.0.0:
+ dependencies:
+ xmlchars: 2.2.0
+ optional: true
+
scheduler@0.23.2:
dependencies:
loose-envify: 1.4.0
@@ -18190,6 +18539,12 @@ snapshots:
dependencies:
randombytes: 2.1.0
+ seroval-plugins@1.3.3(seroval@1.3.2):
+ dependencies:
+ seroval: 1.3.2
+
+ seroval@1.3.2: {}
+
serve-static@1.16.2:
dependencies:
encodeurl: 2.0.0
@@ -18392,7 +18747,7 @@ snapshots:
socks-proxy-agent@8.0.4:
dependencies:
- agent-base: 7.1.1
+ agent-base: 7.1.4
debug: 4.4.3
socks: 2.8.3
transitivePeerDependencies:
@@ -18403,6 +18758,21 @@ snapshots:
ip-address: 9.0.5
smart-buffer: 4.2.0
+ solid-js@1.9.10:
+ dependencies:
+ csstype: 3.1.3
+ seroval: 1.3.2
+ seroval-plugins: 1.3.3(seroval@1.3.2)
+
+ solid-refresh@0.6.3(solid-js@1.9.10):
+ dependencies:
+ '@babel/generator': 7.28.5
+ '@babel/helper-module-imports': 7.27.1
+ '@babel/types': 7.28.5
+ solid-js: 1.9.10
+ transitivePeerDependencies:
+ - supports-color
+
sonic-boom@1.4.1:
dependencies:
atomic-sleep: 1.0.0
@@ -18775,6 +19145,9 @@ snapshots:
transitivePeerDependencies:
- encoding
+ symbol-tree@3.2.4:
+ optional: true
+
tapable@2.2.1: {}
tar-fs@2.1.4:
@@ -18931,6 +19304,14 @@ snapshots:
tinyrainbow@3.0.3: {}
+ tldts-core@7.0.19:
+ optional: true
+
+ tldts@7.0.19:
+ dependencies:
+ tldts-core: 7.0.19
+ optional: true
+
tmp@0.0.33:
dependencies:
os-tmpdir: 1.0.2
@@ -18959,6 +19340,11 @@ snapshots:
touch@3.1.1: {}
+ tough-cookie@6.0.0:
+ dependencies:
+ tldts: 7.0.19
+ optional: true
+
toxic@1.0.1:
dependencies:
lodash: 4.17.21
@@ -18973,6 +19359,11 @@ snapshots:
dependencies:
punycode: 2.3.1
+ tr46@6.0.0:
+ dependencies:
+ punycode: 2.3.1
+ optional: true
+
tree-kill@1.2.2: {}
trim-newlines@3.0.1: {}
@@ -19377,17 +19768,32 @@ snapshots:
html-minifier-terser: 7.2.0
vite: 7.1.12(@types/node@24.9.1)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
- vite-plugin-pwa@1.1.0(vite@7.1.12(@types/node@24.9.1)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1))(workbox-build@7.1.1)(workbox-window@7.1.0):
+ vite-plugin-pwa@1.1.0(vite@7.1.12(@types/node@24.9.1)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.1.0):
dependencies:
debug: 4.4.3
pretty-bytes: 6.1.1
tinyglobby: 0.2.15
vite: 7.1.12(@types/node@24.9.1)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
- workbox-build: 7.1.1
+ workbox-build: 7.1.1(@types/babel__core@7.20.5)
workbox-window: 7.1.0
transitivePeerDependencies:
- supports-color
+ vite-plugin-solid@2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.10)(vite@7.1.12(@types/node@24.9.1)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)):
+ dependencies:
+ '@babel/core': 7.28.5
+ '@types/babel__core': 7.20.5
+ babel-preset-solid: 1.9.10(@babel/core@7.28.5)(solid-js@1.9.10)
+ merge-anything: 5.1.7
+ solid-js: 1.9.10
+ solid-refresh: 0.6.3(solid-js@1.9.10)
+ vite: 7.1.12(@types/node@24.9.1)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
+ vitefu: 1.1.1(vite@7.1.12(@types/node@24.9.1)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1))
+ optionalDependencies:
+ '@testing-library/jest-dom': 6.9.1
+ transitivePeerDependencies:
+ - supports-color
+
vite@7.1.12(@types/node@20.5.1)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1):
dependencies:
esbuild: 0.25.11
@@ -19420,7 +19826,11 @@ snapshots:
tsx: 4.16.2
yaml: 2.8.1
- vitest@4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1):
+ vitefu@1.1.1(vite@7.1.12(@types/node@24.9.1)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)):
+ optionalDependencies:
+ vite: 7.1.12(@types/node@24.9.1)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1)
+
+ vitest@4.0.15(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.0.10)(jsdom@27.4.0)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1):
dependencies:
'@vitest/expect': 4.0.15
'@vitest/mocker': 4.0.15(vite@7.1.12(@types/node@24.9.1)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1))
@@ -19446,6 +19856,7 @@ snapshots:
'@opentelemetry/api': 1.8.0
'@types/node': 24.9.1
happy-dom: 20.0.10
+ jsdom: 27.4.0
transitivePeerDependencies:
- jiti
- less
@@ -19459,7 +19870,7 @@ snapshots:
- tsx
- yaml
- vitest@4.0.15(@types/node@20.5.1)(happy-dom@20.0.10)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1):
+ vitest@4.0.15(@types/node@20.5.1)(happy-dom@20.0.10)(jsdom@27.4.0)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1):
dependencies:
'@vitest/expect': 4.0.15
'@vitest/mocker': 4.0.15(vite@7.1.12(@types/node@20.5.1)(sass@1.70.0)(terser@5.44.1)(tsx@4.16.2)(yaml@2.8.1))
@@ -19484,6 +19895,7 @@ snapshots:
optionalDependencies:
'@types/node': 20.5.1
happy-dom: 20.0.10
+ jsdom: 27.4.0
transitivePeerDependencies:
- jiti
- less
@@ -19499,6 +19911,11 @@ snapshots:
vlq@0.2.3: {}
+ w3c-xmlserializer@5.0.0:
+ dependencies:
+ xml-name-validator: 5.0.0
+ optional: true
+
walkdir@0.4.1: {}
wawoff2@2.0.1:
@@ -19528,6 +19945,9 @@ snapshots:
webidl-conversions@7.0.0: {}
+ webidl-conversions@8.0.1:
+ optional: true
+
webpack-sources@3.2.3: {}
webpack-virtual-modules@0.5.0: {}
@@ -19546,11 +19966,20 @@ snapshots:
whatwg-mimetype@3.0.0: {}
+ whatwg-mimetype@4.0.0:
+ optional: true
+
whatwg-url@13.0.0:
dependencies:
tr46: 4.1.1
webidl-conversions: 7.0.0
+ whatwg-url@15.1.0:
+ dependencies:
+ tr46: 6.0.0
+ webidl-conversions: 8.0.1
+ optional: true
+
whatwg-url@5.0.0:
dependencies:
tr46: 0.0.3
@@ -19667,13 +20096,13 @@ snapshots:
dependencies:
workbox-core: 7.1.0
- workbox-build@7.1.1:
+ workbox-build@7.1.1(@types/babel__core@7.20.5):
dependencies:
'@apideck/better-ajv-errors': 0.3.6(ajv@8.17.1)
'@babel/core': 7.28.5
'@babel/preset-env': 7.28.5(@babel/core@7.28.5)
'@babel/runtime': 7.28.4
- '@rollup/plugin-babel': 5.3.1(@babel/core@7.28.5)(rollup@2.79.2)
+ '@rollup/plugin-babel': 5.3.1(@babel/core@7.28.5)(@types/babel__core@7.20.5)(rollup@2.79.2)
'@rollup/plugin-node-resolve': 15.3.1(rollup@2.79.2)
'@rollup/plugin-replace': 2.4.2(rollup@2.79.2)
'@rollup/plugin-terser': 0.4.4(rollup@2.79.2)
@@ -19800,12 +20229,21 @@ snapshots:
ws@7.5.10: {}
+ ws@8.19.0:
+ optional: true
+
wsl-utils@0.1.0:
dependencies:
is-wsl: 3.1.0
xdg-basedir@4.0.0: {}
+ xml-name-validator@5.0.0:
+ optional: true
+
+ xmlchars@2.2.0:
+ optional: true
+
xtend@4.0.2: {}
y18n@5.0.8: {}
diff --git a/vitest.config.ts b/vitest.config.ts
index 22005f4254fc..f5211a3af1be 100644
--- a/vitest.config.ts
+++ b/vitest.config.ts
@@ -2,6 +2,9 @@ import { defineConfig, UserWorkspaceConfig } from "vitest/config";
import { projects as backendProjects } from "./backend/vitest.config";
import { projects as frontendProjects } from "./frontend/vitest.config";
+//oxlint-disable-next-line no-explicit-any
+let plugins: any[] = [];
+
export default defineConfig({
test: {
projects: [
@@ -10,6 +13,7 @@ export default defineConfig({
"packages/**/vitest.config.ts",
],
},
+ plugins,
});
function convertTests(
@@ -17,13 +21,14 @@ function convertTests(
root: string,
): UserWorkspaceConfig[] {
return (projects as UserWorkspaceConfig[]).map((it) => {
+ copySolidPlugin(it);
const test = it.test ?? {};
const name: string | { label: string } = test.name ?? "unknown";
let updatedName =
name === null || typeof name === "string"
- ? `${name} (${root})`
- : { ...name, label: `${name.label} (${root})` };
+ ? `${name}-${root}`
+ : { ...name, label: `${name.label}-${root}` };
return {
...it,
@@ -35,3 +40,14 @@ function convertTests(
} as UserWorkspaceConfig;
});
}
+
+/**
+ * Tests for solidJs need the solid plugin to run on config level and on test level. idk why
+ */
+function copySolidPlugin(config: UserWorkspaceConfig): void {
+ if (!config.plugins) return;
+ config.plugins
+ //@ts-expect-error this is fine
+ .filter((it) => it["name"] === "solid")
+ .forEach((it) => plugins.push(it));
+}