+ date === undefined
+ ? undefined
+ : dateFormat(
+ date,
+ props.type === "date" ? "yyyy-MM-dd" : "yyyy-MM-dd'T'HH:mm:ss",
+ );
+
return (
props.field().handleChange(e.target.value)}
+ onInput={(e) => {
+ props.field().handleChange(e.target.value);
+ }}
onKeyDown={(e) => {
if (e.key === "Enter") {
shakeItIfYouWantIt();
@@ -84,8 +97,11 @@ export function InputField(props: {
onFocus={() => props.onFocus?.()}
dir={props.dir}
maxLength={props.maxLength}
+ {...getNumberOptions(props.schema)}
+ {...getDateOptions(props.schema, formatDate)}
min={props.min}
max={props.max}
+ step={props.step?.toString()}
/>
@@ -93,3 +109,43 @@ export function InputField(props: {
);
}
+
+function getNumberOptions(schema: ZodTypeAny | undefined): {
+ min?: number;
+ max?: number;
+ step?: string;
+} {
+ if (schema === undefined) return {};
+ if (getZodType(schema) !== ZodFirstPartyTypeKind.ZodNumber) return {};
+ const numberSchema = schema as ZodNumber;
+
+ return {
+ min: numberSchema.minValue ?? undefined,
+ max: numberSchema.maxValue ?? undefined,
+ step: numberSchema.isInt ? "1" : "any",
+ };
+}
+
+function getDateOptions(
+ schema: ZodTypeAny | undefined,
+ format: (val: Date | undefined) => string | undefined,
+): {
+ min?: string;
+ max?: string;
+} {
+ if (schema === undefined) return {};
+ if (getZodType(schema) !== ZodFirstPartyTypeKind.ZodDate) return {};
+
+ const applyFormat = (it: Date | null) =>
+ it === null ? undefined : format(it);
+
+ return {
+ min: applyFormat((schema as ZodDate).minDate),
+ max: applyFormat((schema as ZodDate).maxDate),
+ };
+}
+
+function getZodType(schema: ZodTypeAny): ZodFirstPartyTypeKind {
+ // oxlint-disable-next-line typescript/no-unsafe-assignment typescript/no-unsafe-member-access
+ return schema._def["typeName"] as ZodFirstPartyTypeKind;
+}
diff --git a/frontend/src/ts/components/ui/form/TextareaField.tsx b/frontend/src/ts/components/ui/form/TextareaField.tsx
index 394069d40645..555027c597ce 100644
--- a/frontend/src/ts/components/ui/form/TextareaField.tsx
+++ b/frontend/src/ts/components/ui/form/TextareaField.tsx
@@ -8,6 +8,7 @@ export function TextareaField(props: {
field: Accessor;
ref?: HTMLTextAreaElement | ((el: HTMLTextAreaElement) => void);
placeholder?: string;
+ autocomplete?: string;
disabled?: boolean;
class?: string;
maxLength?: number;
@@ -28,6 +29,7 @@ export function TextareaField(props: {
id={props.field().name as string}
name={props.field().name as string}
placeholder={props.placeholder ?? ""}
+ autocomplete={props.autocomplete}
value={props.field().state.value as string}
onBlur={() => props.field().handleBlur()}
onInput={(e) => props.field().handleChange(e.currentTarget.value)}
diff --git a/frontend/src/ts/input/handlers/before-delete.ts b/frontend/src/ts/input/handlers/before-delete.ts
index 3dc7c77a1c73..85ddc1c7e55a 100644
--- a/frontend/src/ts/input/handlers/before-delete.ts
+++ b/frontend/src/ts/input/handlers/before-delete.ts
@@ -28,6 +28,12 @@ export function onBeforeDelete(event: InputEvent): void {
const inputIsEmpty = inputValue === "";
if (inputIsEmpty) {
+ // we are on the first word, just prevent default, nothing to go back to
+ if (TestState.activeWordIndex === 0) {
+ event.preventDefault();
+ return;
+ }
+
// this is nested because we only wanna pull the element from the dom if needed
const previousWordElement = TestUI.getWordElement(
TestState.activeWordIndex - 1,
diff --git a/frontend/src/ts/input/handlers/delete.ts b/frontend/src/ts/input/handlers/delete.ts
index 8d2a44340a47..fa244fbe5454 100644
--- a/frontend/src/ts/input/handlers/delete.ts
+++ b/frontend/src/ts/input/handlers/delete.ts
@@ -18,6 +18,8 @@ export function onDelete(inputType: DeleteInputType, now: number): void {
TestInput.input.syncWithInputElement();
+ const inputAfterDelete = TestInput.input.current;
+
Replay.addReplayEvent("setLetterIndex", TestInput.input.current.length);
TestInput.setCurrentNotAfk();
@@ -33,25 +35,52 @@ export function onDelete(inputType: DeleteInputType, now: number): void {
inputBeforeDelete.length > 0 &&
beforeDeleteOnlyTabs &&
allTabsCorrect
- // (TestInput.input.getHistory(TestState.activeWordIndex - 1) !==
- // TestWords.words.get(TestState.activeWordIndex - 1) ||
- // Config.freedomMode)
) {
+ // Clear N+1's tabs (the word the user was in)
+ logTestEvent("input", now, {
+ inputType: "deleteWordBackward",
+ wordIndex: activeWordIndexBeforeDelete,
+ charIndex: inputBeforeDelete.length,
+ inputValue: "",
+ });
+
setInputElementValue("");
- TestInput.input.syncWithInputElement();
goToPreviousWord(inputType, true);
- } else {
- //normal backspace
- if (realInputValue === "") {
- goToPreviousWord(inputType);
- }
+
+ // Record the resulting state of the previous word (newline removed)
+ const postNavInputValue = getInputElementValue().inputValue;
+ logTestEvent("input", now, {
+ inputType: "deleteContentBackward",
+ wordIndex: activeWordIndex,
+ charIndex: postNavInputValue.length,
+ inputValue: postNavInputValue,
+ });
+
+ TestUI.afterTestDelete();
+ return;
}
- logTestEvent("input", now, {
- inputType: inputType,
- wordIndex: activeWordIndexBeforeDelete,
- charIndex: inputBeforeDelete.length,
- });
+ //normal backspace
+ if (realInputValue === "") {
+ goToPreviousWord(inputType);
+
+ // Record the resulting state of the destination word
+ const postNavInputValue = getInputElementValue().inputValue;
+ logTestEvent("input", now, {
+ inputType: inputType,
+ wordIndex: activeWordIndex,
+ charIndex: postNavInputValue.length,
+ inputValue: postNavInputValue,
+ });
+ } else {
+ // Delete within current word
+ logTestEvent("input", now, {
+ inputType: inputType,
+ wordIndex: activeWordIndexBeforeDelete,
+ charIndex: inputBeforeDelete.length,
+ inputValue: inputAfterDelete,
+ });
+ }
TestUI.afterTestDelete();
}
diff --git a/frontend/src/ts/input/handlers/insert-text.ts b/frontend/src/ts/input/handlers/insert-text.ts
index 6145641c5a49..af461149f4ca 100644
--- a/frontend/src/ts/input/handlers/insert-text.ts
+++ b/frontend/src/ts/input/handlers/insert-text.ts
@@ -213,6 +213,24 @@ export async function onInsertText(options: OnInsertTextParams): Promise {
TestInput.input.syncWithInputElement();
}
+ // capture DOM before goToNextWord clears it for the new word
+ const inputValueAfterEvent = TestInput.input.current;
+
+ // Log the event BEFORE goToNextWord so readers inside the navigation
+ // (e.g. beforeTestWordChange's updateWordLetters, getWordBurst) see the
+ // completed event in derivation. Otherwise the just-typed trigger char
+ // (space/newline) is missing — visible as missing \n element in zen mode.
+ logTestEvent("input", now, {
+ inputType: "insertText",
+ data,
+ correct,
+ wordIndex,
+ charIndex: testInput.length,
+ isCompositionEnding: isCompositionEnding === true,
+ inputStopped: removeLastChar,
+ inputValue: inputValueAfterEvent + (charIsSpace ? " " : ""),
+ });
+
// going to next word
let increasedWordIndex: null | boolean = null;
let lastBurst: null | number = null;
@@ -221,21 +239,12 @@ export async function onInsertText(options: OnInsertTextParams): Promise {
correctInsert: correct,
isCompositionEnding: isCompositionEnding === true,
zenNewline: charIsNewline && Config.mode === "zen",
+ now,
});
lastBurst = result.lastBurst;
increasedWordIndex = result.increasedWordIndex;
}
- logTestEvent("input", now, {
- inputType: "insertText",
- data,
- correct,
- wordIndex,
- charIndex: testInput.length,
- isCompositionEnding: isCompositionEnding === true,
- inputStopped: removeLastChar,
- });
-
/*
Probably a good place to explain what the heck is going on with all these space related variables:
- spaceOrNewLine: did the user input a space or a new line?
diff --git a/frontend/src/ts/input/helpers/word-navigation.ts b/frontend/src/ts/input/helpers/word-navigation.ts
index 897d115e65c0..27ec9c8fec62 100644
--- a/frontend/src/ts/input/helpers/word-navigation.ts
+++ b/frontend/src/ts/input/helpers/word-navigation.ts
@@ -22,6 +22,7 @@ type GoToNextWordParams = {
// this is used to tell test ui to update the word before moving to the next word (in case of a composition that ends with a space)
isCompositionEnding: boolean;
zenNewline?: boolean;
+ now: number;
};
type GoToNextWordReturn = {
@@ -33,6 +34,7 @@ export async function goToNextWord({
correctInsert,
isCompositionEnding,
zenNewline,
+ now,
}: GoToNextWordParams): Promise {
const ret = {
increasedWordIndex: false,
@@ -56,7 +58,7 @@ export async function goToNextWord({
}
//burst calculation and fail
- const burst: number = TestStats.calculateBurst();
+ const burst: number = TestStats.calculateBurst(now);
TestInput.pushBurstToHistory(burst);
ret.lastBurst = burst;
diff --git a/frontend/src/ts/test/events/data.ts b/frontend/src/ts/test/events/data.ts
index ebda2b4c76ba..67a62c88e6e9 100644
--- a/frontend/src/ts/test/events/data.ts
+++ b/frontend/src/ts/test/events/data.ts
@@ -14,7 +14,6 @@ import {
TimerEventData,
} from "./types";
import { keysToTrack } from "./helpers";
-import { start } from "../test-stats";
import { Keycode } from "../../constants/keys";
import { roundTo2 } from "@monkeytype/util/numbers";
import { resultCalculating } from "../test-state";
@@ -222,6 +221,19 @@ export function cleanupData(): void {
export function getAllTestEvents(): TestEvent[] {
if (cachedAllEvents !== undefined) return cachedAllEvents;
+ const firstEventMs = Math.min(
+ ...[
+ keydownEvents[0]?.ms,
+ keyupEvents[0]?.ms,
+ timerEvents[0]?.ms,
+ inputEvents[0]?.ms,
+ compositionEvents[0]?.ms,
+ ].filter((ms): ms is number => ms !== undefined),
+ );
+
+ const startEventMs =
+ timerEvents.find((e) => e.data.event === "start")?.ms ?? firstEventMs ?? 0;
+
// cachedAllEvents = testData300;
// return cachedAllEvents;
cachedAllEvents = [
@@ -237,7 +249,7 @@ export function getAllTestEvents(): TestEvent[] {
(a.type === "timer" ? 1 : 0) - (b.type === "timer" ? 1 : 0),
)
.map((event) => {
- event.testMs = roundTo2(event.ms - start);
+ event.testMs = roundTo2(event.ms - startEventMs);
return event;
});
@@ -308,6 +320,18 @@ export function getPressedKeys(): Map<
return pressedKeys;
}
+export function getInputEventsForWord(wordIndex: number): InputEvent[] {
+ const events = getAllTestEvents();
+ const result: InputEvent[] = [];
+ for (const event of events) {
+ if (event.type !== "input") continue;
+ if (event.data.wordIndex === wordIndex) {
+ result.push(event);
+ }
+ }
+ return result;
+}
+
export function getInputEventsPerWord(
startMs?: number,
testMsLimit?: number,
@@ -327,18 +351,7 @@ export function getInputEventsPerWord(
break;
}
- let wordIndex = event.data.wordIndex;
-
- //special case for delete events on the 0th index
- // because they affect the previous word - so we need to attribute them to the previous word
- if (
- (event.data.inputType === "deleteWordBackward" ||
- event.data.inputType === "deleteContentBackward") &&
- event.data.charIndex === 0 &&
- wordIndex > 0
- ) {
- wordIndex -= 1;
- }
+ const wordIndex = event.data.wordIndex;
const existing = eventsPerWordIndex.get(wordIndex) ?? [];
existing.push(event);
diff --git a/frontend/src/ts/test/events/helpers.ts b/frontend/src/ts/test/events/helpers.ts
index 415b4916520b..b5d7186f05e4 100644
--- a/frontend/src/ts/test/events/helpers.ts
+++ b/frontend/src/ts/test/events/helpers.ts
@@ -93,25 +93,92 @@ export function getTestEventCode(event: KeyboardEvent): Keycode | "NoCode" {
return event.code as Keycode;
}
-export function getSimulatedInput(events: InputEvent[]): string {
- let simulatedInput = "";
+export function applyOp(input: string, event: InputEvent): string {
+ if (event.data.inputType === "insertText") {
+ if (event.data.inputStopped) return input;
+ return input + event.data.data;
+ }
+ if (event.data.inputType === "insertCompositionText") {
+ if (event.data.inputStopped) return input;
+ return input + event.data.data;
+ }
+ if (event.data.inputType === "deleteContentBackward") {
+ return input.slice(0, -1);
+ }
+ if (event.data.inputType === "deleteWordBackward") {
+ return input.replace(/(?:\S+\s*|\s+)$/, "");
+ }
+ return input;
+}
+/**
+ * Derives input by applying each event's operation in order. Ignores the
+ * recorded inputValue field. Use for verification, tests, or fallback —
+ * not as source of truth.
+ */
+export function getInputFromEvents(events: InputEvent[]): string {
+ let input = "";
for (const event of events) {
- if (event.data.inputType === "insertText") {
- if (event.data.inputStopped) continue;
- simulatedInput += event.data.data;
- }
- if (event.data.inputType === "insertCompositionText") {
- if (event.data.inputStopped) continue;
- simulatedInput += event.data.data;
- }
- if (event.data.inputType === "deleteContentBackward") {
- simulatedInput = simulatedInput.slice(0, -1);
+ input = applyOp(input, event);
+ }
+ return input;
+}
+
+/**
+ * Reads input from the DOM snapshots captured on each event (inputValue),
+ * falling back to op-based derivation for events without a snapshot.
+ * Use this whenever you need the actual current/past input state.
+ *
+ * Walks backward to find the latest event with a captured inputValue, then
+ * replays any subsequent events forward — O(1) when the last event has a
+ * snapshot (the common case), O(n) worst case.
+ */
+export function getInputFromDom(events: InputEvent[]): string {
+ for (let i = events.length - 1; i >= 0; i--) {
+ const event = events[i] as InputEvent;
+ if (event.data.inputValue !== undefined) {
+ let input = event.data.inputValue;
+ for (let j = i + 1; j < events.length; j++) {
+ input = applyOp(input, events[j] as InputEvent);
+ }
+ return input;
}
- if (event.data.inputType === "deleteWordBackward") {
- simulatedInput = "";
+ }
+ return getInputFromEvents(events);
+}
+
+export type InputValueMismatch = {
+ index: number;
+ derived: string;
+ recorded: string;
+};
+
+/**
+ * Compares event-derived input against the recorded DOM snapshot at each
+ * event. Returns the indices where event-derivation disagreed with what the
+ * DOM captured. Useful for catching op-logic bugs or capture-timing bugs.
+ */
+export function findInputValueMismatches(
+ events: InputEvent[],
+): InputValueMismatch[] {
+ const mismatches: InputValueMismatch[] = [];
+ let derived = "";
+
+ for (let i = 0; i < events.length; i++) {
+ const event = events[i] as InputEvent;
+ derived = applyOp(derived, event);
+
+ if (
+ event.data.inputValue !== undefined &&
+ event.data.inputValue !== derived
+ ) {
+ mismatches.push({
+ index: i,
+ derived,
+ recorded: event.data.inputValue,
+ });
}
}
- return simulatedInput;
+ return mismatches;
}
diff --git a/frontend/src/ts/test/events/stats.ts b/frontend/src/ts/test/events/stats.ts
index 3f8ae474ba7b..a56a34760352 100644
--- a/frontend/src/ts/test/events/stats.ts
+++ b/frontend/src/ts/test/events/stats.ts
@@ -1,6 +1,7 @@
import {
getAllTestEvents,
getInputEvents,
+ getInputEventsForWord,
getInputEventsPerWord,
getPressedKeys,
logTestEvent,
@@ -8,7 +9,7 @@ import {
import * as TestWords from "../../test/test-words";
import { CharCounts, countChars, getLastChar } from "../../utils/strings";
import * as CustomText from "../../test/custom-text";
-import { getSimulatedInput } from "./helpers";
+import { getInputFromDom } from "./helpers";
import { activeWordIndex, bailedOut } from "../test-state";
import { calculateWpm } from "../../utils/numbers";
import { mean, roundTo2 } from "@monkeytype/util/numbers";
@@ -259,7 +260,7 @@ export function getChars(): CharCounts {
for (const [wordIndex, events] of eventsPerWordIndex.entries()) {
const lastWord = wordIndex === activeWordIndex;
- let simulatedInput = getSimulatedInput(events);
+ let simulatedInput = getInputFromDom(events);
if (lastWord) {
//remove trailing space for last word
@@ -295,6 +296,11 @@ export function getChars(): CharCounts {
};
}
+export function getInputForWord(wordIndex: number): string {
+ const events = getInputEventsForWord(wordIndex);
+ return getInputFromDom(events).trimEnd();
+}
+
export function getAccuracy(): {
correct: number;
incorrect: number;
@@ -400,7 +406,7 @@ export function getWpmHistory(): number[] {
>();
let maxWordIndex = 0;
for (const [k, wordEvents] of eventsPerWord) {
- const input = getSimulatedInput(wordEvents);
+ const input = getInputFromDom(wordEvents);
wordInputs.set(k, { input, events: wordEvents });
// Only count words with non-empty input for maxWordIndex,
// so that fully-deleted words don't prevent earlier words
diff --git a/frontend/src/ts/test/events/types.ts b/frontend/src/ts/test/events/types.ts
index 94712b8dac63..1d7b64370f94 100644
--- a/frontend/src/ts/test/events/types.ts
+++ b/frontend/src/ts/test/events/types.ts
@@ -69,21 +69,23 @@ export type TimerEventData =
export type InputEvent = EventProps<"input", InputEventData>;
-export type InputEventData = {
+type BaseInputEventData = {
charIndex: number;
wordIndex: number;
-} & (
- | {
+ inputValue?: string;
+};
+
+export type InputEventData =
+ | (BaseInputEventData & {
inputType: InsertInputType;
data: string;
correct: boolean;
isCompositionEnding: boolean;
inputStopped: boolean;
- }
- | {
+ })
+ | (BaseInputEventData & {
inputType: DeleteInputType;
- }
-);
+ });
export type CompositionTestEvent = EventProps<
"composition",
diff --git a/frontend/src/ts/test/funbox/funbox-functions.ts b/frontend/src/ts/test/funbox/funbox-functions.ts
index 78377be3a229..484fc3bb2053 100644
--- a/frontend/src/ts/test/funbox/funbox-functions.ts
+++ b/frontend/src/ts/test/funbox/funbox-functions.ts
@@ -425,7 +425,7 @@ const list: Partial> = {
const outOf: number = TestWords.words.length;
const wordsPerLayout = Math.floor(outOf / layouts.length);
const index = Math.floor(
- (TestInput.input.getHistory().length + 1) / wordsPerLayout,
+ (TestState.activeWordIndex + 1) / wordsPerLayout,
);
const mod =
wordsPerLayout - ((TestState.activeWordIndex + 1) % wordsPerLayout);
diff --git a/frontend/src/ts/test/test-input.ts b/frontend/src/ts/test/test-input.ts
index e74f8ba05b07..d1b0cf76139f 100644
--- a/frontend/src/ts/test/test-input.ts
+++ b/frontend/src/ts/test/test-input.ts
@@ -99,11 +99,9 @@ type ErrorHistoryObject = {
class Input {
current: string;
private history: string[];
- koreanStatus: boolean;
constructor() {
this.current = "";
this.history = [];
- this.koreanStatus = false;
}
reset(): void {
@@ -115,14 +113,6 @@ class Input {
this.history = [];
}
- setKoreanStatus(val: boolean): void {
- this.koreanStatus = val;
- }
-
- getKoreanStatus(): boolean {
- return this.koreanStatus;
- }
-
pushHistory(): void {
this.history.push(this.current);
this.current = "";
diff --git a/frontend/src/ts/test/test-logic.ts b/frontend/src/ts/test/test-logic.ts
index 337e19eb11c9..ad43d55ff73e 100644
--- a/frontend/src/ts/test/test-logic.ts
+++ b/frontend/src/ts/test/test-logic.ts
@@ -195,7 +195,7 @@ export function startTest(now: number): boolean {
} catch (e) {}
//use a recursive self-adjusting timer to avoid time drift
TestStats.setStart(now);
- void TestTimer.start();
+ void TestTimer.start(now);
TestUI.onTestStart();
return true;
}
@@ -338,7 +338,7 @@ export function restart(options = {} as RestartOptions): void {
TestState.setBailedOut(false);
Caret.resetPosition();
PaceCaret.reset();
- TestInput.input.setKoreanStatus(false);
+ TestState.setKoreanStatus(false);
clearQuoteStats();
CompositionState.setComposing(false);
CompositionState.setData("");
@@ -599,7 +599,7 @@ async function init(): Promise {
/[\uac00-\ud7af]|[\u1100-\u11ff]|[\u3130-\u318f]|[\ua960-\ua97f]|[\ud7b0-\ud7ff]/g,
)
) {
- TestInput.input.setKoreanStatus(true);
+ TestState.setKoreanStatus(true);
}
for (let i = 0; i < generatedWords.length; i++) {
@@ -660,7 +660,7 @@ export function areAllTestWordsGenerated(): boolean {
//add word during the test
export async function addWord(): Promise {
if (Config.mode === "zen") {
- TestUI.appendEmptyWordElement();
+ TestUI.appendEmptyWordElement(TestState.activeWordIndex + 1);
return;
}
@@ -674,7 +674,7 @@ export async function addWord(): Promise {
const toPushCount = funboxToPush?.split(":")[1];
if (toPushCount !== undefined) bound = +toPushCount - 1;
- if (TestWords.words.length - TestInput.input.getHistory().length > bound) {
+ if (TestWords.words.length - TestState.activeWordIndex > bound) {
console.debug("Not adding word, enough words already");
return;
}
diff --git a/frontend/src/ts/test/test-state.ts b/frontend/src/ts/test/test-state.ts
index 82c27c083657..831c101d08ec 100644
--- a/frontend/src/ts/test/test-state.ts
+++ b/frontend/src/ts/test/test-state.ts
@@ -13,6 +13,11 @@ export let isDirectionReversed = false;
export let testRestarting = false;
export let resultVisible = false;
export let resultCalculating = false;
+export let koreanStatus = false;
+
+export function setKoreanStatus(val: boolean): void {
+ koreanStatus = val;
+}
export function setRepeated(tf: boolean): void {
isRepeated = tf;
diff --git a/frontend/src/ts/test/test-stats.ts b/frontend/src/ts/test/test-stats.ts
index 9d7701fc45f7..807962f76b3e 100644
--- a/frontend/src/ts/test/test-stats.ts
+++ b/frontend/src/ts/test/test-stats.ts
@@ -179,7 +179,7 @@ export function setLastSecondNotRound(): void {
}
export function calculateBurst(endTime: number = performance.now()): number {
- const containsKorean = TestInput.input.getKoreanStatus();
+ const containsKorean = TestState.koreanStatus;
const timeToWrite = (endTime - TestInput.currentBurstStart) / 1000;
if (timeToWrite <= 0) return 0;
let wordLength: number;
@@ -213,7 +213,7 @@ export function removeAfkData(): void {
}
function getInputWords(): string[] {
- const containsKorean = TestInput.input.getKoreanStatus();
+ const containsKorean = TestState.koreanStatus;
let inputWords = [...TestInput.input.getHistory()];
@@ -229,7 +229,7 @@ function getInputWords(): string[] {
}
function getTargetWords(): string[] {
- const containsKorean = TestInput.input.getKoreanStatus();
+ const containsKorean = TestState.koreanStatus;
let targetWords = [
...(Config.mode === "zen"
diff --git a/frontend/src/ts/test/test-timer.ts b/frontend/src/ts/test/test-timer.ts
index b7467e0dab62..849c4e269d7d 100644
--- a/frontend/src/ts/test/test-timer.ts
+++ b/frontend/src/ts/test/test-timer.ts
@@ -313,20 +313,20 @@ function checkIfTimerIsSlow(drift: number): void {
}
}
-export async function start(): Promise {
+export async function start(now: number): Promise {
SlowTimer.clear();
slowTimerCount = 0;
for (const id of slowTimerNotifIds) {
removeNotification(id, "clear");
}
slowTimerNotifIds = [];
- void _startNew();
+ void _startNew(now);
// void _startOld();
}
-async function _startNew(): Promise {
+async function _startNew(now: number): Promise {
newTimer.play();
- logTestEvent("timer", performance.now(), {
+ logTestEvent("timer", now, {
event: "start",
timer: Time.get(),
});
diff --git a/frontend/src/ts/test/test-ui.ts b/frontend/src/ts/test/test-ui.ts
index ffc105d1dfda..cd1dec9b948d 100644
--- a/frontend/src/ts/test/test-ui.ts
+++ b/frontend/src/ts/test/test-ui.ts
@@ -493,7 +493,7 @@ function showWords(): void {
wordsEl.setHtml("");
if (Config.mode === "zen") {
- appendEmptyWordElement();
+ appendEmptyWordElement(0);
} else {
let wordsHTML = "";
for (let i = 0; i < TestWords.words.length; i++) {
@@ -509,9 +509,7 @@ function showWords(): void {
PaceCaret.resetCaretPosition();
}
-export function appendEmptyWordElement(
- index = TestInput.input.getHistory().length,
-): void {
+export function appendEmptyWordElement(index: number): void {
wordsEl.appendHtml(
`_
`,
);
diff --git a/frontend/src/ts/test/timer-progress.ts b/frontend/src/ts/test/timer-progress.ts
index 89a41bc521e9..717748e9bbbc 100644
--- a/frontend/src/ts/test/timer-progress.ts
+++ b/frontend/src/ts/test/timer-progress.ts
@@ -2,7 +2,6 @@ import { Config } from "../config/store";
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 "../legacy-states/time";
import * as TestState from "./test-state";
import { configEvent } from "../events/config";
@@ -111,12 +110,12 @@ function getCurrentCount(): number {
1
);
} else {
- return TestInput.input.getHistory().length;
+ return TestState.activeWordIndex;
}
}
function setTimerHtmlToInputLength(el: HTMLElement, wrapInDiv: boolean): void {
- let historyLength = `${TestInput.input.getHistory().length}`;
+ let historyLength = `${TestState.activeWordIndex}`;
if (wrapInDiv) {
historyLength = `${historyLength}
`;
diff --git a/frontend/static/quotes/code_javascript.json b/frontend/static/quotes/code_javascript.json
index 68845ad636bf..52156defc707 100644
--- a/frontend/static/quotes/code_javascript.json
+++ b/frontend/static/quotes/code_javascript.json
@@ -276,6 +276,18 @@
"source": "Monkeytype Sourcecode",
"length": 159,
"id": 45
+ },
+ {
+ "text": "(function () {\n\t\"use strict\";\n\t/* Start of your code */\n\tfunction greetMe(yourName) {\n\t\talert(`Hello ${yourName}`);\n\t}\n\n\tgreetMe(\"World\");\n\t/* End of your code */\n})();",
+ "source": "MDN",
+ "length": 168,
+ "id": 46
+ },
+ {
+ "text": "function die(msg) { process.stderr.write(msg + '\n'); process.exit(2); }",
+ "source": "Julius Brussee - Caveman",
+ "length": 71,
+ "id": 47
}
]
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index fcff95bbd8cd..e9d87439dc0e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -607,7 +607,7 @@ importers:
version: 10.4.1(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.7.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
'@storybook/addon-vitest':
specifier: ^10.2.14
- version: 10.2.16(@vitest/browser-playwright@4.0.18)(@vitest/browser@4.1.6(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0))(@vitest/runner@4.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.7.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vitest@4.1.0)
+ version: 10.2.16(@vitest/browser-playwright@4.0.18)(@vitest/browser@4.1.8(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0))(@vitest/runner@4.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.7.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vitest@4.1.0)
'@storybook/builder-vite':
specifier: ^10.2.14
version: 10.2.16(esbuild@0.27.7)(rollup@4.60.1)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.7.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))
@@ -616,13 +616,13 @@ importers:
version: 4.2.1(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))
'@vitest/browser':
specifier: ^4.1.6
- version: 4.1.6(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0)
+ version: 4.1.8(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0)
'@vitest/browser-playwright':
specifier: ^4.0.18
version: 4.0.18(playwright@1.58.2)(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0)
'@vitest/coverage-v8':
specifier: ^4.1.5
- version: 4.1.5(@vitest/browser@4.1.6(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0))(vitest@4.1.0)
+ version: 4.1.5(@vitest/browser@4.1.8(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0))(vitest@4.1.0)
playwright:
specifier: ^1.58.2
version: 1.58.2
@@ -3256,48 +3256,56 @@ packages:
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@oxfmt/binding-linux-arm64-musl@0.49.0':
resolution: {integrity: sha512-iNzkMPG18jPkwBOZ4/HEjwqfzAjq4RrUQ0CgId/fC1ENvYD5jLVAaU/gWgpiqP1ys07kxSsSggDd1fp3E7mQHw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@oxfmt/binding-linux-ppc64-gnu@0.49.0':
resolution: {integrity: sha512-BPHA/NN3LvoIXiid+iz3BHt5V0Rzx0tXAqRUovwE1NsbDaLG9e8mtv7evDGRIkVQacqTDBv0XL25THHsxSJosQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ppc64]
os: [linux]
+ libc: [glibc]
'@oxfmt/binding-linux-riscv64-gnu@0.49.0':
resolution: {integrity: sha512-3Eroshe+s69htC9JIL0+zLGQczLtRKezkMhwqQC21VC5Z/fuLvzLfbAOLgJLUq601H8gDYjy7deYycfOBjCvWg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
+ libc: [glibc]
'@oxfmt/binding-linux-riscv64-musl@0.49.0':
resolution: {integrity: sha512-fnaERGgsxGm0lKAmO72EYR4BA3qBnzBTJBTi6EtUMq1D4R7EexRBMU4voXnx4TXla3SEDl9x4uNp/18SbkPjGg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
+ libc: [musl]
'@oxfmt/binding-linux-s390x-gnu@0.49.0':
resolution: {integrity: sha512-rBwasMl1Uul1MCCeTGEFKnOTL7VUxHf+634jWStrQAbzpBJgd5Yz5m4F7exVCsoI8PHn57dNjssXagXLCLB5yA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@oxfmt/binding-linux-x64-gnu@0.49.0':
resolution: {integrity: sha512-BoC/F9xHe2y/deuBGA5Aw7bes07OD2gcL2wlpzTrfImR92vPP7S/k3LBTyspQZCNIVNdagkELcqKELwMLGIfAg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@oxfmt/binding-linux-x64-musl@0.49.0':
resolution: {integrity: sha512-umY6jFADAo/oztFKl8D/S6vSrG6oBpEskcentiRuz42kZVU2kfDXMWCYavxyZR2bwPjqkHpcHZ6EZFiH3Qj9ZA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@oxfmt/binding-openharmony-arm64@0.49.0':
resolution: {integrity: sha512-J85zQMiw2pXiGPK+OusmDvSnJ/dgpgN7VgmB2zOBtgS8F+nsOUfSg9ZEBrwbQscjZ7tkPbm38CG4VF5f53MsiA==}
@@ -3400,48 +3408,56 @@ packages:
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@oxlint/binding-linux-arm64-musl@1.64.0':
resolution: {integrity: sha512-00QQ0h0Y7u0G69BgiH3+ky2aaq/QvkDL6DYok8htIuJHxybiux5aQ8jwmg8qIk9wha6UagUP2BAwAzbemcJbpg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@oxlint/binding-linux-ppc64-gnu@1.64.0':
resolution: {integrity: sha512-2GaimTV6EMW+s5HS0An3oGbQme3BgHswvfVdGk3EB57Xe9+/gyT+Qd7lNVzb3rtir52vbIPzXfaYArzs5b5zcw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ppc64]
os: [linux]
+ libc: [glibc]
'@oxlint/binding-linux-riscv64-gnu@1.64.0':
resolution: {integrity: sha512-H46AtFb9wypjoVwGdlxrm0DsD809NGmtiK9HiyPKTxkSte2YjhC4S+00rOIrwCaxcyPiGid3Y3OMXp5KMAkGZw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
+ libc: [glibc]
'@oxlint/binding-linux-riscv64-musl@1.64.0':
resolution: {integrity: sha512-HEgsidjjvvyzdg82icYkuFCf7REDV7B9JFwbIMbVwrKLBY0MrXX+bku3POn/hduZ2yW91IyVDUMq0Bf02KwXQw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
+ libc: [musl]
'@oxlint/binding-linux-s390x-gnu@1.64.0':
resolution: {integrity: sha512-Axvm8qryotmKN00P5w4JapaSjvP2LOSbdbBJiX+2SuHd3QzhW7TUc8skqgw+ahQZ5DmzEYeHCqauvW8f32Ns6Q==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@oxlint/binding-linux-x64-gnu@1.64.0':
resolution: {integrity: sha512-cR60vSd7+m+KRZ3GQGfDxWwahW5RMXg0qlGvAluZr0fTUYvw0H9N9AXAF/M/PMqgytyqvVNmBAkJG9l7U30Y1g==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@oxlint/binding-linux-x64-musl@1.64.0':
resolution: {integrity: sha512-2u/aPZ9pEg7HnvZPDsHxUGNnrpr4qaHi+mCgLgpt+LYRzPrS4Px4wPfkIdRdr2GvKnaYyt+XSlto0Vm5sbStTg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@oxlint/binding-openharmony-arm64@1.64.0':
resolution: {integrity: sha512-kfhkGfCdoXLSxEkrhDlJrvBYajGmq+ma4EMc53dsOWTq+rIBOlI0vTBmpZNnM5oH2LY/K/w1HAK+UQEgjgpVUg==}
@@ -3503,36 +3519,42 @@ packages:
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
+ libc: [glibc]
'@parcel/watcher-linux-arm-musl@2.5.6':
resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==}
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
+ libc: [musl]
'@parcel/watcher-linux-arm64-glibc@2.5.6':
resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@parcel/watcher-linux-arm64-musl@2.5.6':
resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@parcel/watcher-linux-x64-glibc@2.5.6':
resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@parcel/watcher-linux-x64-musl@2.5.6':
resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@parcel/watcher-win32-arm64@2.5.6':
resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==}
@@ -3675,36 +3697,42 @@ packages:
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@rolldown/binding-linux-arm64-musl@1.0.0-rc.12':
resolution: {integrity: sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12':
resolution: {integrity: sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ppc64]
os: [linux]
+ libc: [glibc]
'@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12':
resolution: {integrity: sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.12':
resolution: {integrity: sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@rolldown/binding-linux-x64-musl@1.0.0-rc.12':
resolution: {integrity: sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@rolldown/binding-openharmony-arm64@1.0.0-rc.12':
resolution: {integrity: sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==}
@@ -3772,8 +3800,8 @@ packages:
peerDependencies:
rollup: ^1.20.0||^2.0.0
- '@rollup/pluginutils@5.3.0':
- resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==}
+ '@rollup/pluginutils@5.4.0':
+ resolution: {integrity: sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==}
engines: {node: '>=14.0.0'}
peerDependencies:
rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
@@ -3845,121 +3873,145 @@ packages:
resolution: {integrity: sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==}
cpu: [arm]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-arm-gnueabihf@4.60.1':
resolution: {integrity: sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==}
cpu: [arm]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.40.0':
resolution: {integrity: sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==}
cpu: [arm]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-arm-musleabihf@4.60.1':
resolution: {integrity: sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==}
cpu: [arm]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.40.0':
resolution: {integrity: sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-arm64-gnu@4.60.1':
resolution: {integrity: sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.40.0':
resolution: {integrity: sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-arm64-musl@4.60.1':
resolution: {integrity: sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-loong64-gnu@4.60.1':
resolution: {integrity: sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==}
cpu: [loong64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-loong64-musl@4.60.1':
resolution: {integrity: sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==}
cpu: [loong64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-loongarch64-gnu@4.40.0':
resolution: {integrity: sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==}
cpu: [loong64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-powerpc64le-gnu@4.40.0':
resolution: {integrity: sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==}
cpu: [ppc64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-ppc64-gnu@4.60.1':
resolution: {integrity: sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==}
cpu: [ppc64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-ppc64-musl@4.60.1':
resolution: {integrity: sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==}
cpu: [ppc64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-riscv64-gnu@4.40.0':
resolution: {integrity: sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==}
cpu: [riscv64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.60.1':
resolution: {integrity: sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==}
cpu: [riscv64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.40.0':
resolution: {integrity: sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==}
cpu: [riscv64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-riscv64-musl@4.60.1':
resolution: {integrity: sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==}
cpu: [riscv64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.40.0':
resolution: {integrity: sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-s390x-gnu@4.60.1':
resolution: {integrity: sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.40.0':
resolution: {integrity: sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.60.1':
resolution: {integrity: sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.40.0':
resolution: {integrity: sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-x64-musl@4.60.1':
resolution: {integrity: sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-openbsd-x64@4.60.1':
resolution: {integrity: sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==}
@@ -4431,24 +4483,28 @@ packages:
engines: {node: '>= 20'}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@tailwindcss/oxide-linux-arm64-musl@4.2.1':
resolution: {integrity: sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==}
engines: {node: '>= 20'}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@tailwindcss/oxide-linux-x64-gnu@4.2.1':
resolution: {integrity: sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==}
engines: {node: '>= 20'}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@tailwindcss/oxide-linux-x64-musl@4.2.1':
resolution: {integrity: sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==}
engines: {node: '>= 20'}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@tailwindcss/oxide-wasm32-wasi@4.2.1':
resolution: {integrity: sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==}
@@ -5064,10 +5120,10 @@ packages:
peerDependencies:
vitest: 4.0.18
- '@vitest/browser@4.1.6':
- resolution: {integrity: sha512-ynsspTubXGSpa58JFJ24xIQt4z4A25epSbugEyaTmmrV1//Wec9EgE/LtoaC6yxUrXi5P7erGHRrkdZIHaVQuA==}
+ '@vitest/browser@4.1.8':
+ resolution: {integrity: sha512-u21VzX07HzlJYpFgkxmjEXar/tG2UqWGgyGG/46SrrPc7rSdCTPw5vuowopO9CIqF8UCUQzDFdbVnNpw6N0BfQ==}
peerDependencies:
- vitest: 4.1.6
+ vitest: 4.1.8
'@vitest/coverage-v8@4.1.5':
resolution: {integrity: sha512-38C0/Ddb7HcRG0Z4/DUem8x57d2p9jYgp18mkaYswEOQBGsI1CG4f/hjm0ZCeaJfWhSZ4k7jgs29V1Zom7Ki9A==}
@@ -5106,8 +5162,8 @@ packages:
vite:
optional: true
- '@vitest/mocker@4.1.6':
- resolution: {integrity: sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ==}
+ '@vitest/mocker@4.1.8':
+ resolution: {integrity: sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==}
peerDependencies:
msw: ^2.4.9
vite: ^6.0.0 || ^7.0.0 || ^8.0.0
@@ -5129,8 +5185,8 @@ packages:
'@vitest/pretty-format@4.1.5':
resolution: {integrity: sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==}
- '@vitest/pretty-format@4.1.6':
- resolution: {integrity: sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw==}
+ '@vitest/pretty-format@4.1.8':
+ resolution: {integrity: sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==}
'@vitest/runner@4.1.0':
resolution: {integrity: sha512-Duvx2OzQ7d6OjchL+trw+aSrb9idh7pnNfxrklo14p3zmNL4qPCDeIJAK+eBKYjkIwG96Bc6vYuxhqDXQOWpoQ==}
@@ -5147,8 +5203,8 @@ packages:
'@vitest/spy@4.1.0':
resolution: {integrity: sha512-pz77k+PgNpyMDv2FV6qmk5ZVau6c3R8HC8v342T2xlFxQKTrSeYw9waIJG8KgV9fFwAtTu4ceRzMivPTH6wSxw==}
- '@vitest/spy@4.1.6':
- resolution: {integrity: sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg==}
+ '@vitest/spy@4.1.8':
+ resolution: {integrity: sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==}
'@vitest/utils@3.2.4':
resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==}
@@ -5162,8 +5218,8 @@ packages:
'@vitest/utils@4.1.5':
resolution: {integrity: sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==}
- '@vitest/utils@4.1.6':
- resolution: {integrity: sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ==}
+ '@vitest/utils@4.1.8':
+ resolution: {integrity: sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==}
'@vue/compiler-core@3.4.37':
resolution: {integrity: sha512-ZDDT/KiLKuCRXyzWecNzC5vTcubGz4LECAtfGPENpo0nrmqJHwuWtRLxk/Sb9RAKtR9iFflFycbkjkY+W/PZUQ==}
@@ -5540,8 +5596,8 @@ packages:
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
- baseline-browser-mapping@2.10.32:
- resolution: {integrity: sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==}
+ baseline-browser-mapping@2.10.33:
+ resolution: {integrity: sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==}
engines: {node: '>=6.0.0'}
hasBin: true
@@ -6619,8 +6675,8 @@ packages:
electron-to-chromium@1.5.267:
resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==}
- electron-to-chromium@1.5.362:
- resolution: {integrity: sha512-PUY2DrLvkjkUuWqq+KPL2iWshrJsZOcIojzRQ7eXFacc9dWga7MGMJAa15VbiejSZB1PAXaRLAiKgruHP8LB1w==}
+ electron-to-chromium@1.5.364:
+ resolution: {integrity: sha512-G/dYE3+AYhyHwzTwg8UbnXf7zqMERYh7l2jJ3QujhFsH8agSYwtnGAR2aZ7f0AakIKJXd5En/Hre4igIUrdlYw==}
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@@ -7467,8 +7523,8 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
- hasown@2.0.3:
- resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==}
+ hasown@2.0.4:
+ resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==}
engines: {node: '>= 0.4'}
he@1.2.0:
@@ -7619,8 +7675,8 @@ packages:
immutable@4.3.8:
resolution: {integrity: sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw==}
- immutable@5.1.5:
- resolution: {integrity: sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==}
+ immutable@5.1.6:
+ resolution: {integrity: sha512-q1swsS8K7L8usSHuOqF2TAoCCkonYz0SG38wLAggaa4Wml70zixIvt2ql4coQ2C2B3hTjltJry4r6bULwgAXLQ==}
import-fresh@3.3.1:
resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
@@ -8270,48 +8326,56 @@ packages:
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
lightningcss-linux-arm64-gnu@1.32.0:
resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
lightningcss-linux-arm64-musl@1.31.1:
resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
+ libc: [musl]
lightningcss-linux-arm64-musl@1.32.0:
resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
+ libc: [musl]
lightningcss-linux-x64-gnu@1.31.1:
resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
+ libc: [glibc]
lightningcss-linux-x64-gnu@1.32.0:
resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
+ libc: [glibc]
lightningcss-linux-x64-musl@1.31.1:
resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
+ libc: [musl]
lightningcss-linux-x64-musl@1.32.0:
resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
+ libc: [musl]
lightningcss-win32-arm64-msvc@1.31.1:
resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==}
@@ -11145,8 +11209,8 @@ packages:
resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==}
engines: {node: '>= 0.4'}
- typed-array-length@1.0.7:
- resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
+ typed-array-length@1.0.8:
+ resolution: {integrity: sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==}
engines: {node: '>= 0.4'}
typedarray-to-buffer@3.1.5:
@@ -11762,6 +11826,18 @@ packages:
utf-8-validate:
optional: true
+ ws@7.5.11:
+ resolution: {integrity: sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==}
+ engines: {node: '>=8.3.0'}
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: ^5.0.2
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+
ws@8.19.0:
resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==}
engines: {node: '>=10.0.0'}
@@ -11774,8 +11850,8 @@ packages:
utf-8-validate:
optional: true
- ws@8.20.1:
- resolution: {integrity: sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==}
+ ws@8.21.0:
+ resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
@@ -13487,7 +13563,7 @@ snapshots:
'@eslint/eslintrc@3.3.3':
dependencies:
- ajv: 6.15.0
+ ajv: 6.12.6
debug: 4.4.3
espree: 10.4.0
globals: 14.0.0
@@ -14912,7 +14988,7 @@ snapshots:
'@rollup/plugin-node-resolve@15.3.1(rollup@2.80.0)':
dependencies:
- '@rollup/pluginutils': 5.3.0(rollup@2.80.0)
+ '@rollup/pluginutils': 5.4.0(rollup@2.80.0)
'@types/resolve': 1.20.2
deepmerge: 4.3.1
is-module: 1.0.0
@@ -14941,7 +15017,7 @@ snapshots:
picomatch: 2.3.2
rollup: 2.80.0
- '@rollup/pluginutils@5.3.0(rollup@2.80.0)':
+ '@rollup/pluginutils@5.4.0(rollup@2.80.0)':
dependencies:
'@types/estree': 1.0.9
estree-walker: 2.0.2
@@ -15470,13 +15546,13 @@ snapshots:
dependencies:
storybook: 10.2.16(@testing-library/dom@10.4.1)(prettier@3.7.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@storybook/addon-vitest@10.2.16(@vitest/browser-playwright@4.0.18)(@vitest/browser@4.1.6(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0))(@vitest/runner@4.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.7.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vitest@4.1.0)':
+ '@storybook/addon-vitest@10.2.16(@vitest/browser-playwright@4.0.18)(@vitest/browser@4.1.8(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0))(@vitest/runner@4.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.2.16(@testing-library/dom@10.4.1)(prettier@3.7.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vitest@4.1.0)':
dependencies:
'@storybook/global': 5.0.0
'@storybook/icons': 2.0.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
storybook: 10.2.16(@testing-library/dom@10.4.1)(prettier@3.7.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
optionalDependencies:
- '@vitest/browser': 4.1.6(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0)
+ '@vitest/browser': 4.1.8(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0)
'@vitest/browser-playwright': 4.0.18(playwright@1.58.2)(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0)
'@vitest/runner': 4.1.0
vitest: 4.1.0(@types/node@24.9.1)(@vitest/browser-playwright@4.0.18)(happy-dom@20.8.9)(jsdom@27.4.0)(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))
@@ -15618,7 +15694,7 @@ snapshots:
'@tanstack/devtools-event-bus@0.4.1':
dependencies:
- ws: 8.20.1
+ ws: 8.21.0
transitivePeerDependencies:
- bufferutil
- utf-8-validate
@@ -16284,33 +16360,33 @@ snapshots:
pixelmatch: 7.1.0
pngjs: 7.0.0
sirv: 3.0.2
- tinyrainbow: 3.1.0
+ tinyrainbow: 3.0.3
vitest: 4.1.0(@types/node@24.9.1)(@vitest/browser-playwright@4.0.18)(happy-dom@20.8.9)(jsdom@27.4.0)(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))
- ws: 8.20.1
+ ws: 8.21.0
transitivePeerDependencies:
- bufferutil
- msw
- utf-8-validate
- vite
- '@vitest/browser@4.1.6(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0)':
+ '@vitest/browser@4.1.8(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0)':
dependencies:
'@blazediff/core': 1.9.1
- '@vitest/mocker': 4.1.6(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))
- '@vitest/utils': 4.1.6
+ '@vitest/mocker': 4.1.8(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))
+ '@vitest/utils': 4.1.8
magic-string: 0.30.21
pngjs: 7.0.0
sirv: 3.0.2
tinyrainbow: 3.1.0
vitest: 4.1.0(@types/node@24.9.1)(@vitest/browser-playwright@4.0.18)(happy-dom@20.8.9)(jsdom@27.4.0)(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))
- ws: 8.20.1
+ ws: 8.21.0
transitivePeerDependencies:
- bufferutil
- msw
- utf-8-validate
- vite
- '@vitest/coverage-v8@4.1.5(@vitest/browser@4.1.6(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0))(vitest@4.1.0)':
+ '@vitest/coverage-v8@4.1.5(@vitest/browser@4.1.8(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0))(vitest@4.1.0)':
dependencies:
'@bcoe/v8-coverage': 1.0.2
'@vitest/utils': 4.1.5
@@ -16324,7 +16400,7 @@ snapshots:
tinyrainbow: 3.1.0
vitest: 4.1.0(@types/node@24.9.1)(@vitest/browser-playwright@4.0.18)(happy-dom@20.8.9)(jsdom@27.4.0)(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))
optionalDependencies:
- '@vitest/browser': 4.1.6(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0)
+ '@vitest/browser': 4.1.8(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0)
'@vitest/coverage-v8@4.1.5(vitest@4.1.0(@opentelemetry/api@1.8.0)(@types/node@24.9.1)(happy-dom@20.8.9)(jsdom@27.4.0)(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.0)(@types/node@24.9.1)(esbuild@0.27.7)(jiti@2.6.1)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.2)))':
dependencies:
@@ -16383,7 +16459,7 @@ snapshots:
'@vitest/spy': 4.1.0
'@vitest/utils': 4.1.0
chai: 6.2.2
- tinyrainbow: 3.1.0
+ tinyrainbow: 3.0.3
'@vitest/mocker@4.0.18(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))':
dependencies:
@@ -16433,9 +16509,9 @@ snapshots:
optionalDependencies:
vite: 8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.0)(@types/node@24.9.1)(esbuild@0.27.7)(jiti@2.6.1)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3)
- '@vitest/mocker@4.1.6(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))':
+ '@vitest/mocker@4.1.8(vite@7.3.2(@types/node@24.9.1)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.8.3))':
dependencies:
- '@vitest/spy': 4.1.6
+ '@vitest/spy': 4.1.8
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
@@ -16447,17 +16523,17 @@ snapshots:
'@vitest/pretty-format@4.0.18':
dependencies:
- tinyrainbow: 3.1.0
+ tinyrainbow: 3.0.3
'@vitest/pretty-format@4.1.0':
dependencies:
- tinyrainbow: 3.1.0
+ tinyrainbow: 3.0.3
'@vitest/pretty-format@4.1.5':
dependencies:
tinyrainbow: 3.1.0
- '@vitest/pretty-format@4.1.6':
+ '@vitest/pretty-format@4.1.8':
dependencies:
tinyrainbow: 3.1.0
@@ -16481,7 +16557,7 @@ snapshots:
'@vitest/spy@4.1.0': {}
- '@vitest/spy@4.1.6': {}
+ '@vitest/spy@4.1.8': {}
'@vitest/utils@3.2.4':
dependencies:
@@ -16492,13 +16568,13 @@ snapshots:
'@vitest/utils@4.0.18':
dependencies:
'@vitest/pretty-format': 4.0.18
- tinyrainbow: 3.1.0
+ tinyrainbow: 3.0.3
'@vitest/utils@4.1.0':
dependencies:
'@vitest/pretty-format': 4.1.0
convert-source-map: 2.0.0
- tinyrainbow: 3.1.0
+ tinyrainbow: 3.0.3
'@vitest/utils@4.1.5':
dependencies:
@@ -16506,9 +16582,9 @@ snapshots:
convert-source-map: 2.0.0
tinyrainbow: 3.1.0
- '@vitest/utils@4.1.6':
+ '@vitest/utils@4.1.8':
dependencies:
- '@vitest/pretty-format': 4.1.6
+ '@vitest/pretty-format': 4.1.8
convert-source-map: 2.0.0
tinyrainbow: 3.1.0
@@ -16909,7 +16985,7 @@ snapshots:
base64-js@1.5.1: {}
- baseline-browser-mapping@2.10.32: {}
+ baseline-browser-mapping@2.10.33: {}
baseline-browser-mapping@2.9.11: {}
@@ -17066,9 +17142,9 @@ snapshots:
browserslist@4.28.2:
dependencies:
- baseline-browser-mapping: 2.10.32
+ baseline-browser-mapping: 2.10.33
caniuse-lite: 1.0.30001793
- electron-to-chromium: 1.5.362
+ electron-to-chromium: 1.5.364
node-releases: 2.0.46
update-browserslist-db: 1.2.3(browserslist@4.28.2)
@@ -18059,7 +18135,7 @@ snapshots:
electron-to-chromium@1.5.267: {}
- electron-to-chromium@1.5.362: {}
+ electron-to-chromium@1.5.364: {}
emoji-regex@8.0.0: {}
@@ -18139,7 +18215,7 @@ snapshots:
has-property-descriptors: 1.0.2
has-proto: 1.2.0
has-symbols: 1.1.0
- hasown: 2.0.3
+ hasown: 2.0.4
internal-slot: 1.1.0
is-array-buffer: 3.0.5
is-callable: 1.2.7
@@ -18168,7 +18244,7 @@ snapshots:
typed-array-buffer: 1.0.3
typed-array-byte-length: 1.0.3
typed-array-byte-offset: 1.0.4
- typed-array-length: 1.0.7
+ typed-array-length: 1.0.8
unbox-primitive: 1.1.0
which-typed-array: 1.1.21
@@ -19017,7 +19093,7 @@ snapshots:
call-bound: 1.0.4
define-properties: 1.2.1
functions-have-names: 1.2.3
- hasown: 2.0.3
+ hasown: 2.0.4
is-callable: 1.2.7
functional-red-black-tree@1.0.1:
@@ -19370,7 +19446,7 @@ snapshots:
dependencies:
function-bind: 1.1.2
- hasown@2.0.3:
+ hasown@2.0.4:
dependencies:
function-bind: 1.1.2
@@ -19534,7 +19610,7 @@ snapshots:
immutable@4.3.8: {}
- immutable@5.1.5:
+ immutable@5.1.6:
optional: true
import-fresh@3.3.1:
@@ -19607,7 +19683,7 @@ snapshots:
internal-slot@1.1.0:
dependencies:
es-errors: 1.3.0
- hasown: 2.0.3
+ hasown: 2.0.4
side-channel: 1.1.0
ioredis@4.28.5:
@@ -19692,7 +19768,7 @@ snapshots:
is-core-module@2.16.2:
dependencies:
- hasown: 2.0.3
+ hasown: 2.0.4
is-data-view@1.0.2:
dependencies:
@@ -19789,7 +19865,7 @@ snapshots:
call-bound: 1.0.4
gopd: 1.2.0
has-tostringtag: 1.0.2
- hasown: 2.0.3
+ hasown: 2.0.4
is-regexp@1.0.0: {}
@@ -22360,7 +22436,7 @@ snapshots:
sass@1.98.0:
dependencies:
chokidar: 4.0.3
- immutable: 5.1.5
+ immutable: 5.1.6
source-map-js: 1.2.1
optionalDependencies:
'@parcel/watcher': 2.5.6
@@ -22623,7 +22699,7 @@ snapshots:
queue-microtask: 1.2.3
randombytes: 2.1.0
readable-stream: 3.6.2
- ws: 7.5.10
+ ws: 7.5.11
transitivePeerDependencies:
- bufferutil
- supports-color
@@ -23616,7 +23692,7 @@ snapshots:
is-typed-array: 1.1.15
reflect.getprototypeof: 1.0.10
- typed-array-length@1.0.7:
+ typed-array-length@1.0.8:
dependencies:
call-bind: 1.0.9
for-each: 0.3.5
@@ -24461,9 +24537,11 @@ snapshots:
ws@7.5.10: {}
+ ws@7.5.11: {}
+
ws@8.19.0: {}
- ws@8.20.1: {}
+ ws@8.21.0: {}
wsl-utils@0.1.0:
dependencies: