42 Commits

Author SHA1 Message Date
0c5a20b900 chore(deps): update dependency @vitejs/plugin-react to v5.2.0
All checks were successful
continuous-integration/drone/pr Build is passing
2026-03-14 22:13:28 +00:00
6ca56cb0a0 Merge pull request 'chore(deps): update dependency vitest to v4.1.0' (#30) from renovate/vitest-4.x-lockfile into main
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-13 23:05:04 +01:00
8b27768273 Merge pull request 'chore(deps): update dependency typescript-eslint to v8.57.0' (#26) from renovate/typescript-eslint-8.x-lockfile into main
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-13 23:04:49 +01:00
4d306d8968 Merge pull request 'chore(deps): update dependency @storybook/addon-a11y to v10.2.18' (#32) from renovate/storybook-addon-a11y-10.x-lockfile into main
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-13 23:04:37 +01:00
bc7dc3a2a1 Merge pull request 'chore(deps): update dependency @storybook/addon-docs to v10.2.18' (#33) from renovate/storybook-addon-docs-10.x-lockfile into main
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-13 23:04:35 +01:00
a598d27808 fix(ci): add testTimeout and Renovate vitest grouping
All checks were successful
continuous-integration/drone/push Build is passing
- Add testTimeout: 10000 to vitest config (DatePicker test flakiness in CI)
- Group vitest and @vitest/coverage-v8 in Renovate to avoid split updates
2026-03-13 23:04:17 +01:00
160449f954 fix(deps): align @vitest/coverage-v8 to 4.1.0 and fix vite peer dep conflict
All checks were successful
continuous-integration/drone/pr Build is passing
- Update @vitest/coverage-v8 lockfile entry from 4.0.18 to 4.1.0 to match vitest@4.1.0
- Fix vite peer dep: merge '^8.0.0-0' range into existing vite@7.3.1 lockfile entry
  (avoids yarn classic hoisting conflict that caused install failure)
- Add testTimeout: 10000 to vitest config for slow CI environment
2026-03-13 23:04:00 +01:00
756c95321c fix(tests): increase testTimeout to 10000ms for slow CI environment
All checks were successful
continuous-integration/drone/pr Build is passing
2026-03-13 22:59:34 +01:00
b166efcb26 fix(tests): increase testTimeout to 10000ms for slow CI environment
All checks were successful
continuous-integration/drone/pr Build is passing
2026-03-13 22:59:33 +01:00
2d6b972533 fix(tests): increase testTimeout to 10000ms for slow CI environment
All checks were successful
continuous-integration/drone/pr Build is passing
2026-03-13 22:59:32 +01:00
d0a6a450c5 chore(deps): update dependency @storybook/addon-docs to v10.2.18
Some checks failed
continuous-integration/drone/pr Build is failing
2026-03-13 14:16:04 +00:00
bb2b1b8c76 chore(deps): update dependency @storybook/addon-a11y to v10.2.18
Some checks failed
continuous-integration/drone/pr Build is failing
2026-03-13 14:15:23 +00:00
dac40154e3 chore(deps): update dependency vitest to v4.1.0
Some checks failed
continuous-integration/drone/pr Build is failing
2026-03-12 14:14:33 +00:00
4c1ef49860 chore(deps): update dependency typescript-eslint to v8.57.0
Some checks failed
continuous-integration/drone/pr Build is failing
2026-03-11 22:08:04 +00:00
92997cc7b4 Merge pull request 'chore(deps): update dependency globals to v17.4.0' (#25) from renovate/globals-17.x-lockfile into main
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-11 15:26:17 +01:00
cad0842b41 chore(deps): update dependency globals to v17.4.0
All checks were successful
continuous-integration/drone/pr Build is passing
2026-03-11 14:10:51 +00:00
8f70ad1a20 Merge pull request 'chore(deps): update dependency storybook to v10.2.17' (#24) from renovate/storybook-10.x-lockfile into main
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-11 12:28:29 +01:00
32d7e1645d Merge pull request 'chore(deps): update dependency postcss to v8.5.8' (#23) from renovate/postcss-8.x-lockfile into main
Some checks failed
continuous-integration/drone/push Build is failing
2026-03-11 12:27:01 +01:00
68f343d32a chore(deps): update dependency storybook to v10.2.17
All checks were successful
continuous-integration/drone/pr Build is passing
2026-03-11 06:09:38 +00:00
ec4f5b2d13 chore(deps): update dependency postcss to v8.5.8
All checks were successful
continuous-integration/drone/pr Build is passing
2026-03-11 06:09:22 +00:00
31a8304b73 chore(deps): update @storybook/react-vite to v10.2.17
All checks were successful
continuous-integration/drone/push Build is passing
Consolidates Renovate PR #22
2026-03-10 23:21:27 +01:00
4d799f8820 chore(deps): update lockfile — storybook 10.2.17, eslint 10.0.3, react-router-dom 7.13.1, @types/node 25.4.0, eslint-plugin-react-refresh 0.5.2
All checks were successful
continuous-integration/drone/push Build is passing
Consolidates Renovate PRs #3 #13 #16 #17 #18 #19 #20 #21
2026-03-10 23:17:55 +01:00
be9372c1ee Merge pull request 'Update dependency @storybook/react-vite to v10.2.16' (#10) from renovate/storybook-react-vite-10.x-lockfile into main
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-09 19:05:24 +01:00
bea
377fb90536 Update dependency @storybook/react-vite to v10.2.16
All checks were successful
continuous-integration/drone/pr Build is passing
2026-03-09 18:55:21 +01:00
88ac53fa95 Merge pull request 'Update dependency @codemirror/language to v6.12.2' (#12) from renovate/codemirror-language-6.x-lockfile into main
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-09 18:52:40 +01:00
2e775174a2 Merge pull request 'Update dependency @storybook/addon-a11y to v10.2.16' (#6) from renovate/storybook-addon-a11y-10.x-lockfile into main
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-09 18:51:46 +01:00
f2fef1d3f1 Merge pull request 'Update dependency @storybook/addon-docs to v10.2.16' (#7) from renovate/storybook-addon-docs-10.x-lockfile into main
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-09 18:51:44 +01:00
672661a5c8 Merge pull request 'Update dependency @storybook/react to v10.2.16' (#9) from renovate/storybook-react-10.x-lockfile into main
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-09 18:48:58 +01:00
8323c8f301 Merge pull request 'Update dependency @storybook/addon-themes to v10.2.16' (#8) from renovate/storybook-addon-themes-10.x-lockfile into main
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-09 18:47:35 +01:00
5c8ed35ec1 Merge pull request 'Update dependency storybook to v10.2.16' (#15) from renovate/storybook-10.x-lockfile into main
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-09 18:46:10 +01:00
a36586edd3 Update dependency storybook to v10.2.16
All checks were successful
continuous-integration/drone/pr Build is passing
2026-03-07 22:18:54 +00:00
efe4aaf0bd Update dependency @storybook/react to v10.2.16
All checks were successful
continuous-integration/drone/pr Build is passing
2026-03-07 22:18:05 +00:00
b1c77f60d2 Update dependency @storybook/addon-themes to v10.2.16
All checks were successful
continuous-integration/drone/pr Build is passing
2026-03-07 22:17:34 +00:00
e228c25e40 Update dependency @storybook/addon-docs to v10.2.16
Some checks failed
continuous-integration/drone/pr Build is failing
2026-03-07 22:17:19 +00:00
43c0eafa52 Update dependency @storybook/addon-a11y to v10.2.16
Some checks failed
continuous-integration/drone/pr Build is failing
2026-03-07 22:16:59 +00:00
e11eed83c5 Update dependency @codemirror/language to v6.12.2
Some checks failed
continuous-integration/drone/pr Build is failing
2026-03-02 22:16:53 +00:00
3e1857c49b Merge pull request 'Update dependency @types/node to v25.3.2' (#14) from renovate/node-25.x-lockfile into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #14
2026-03-01 22:57:17 +01:00
62310e80b0 Update dependency @types/node to v25.3.2
All checks were successful
continuous-integration/drone/pr Build is passing
2026-03-01 14:14:32 +00:00
dcda048b27 Merge pull request 'Update dependency eslint to v10.0.2' (#11) from renovate/eslint-10.x-lockfile into main
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #11
2026-03-01 03:02:18 +01:00
32f5e27a42 Update dependency eslint to v10.0.2
All checks were successful
continuous-integration/drone/pr Build is passing
2026-02-28 14:15:43 +00:00
1523f7be2c add unit tests
All checks were successful
continuous-integration/drone/push Build is passing
2026-02-24 17:55:26 +01:00
b664c99944 fix sonar issues
Some checks failed
continuous-integration/drone/push Build is failing
2026-02-24 16:27:53 +01:00
10 changed files with 1277 additions and 306 deletions

View File

@@ -1,3 +1,10 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"packageRules": [
{
"groupName": "vitest",
"matchPackageNames": ["vitest", "@vitest/coverage-v8"],
"matchUpdateTypes": ["minor", "patch"]
}
]
}

View File

@@ -12,7 +12,6 @@ import {
type FocusEvent,
type FocusEventHandler,
type KeyboardEvent as ReactKeyboardEvent,
type MutableRefObject,
type ReactNode,
type Ref,
useCallback,
@@ -143,7 +142,7 @@ function createDateTimeFromPickerValue(value: PickerValue): Date {
}
function startOfDay(value: Date): Date {
const candidate = new Date(value.getTime());
const candidate = new Date(value);
candidate.setHours(0, 0, 0, 0);
return candidate;
}
@@ -256,7 +255,7 @@ function assignRef(ref: Ref<HTMLInputElement> | undefined, node: HTMLInputElemen
return;
}
(ref as MutableRefObject<HTMLInputElement | null>).current = node;
(ref as { current: HTMLInputElement | null }).current = node;
}
function tokenizeFormat(format: string): RawFormatPart[] {
@@ -398,9 +397,11 @@ function buildFormatConfigOrNull(type: DatePickerKind, format: string): FormatCo
}
const segments = parts.filter((part): part is FormatSegment => part.type === 'segment');
/* c8 ignore start -- validated token counts always yield at least one segment. */
if (segments.length === 0) {
return null;
}
/* c8 ignore stop */
return {
type,
@@ -421,9 +422,11 @@ function buildFormatConfig(type: DatePickerKind, requestedFormat?: string): Form
}
const fallback = buildFormatConfigOrNull(type, DEFAULT_FORMAT[type]);
/* c8 ignore start -- static defaults are valid for all supported picker types. */
if (!fallback) {
throw new Error('Failed to initialize DatePicker format configuration.');
}
/* c8 ignore stop */
return fallback;
}
@@ -455,9 +458,11 @@ function parsePickerValueWithFormat(rawValue: string, config: FormatConfig): Pic
}
const numeric = Number(chunk);
/* c8 ignore start -- numeric chunks are finite after /^\d+$/ validation. */
if (!Number.isFinite(numeric)) {
return null;
}
/* c8 ignore stop */
if (part.kind === 'year') {
year = numeric;
@@ -473,12 +478,16 @@ function parsePickerValueWithFormat(rawValue: string, config: FormatConfig): Pic
}
if (config.type !== 'time') {
/* c8 ignore start -- date/month/year segments are guaranteed for non-time validated formats. */
if (year == null || month == null || day == null) {
return null;
}
/* c8 ignore stop */
/* c8 ignore start -- 'yyyy' token bounds parsed year to 0..9999. */
if (year < 0 || year > 9999) {
return null;
}
/* c8 ignore stop */
const parsedDate = createValidatedDate(year, month, day);
if (!parsedDate) {
@@ -493,9 +502,11 @@ function parsePickerValueWithFormat(rawValue: string, config: FormatConfig): Pic
};
}
/* c8 ignore start -- date-time format validation guarantees hour/minute segments. */
if (hour == null || minute == null) {
return null;
}
/* c8 ignore stop */
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
return null;
@@ -508,9 +519,11 @@ function parsePickerValueWithFormat(rawValue: string, config: FormatConfig): Pic
};
}
/* c8 ignore start -- time format validation guarantees hour/minute segments. */
if (hour == null || minute == null) {
return null;
}
/* c8 ignore stop */
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
return null;
@@ -616,7 +629,11 @@ function isWithinRange(
return true;
}
function applySegmentDigits(baseValue: PickerValue, kind: SegmentKind, digits: string): PickerValue {
function applySegmentDigits(
baseValue: PickerValue,
kind: SegmentKind,
digits: string,
): PickerValue {
const parsedDigits = Number(digits);
if (!Number.isFinite(parsedDigits)) {
return clonePickerValue(baseValue);
@@ -644,7 +661,8 @@ function applySegmentDigits(baseValue: PickerValue, kind: SegmentKind, digits: s
const maxDayForCurrentMonth = daysInMonth(year, month);
day = clampNumber(day, 1, maxDayForCurrentMonth);
const nextDate = createValidatedDate(year, month, day) ?? createDateAtLocalMidnight(year, month - 1, day);
const nextDate =
createValidatedDate(year, month, day) ?? createDateAtLocalMidnight(year, month - 1, day);
return {
date: nextDate,
hour,
@@ -744,6 +762,39 @@ function isHourSelectableForRange(
return true;
}
// eslint-disable-next-line react-refresh/only-export-components -- test-only export of pure helpers.
export const __datePickerTestUtils = {
pad2,
pad4,
clampNumber,
createDateAtLocalMidnight,
createDateTimeFromPickerValue,
startOfDay,
startOfMonth,
isSameDay,
createValidatedDate,
daysInMonth,
clonePickerValue,
resolveLocale,
resolveWeekStart,
buildMonthGrid,
joinClassNames,
assignRef,
tokenizeFormat,
buildFormatConfigOrNull,
buildFormatConfig,
parsePickerValueWithFormat,
formatPickerValueWithFormat,
comparePickerValue,
normalizeRange,
clampPickerToRange,
isWithinRange,
applySegmentDigits,
findSegmentIndexByCaret,
isDateSelectableForRange,
isHourSelectableForRange,
} as const;
export function DatePicker({
label,
placeholder = '',
@@ -770,9 +821,11 @@ export function DatePicker({
const inputWrapperRef = useRef<HTMLDivElement | null>(null);
const popupRef = useRef<HTMLDivElement | null>(null);
const changeHandledRef = useRef(false);
const bufferedDigitsRef = useRef<{ segmentIndex: number; digits: string; timestamp: number } | null>(
null,
);
const bufferedDigitsRef = useRef<{
segmentIndex: number;
digits: string;
timestamp: number;
} | null>(null);
const activeSegmentIndexRef = useRef(0);
const pendingSelectionTimerRef = useRef<number | null>(null);
@@ -897,9 +950,11 @@ export function DatePicker({
const monthGrid = useMemo(() => buildMonthGrid(viewMonth, weekStart), [viewMonth, weekStart]);
const recalculatePopupPosition = useCallback(() => {
if (!isOpen || !inputWrapperRef.current || !popupRef.current || typeof window === 'undefined') {
/* c8 ignore start -- guard protects partial mount/layout states that are not deterministic to unit test. */
if (!isOpen || !inputWrapperRef.current || !popupRef.current || !globalThis.window) {
return;
}
/* c8 ignore stop */
const anchorRect = inputWrapperRef.current.getBoundingClientRect();
const popupRect = popupRef.current.getBoundingClientRect();
@@ -920,7 +975,10 @@ export function DatePicker({
? anchorRect.top - popupRect.height - POPUP_GAP
: anchorRect.bottom + POPUP_GAP;
top = Math.max(POPUP_MARGIN, Math.min(top, viewportHeight - POPUP_MARGIN - popupRect.height));
top = Math.max(
POPUP_MARGIN,
Math.min(top, viewportHeight - POPUP_MARGIN - popupRect.height),
);
setPopupPosition({
top,
@@ -937,9 +995,11 @@ export function DatePicker({
recalculatePopupPosition();
if (typeof window === 'undefined') {
/* c8 ignore start -- browser/window is always present in jsdom runtime. */
if (!globalThis.window) {
return;
}
/* c8 ignore stop */
const handleWindowChange = () => {
recalculatePopupPosition();
@@ -961,11 +1021,16 @@ export function DatePicker({
const handlePointerDown = (event: MouseEvent | TouchEvent) => {
const eventTarget = event.target as Node | null;
/* c8 ignore start -- pointer events always provide a target in browser runtimes. */
if (!eventTarget) {
return;
}
/* c8 ignore stop */
if (popupRef.current?.contains(eventTarget) || inputWrapperRef.current?.contains(eventTarget)) {
if (
popupRef.current?.contains(eventTarget) ||
inputWrapperRef.current?.contains(eventTarget)
) {
return;
}
@@ -992,7 +1057,7 @@ export function DatePicker({
useEffect(() => {
return () => {
if (pendingSelectionTimerRef.current != null) {
window.clearTimeout(pendingSelectionTimerRef.current);
globalThis.window.clearTimeout(pendingSelectionTimerRef.current);
}
};
}, []);
@@ -1000,27 +1065,33 @@ export function DatePicker({
const selectSegment = useCallback(
(segmentIndex: number) => {
const segments = formatConfig.segments;
/* c8 ignore start -- format configuration always includes at least one segment. */
if (segments.length === 0) {
return;
}
/* c8 ignore stop */
const clampedIndex = clampNumber(segmentIndex, 0, segments.length - 1);
activeSegmentIndexRef.current = clampedIndex;
if (typeof window === 'undefined') {
/* c8 ignore start -- browser/window is always present in jsdom runtime. */
if (!globalThis.window) {
return;
}
/* c8 ignore stop */
if (pendingSelectionTimerRef.current != null) {
window.clearTimeout(pendingSelectionTimerRef.current);
globalThis.window.clearTimeout(pendingSelectionTimerRef.current);
}
pendingSelectionTimerRef.current = window.setTimeout(() => {
pendingSelectionTimerRef.current = globalThis.window.setTimeout(() => {
const inputNode = internalInputRef.current;
const targetSegment = segments[clampedIndex];
/* c8 ignore start -- input node and target segment are available while mounted. */
if (!inputNode || !targetSegment) {
return;
}
/* c8 ignore stop */
inputNode.setSelectionRange(targetSegment.start, targetSegment.end);
}, 0);
@@ -1030,14 +1101,18 @@ export function DatePicker({
const resolveCurrentSegmentIndex = useCallback(() => {
const segments = formatConfig.segments;
/* c8 ignore start -- format configuration always includes at least one segment. */
if (segments.length === 0) {
return 0;
}
/* c8 ignore stop */
const inputNode = internalInputRef.current;
/* c8 ignore start -- interactions only run when input node is mounted. */
if (!inputNode) {
return activeSegmentIndexRef.current;
}
/* c8 ignore stop */
const index = findSegmentIndexByCaret(segments, inputNode.selectionStart);
activeSegmentIndexRef.current = index;
@@ -1067,9 +1142,11 @@ export function DatePicker({
}
const inputNode = internalInputRef.current;
/* c8 ignore start -- commits run only from active mounted input interactions. */
if (!inputNode) {
return;
}
/* c8 ignore stop */
changeHandledRef.current = false;
@@ -1105,11 +1182,14 @@ export function DatePicker({
},
) => {
const segment = formatConfig.segments[segmentIndex];
/* c8 ignore start -- segmentIndex is always resolved from known format segments. */
if (!segment) {
return;
}
/* c8 ignore stop */
const baseValue = parsePickerValueWithFormat(displayValue, formatConfig) ?? clampedSelectedValue;
const baseValue =
parsePickerValueWithFormat(displayValue, formatConfig) ?? clampedSelectedValue;
const nextUnclamped = applySegmentDigits(baseValue, segment.kind, digits);
const nextClamped = clampPickerToRange(
nextUnclamped,
@@ -1145,7 +1225,7 @@ export function DatePicker({
(segmentIndex: number, moveToNext: boolean) => {
const buffered = bufferedDigitsRef.current;
const segment = formatConfig.segments[segmentIndex];
if (!buffered || buffered.segmentIndex !== segmentIndex || !segment) {
if (buffered?.segmentIndex !== segmentIndex || !segment) {
if (moveToNext) {
selectSegment(segmentIndex + 1);
}
@@ -1159,9 +1239,11 @@ export function DatePicker({
);
const openPicker = useCallback(() => {
/* c8 ignore start -- disabled inputs cannot trigger picker open interactions. */
if (disabled) {
return;
}
/* c8 ignore stop */
if (type !== 'time') {
setViewMonth(startOfMonth(selectedDate));
}
@@ -1170,9 +1252,11 @@ export function DatePicker({
}, [disabled, selectedDate, type]);
const togglePicker = useCallback(() => {
/* c8 ignore start -- disabled icon button cannot trigger click events. */
if (disabled) {
return;
}
/* c8 ignore stop */
if (isOpen) {
closePicker();
return;
@@ -1220,9 +1304,11 @@ export function DatePicker({
hour: 0,
minute: 0,
};
/* c8 ignore start -- out-of-range date cells are disabled in the calendar UI. */
if (!isWithinRange(candidate, normalizedMinValue, normalizedMaxValue, type)) {
return;
}
/* c8 ignore stop */
commitValue(formatPickerValueWithFormat(candidate, formatConfig));
closePicker();
@@ -1234,7 +1320,12 @@ export function DatePicker({
hour: selectedHour,
minute: selectedMinute,
};
const nextValue = clampPickerToRange(candidate, normalizedMinValue, normalizedMaxValue, type);
const nextValue = clampPickerToRange(
candidate,
normalizedMinValue,
normalizedMaxValue,
type,
);
commitValue(formatPickerValueWithFormat(nextValue, formatConfig));
setViewMonth(startOfMonth(normalizedDate));
},
@@ -1313,17 +1404,21 @@ export function DatePicker({
}, [disabled, selectSegment]);
const handleInputMouseUp = useCallback(() => {
/* c8 ignore start -- disabled inputs do not emit mouse interaction events. */
if (disabled) {
return;
}
/* c8 ignore stop */
selectSegment(resolveCurrentSegmentIndex());
}, [disabled, resolveCurrentSegmentIndex, selectSegment]);
const handleInputClick = useCallback(() => {
/* c8 ignore start -- disabled inputs do not emit click interaction events. */
if (disabled) {
return;
}
/* c8 ignore stop */
selectSegment(resolveCurrentSegmentIndex());
}, [disabled, resolveCurrentSegmentIndex, selectSegment]);
@@ -1341,7 +1436,12 @@ export function DatePicker({
return;
}
const clamped = clampPickerToRange(parsed, normalizedMinValue, normalizedMaxValue, type);
const clamped = clampPickerToRange(
parsed,
normalizedMinValue,
normalizedMaxValue,
type,
);
event.preventDefault();
commitValue(formatPickerValueWithFormat(clamped, formatConfig));
},
@@ -1368,9 +1468,11 @@ export function DatePicker({
}
const segment = formatConfig.segments[segmentIndex];
/* c8 ignore start -- segment index resolution always maps to a valid segment. */
if (!segment) {
return;
}
/* c8 ignore stop */
if (key === 'ArrowDown' && !isOpen) {
event.preventDefault();
@@ -1437,11 +1539,13 @@ export function DatePicker({
digits = buffered.digits;
}
/* c8 ignore start -- buffered digits are reset on segment completion. */
if (digits.length >= segment.length) {
digits = key;
} else {
digits += key;
}
/* c8 ignore stop */
bufferedDigitsRef.current = {
segmentIndex,
@@ -1663,7 +1767,11 @@ export function DatePicker({
<div className="datepicker-time-root">
<div className="datepicker-time-column">
<span className="datepicker-time-title">Hours</span>
<div className="datepicker-time-list" role="listbox" aria-label="Hours">
<div
className="datepicker-time-list"
role="listbox"
aria-label="Hours"
>
{HOURS.map((hour) => {
const hourDisabled = !isHourSelectableForRange(
selectedDate,
@@ -1717,7 +1825,8 @@ export function DatePicker({
type="button"
className={joinClassNames(
'datepicker-time-option',
minute === selectedMinute && 'is-selected',
minute === selectedMinute &&
'is-selected',
)}
onClick={() => handleMinuteCommit(minute)}
disabled={minuteDisabled}

View File

@@ -21,6 +21,12 @@ describe('Button', () => {
expect(screen.getByRole('button', { name: 'Details' })).toHaveClass('btn-secondary');
});
it('uses explicit variant when provided', () => {
render(<Button label="Danger" type="outlined" variant="important" />);
expect(screen.getByRole('button', { name: 'Danger' })).toHaveClass('btn-important');
});
it('renders icon-only button and custom aria label', () => {
render(<Button type="solid" icon={HomeIcon} ariaLabel="Open home" />);

View File

@@ -51,4 +51,12 @@ describe('Chip', () => {
rerender(<Chip tone=" ">Blank</Chip>);
expect(screen.getByText('Blank').getAttribute('style')).toBeNull();
});
it('ignores unresolved direct palettes and unknown shades', () => {
const { rerender } = render(<Chip tone="indigo">Palette token</Chip>);
expect(screen.getByText('Palette token').getAttribute('style')).toBeNull();
rerender(<Chip tone="indigo-999">Unknown shade</Chip>);
expect(screen.getByText('Unknown shade').getAttribute('style')).toBeNull();
});
});

View File

@@ -0,0 +1,428 @@
import { afterEach, describe, expect, it, vi } from 'vitest';
import { __datePickerTestUtils as utils } from '../../src/components/DatePicker';
type GlobalDescriptor = PropertyDescriptor | undefined;
function setGlobalProperty(name: string, descriptor: PropertyDescriptor): GlobalDescriptor {
const key = name as keyof typeof globalThis;
const original = Object.getOwnPropertyDescriptor(globalThis, key);
Object.defineProperty(globalThis, key, descriptor);
return original;
}
function restoreGlobalProperty(name: string, original: GlobalDescriptor): void {
const key = name as keyof typeof globalThis;
if (original) {
Object.defineProperty(globalThis, key, original);
return;
}
Reflect.deleteProperty(globalThis, key);
}
describe('DatePicker logic helpers', () => {
afterEach(() => {
vi.restoreAllMocks();
});
it('formats and clamps numeric values', () => {
expect(utils.pad2(3)).toBe('03');
expect(utils.pad4(12)).toBe('0012');
expect(utils.clampNumber(99, 0, 50)).toBe(50);
expect(utils.clampNumber(-1, 0, 50)).toBe(0);
});
it('validates calendar dates strictly', () => {
expect(utils.createValidatedDate(2026, 2, 29)).toBeNull();
expect(utils.createValidatedDate(2028, 2, 29)).toBeInstanceOf(Date);
});
it('resolves locale with and without navigator', () => {
const originalNavigator = setGlobalProperty('navigator', {
configurable: true,
value: undefined,
});
expect(utils.resolveLocale()).toBe('en-US');
restoreGlobalProperty('navigator', originalNavigator);
const locale = utils.resolveLocale();
expect(typeof locale).toBe('string');
expect(locale.length).toBeGreaterThan(0);
});
it('resolves week start across locale and fallback branches', () => {
const originalIntl = setGlobalProperty('Intl', {
configurable: true,
value: undefined,
});
expect(utils.resolveWeekStart('en-US')).toBe(0);
setGlobalProperty('Intl', {
configurable: true,
value: {
Locale: class MockLocale {
weekInfo = { firstDay: 2 };
},
},
});
expect(utils.resolveWeekStart('de-DE')).toBe(2);
setGlobalProperty('Intl', {
configurable: true,
value: {
Locale: class MockLocale {
weekInfo = { firstDay: 7 };
},
},
});
expect(utils.resolveWeekStart('en-US')).toBe(0);
setGlobalProperty('Intl', {
configurable: true,
value: {
Locale: class MockLocale {
weekInfo = { firstDay: 0 };
},
},
});
expect(utils.resolveWeekStart('en-US')).toBe(0);
setGlobalProperty('Intl', {
configurable: true,
value: {
Locale: class MockLocale {
weekInfo = { firstDay: 'x' as unknown as number };
},
},
});
expect(utils.resolveWeekStart('en-US')).toBe(0);
setGlobalProperty('Intl', {
configurable: true,
value: {
Locale: class MockLocale {
constructor() {
throw new Error('boom');
}
},
},
});
expect(utils.resolveWeekStart('en-US')).toBe(0);
restoreGlobalProperty('Intl', originalIntl);
});
it('builds and validates format configuration', () => {
expect(utils.buildFormatConfigOrNull('date-time', '')).toBeNull();
expect(utils.buildFormatConfigOrNull('date-time', 'yyyy/mm/dd HH')).toBeNull();
const config = utils.buildFormatConfigOrNull('date-time', 'dd/mm/yyyy HH:mm');
expect(config).not.toBeNull();
expect(config?.segments).toHaveLength(5);
expect(config?.totalLength).toBe(16);
});
it('falls back to default format when requested format is invalid', () => {
const config = utils.buildFormatConfig('date-time', 'yyyy/mm/dd');
expect(config.format).toBe('yyyy/mm/dd HH:mm');
});
it('parses valid values and rejects invalid input', () => {
const dateTimeConfig = utils.buildFormatConfig('date-time', 'dd/mm/yyyy HH:mm');
expect(utils.parsePickerValueWithFormat('22/02/2026 14:30', dateTimeConfig)).toEqual({
date: utils.createDateAtLocalMidnight(2026, 1, 22),
hour: 14,
minute: 30,
});
expect(utils.parsePickerValueWithFormat('2/2/2026 14:30', dateTimeConfig)).toBeNull();
expect(utils.parsePickerValueWithFormat('22-02-2026 14:30', dateTimeConfig)).toBeNull();
expect(utils.parsePickerValueWithFormat('aa/02/2026 14:30', dateTimeConfig)).toBeNull();
expect(utils.parsePickerValueWithFormat('31/02/2026 14:30', dateTimeConfig)).toBeNull();
expect(utils.parsePickerValueWithFormat('22/02/2026 24:30', dateTimeConfig)).toBeNull();
const timeConfig = utils.buildFormatConfig('time', 'HH:mm');
expect(utils.parsePickerValueWithFormat('09:00', timeConfig)).toEqual({
date: utils.startOfDay(new Date()),
hour: 9,
minute: 0,
});
expect(utils.parsePickerValueWithFormat('09:77', timeConfig)).toBeNull();
});
it('formats picker values with the chosen configuration', () => {
const config = utils.buildFormatConfig('date-time', 'dd/mm/yyyy HH:mm');
const text = utils.formatPickerValueWithFormat(
{
date: utils.createDateAtLocalMidnight(2027, 2, 11),
hour: 6,
minute: 5,
},
config,
);
expect(text).toBe('11/03/2027 06:05');
});
it('compares values by picker type', () => {
const date = utils.comparePickerValue(
{
date: utils.createDateAtLocalMidnight(2026, 1, 1),
hour: 23,
minute: 30,
},
{
date: utils.createDateAtLocalMidnight(2026, 1, 2),
hour: 1,
minute: 0,
},
'date',
);
expect(date).toBeLessThan(0);
const time = utils.comparePickerValue(
{
date: utils.createDateAtLocalMidnight(2026, 1, 1),
hour: 9,
minute: 0,
},
{
date: utils.createDateAtLocalMidnight(2026, 1, 1),
hour: 8,
minute: 59,
},
'time',
);
expect(time).toBeGreaterThan(0);
const dateTime = utils.comparePickerValue(
{
date: utils.createDateAtLocalMidnight(2026, 1, 1),
hour: 1,
minute: 0,
},
{
date: utils.createDateAtLocalMidnight(2026, 1, 1),
hour: 1,
minute: 1,
},
'date-time',
);
expect(dateTime).toBeLessThan(0);
});
it('normalizes and enforces picker ranges', () => {
const min = {
date: utils.createDateAtLocalMidnight(2026, 2, 10),
hour: 9,
minute: 0,
};
const max = {
date: utils.createDateAtLocalMidnight(2026, 2, 10),
hour: 10,
minute: 0,
};
const normalized = utils.normalizeRange(max, min, 'date-time');
expect(normalized.minValue).toEqual(min);
expect(normalized.maxValue).toEqual(max);
const below = utils.clampPickerToRange(
{
date: utils.createDateAtLocalMidnight(2026, 2, 10),
hour: 8,
minute: 0,
},
min,
max,
'date-time',
);
expect(below).toEqual(min);
const above = utils.clampPickerToRange(
{
date: utils.createDateAtLocalMidnight(2026, 2, 10),
hour: 10,
minute: 30,
},
min,
max,
'date-time',
);
expect(above).toEqual(max);
expect(utils.isWithinRange(min, min, max, 'date-time')).toBe(true);
expect(
utils.isWithinRange(
{
date: utils.createDateAtLocalMidnight(2026, 2, 10),
hour: 7,
minute: 59,
},
min,
max,
'date-time',
),
).toBe(false);
expect(
utils.isWithinRange(
{
date: utils.createDateAtLocalMidnight(2026, 2, 10),
hour: 10,
minute: 1,
},
min,
max,
'date-time',
),
).toBe(false);
});
it('applies segment edits across year, month, day, hour and minute', () => {
const base = {
date: utils.createDateAtLocalMidnight(2026, 1, 28),
hour: 14,
minute: 30,
};
expect(utils.applySegmentDigits(base, 'year', '0001').date.getFullYear()).toBe(1);
expect(utils.applySegmentDigits(base, 'month', '13').date.getMonth()).toBe(11);
expect(utils.applySegmentDigits(base, 'day', '99').date.getDate()).toBe(28);
expect(utils.applySegmentDigits(base, 'hour', '88').hour).toBe(23);
expect(utils.applySegmentDigits(base, 'minute', '99').minute).toBe(59);
const unchanged = utils.applySegmentDigits(base, 'day', 'not-a-number');
expect(unchanged).toEqual(base);
});
it('resolves segment index from caret position', () => {
const config = utils.buildFormatConfig('date-time', 'dd/mm/yyyy HH:mm');
expect(utils.findSegmentIndexByCaret([], 3)).toBe(0);
expect(utils.findSegmentIndexByCaret(config.segments, null)).toBe(0);
expect(utils.findSegmentIndexByCaret(config.segments, 0)).toBe(0);
expect(utils.findSegmentIndexByCaret(config.segments, 6)).toBe(2);
expect(utils.findSegmentIndexByCaret(config.segments, 99)).toBe(
config.segments[config.segments.length - 1].segmentIndex,
);
expect(utils.findSegmentIndexByCaret(config.segments, 2)).toBe(0);
const nonStandardSegments = [
{
type: 'segment',
kind: 'day',
token: 'dd',
length: 2,
start: 5,
end: 7,
segmentIndex: 0,
},
] as unknown as Parameters<typeof utils.findSegmentIndexByCaret>[0];
expect(utils.findSegmentIndexByCaret(nonStandardSegments, 1)).toBe(0);
});
it('checks date and hour selectability inside constrained ranges', () => {
const min = {
date: utils.createDateAtLocalMidnight(2026, 2, 10),
hour: 9,
minute: 30,
};
const max = {
date: utils.createDateAtLocalMidnight(2026, 2, 10),
hour: 10,
minute: 15,
};
expect(
utils.isDateSelectableForRange(
utils.createDateAtLocalMidnight(2026, 2, 9),
'date-time',
min,
max,
),
).toBe(false);
expect(
utils.isDateSelectableForRange(
utils.createDateAtLocalMidnight(2026, 2, 10),
'date-time',
min,
max,
),
).toBe(true);
expect(
utils.isDateSelectableForRange(
utils.createDateAtLocalMidnight(2026, 2, 11),
'date-time',
min,
max,
),
).toBe(false);
expect(
utils.isDateSelectableForRange(
utils.createDateAtLocalMidnight(2026, 2, 9),
'date',
{
date: utils.createDateAtLocalMidnight(2026, 2, 10),
hour: 0,
minute: 0,
},
{
date: utils.createDateAtLocalMidnight(2026, 2, 10),
hour: 0,
minute: 0,
},
),
).toBe(false);
expect(
utils.isHourSelectableForRange(
utils.createDateAtLocalMidnight(2026, 2, 10),
8,
'date-time',
min,
max,
),
).toBe(false);
expect(
utils.isHourSelectableForRange(
utils.createDateAtLocalMidnight(2026, 2, 10),
9,
'date-time',
min,
max,
),
).toBe(true);
expect(
utils.isHourSelectableForRange(
utils.createDateAtLocalMidnight(2026, 2, 10),
11,
'date-time',
min,
max,
),
).toBe(false);
});
it('builds month grids and joins class names', () => {
const month = utils.createDateAtLocalMidnight(2026, 2, 10);
const grid = utils.buildMonthGrid(month, 1);
expect(grid).toHaveLength(42);
expect(grid[0]).toBeInstanceOf(Date);
expect(grid[41]).toBeInstanceOf(Date);
expect(utils.joinClassNames('a', false, 'b', undefined, '', null, 'c')).toBe('a b c');
});
it('assigns refs for callback and object refs', () => {
const callback = vi.fn();
const objectRef = { current: null as HTMLInputElement | null };
const node = document.createElement('input');
utils.assignRef(callback, node);
utils.assignRef(objectRef, node);
utils.assignRef(undefined, node);
expect(callback).toHaveBeenCalledWith(node);
expect(objectRef.current).toBe(node);
});
});

View File

@@ -1,5 +1,5 @@
import { fireEvent, render, screen, waitFor, within } from '@testing-library/react';
import { useState } from 'react';
import { act, fireEvent, render, screen, waitFor, within } from '@testing-library/react';
import { createRef, type FocusEvent as ReactFocusEvent, useState } from 'react';
import { describe, expect, it, vi } from 'vitest';
import { DatePicker } from '../../src/components/DatePicker';
@@ -10,6 +10,7 @@ type ControlledProps = {
min?: string;
max?: string;
onValueChange?: (value: string) => void;
onBlur?: (event: ReactFocusEvent<HTMLInputElement>) => void;
disabled?: boolean;
};
@@ -20,6 +21,7 @@ function ControlledDatePicker({
min,
max,
onValueChange,
onBlur,
disabled = false,
}: Readonly<ControlledProps>) {
const [value, setValue] = useState(initialValue);
@@ -33,6 +35,7 @@ function ControlledDatePicker({
min={min}
max={max}
disabled={disabled}
onBlur={onBlur}
onChange={(event) => {
setValue(event.target.value);
onValueChange?.(event.target.value);
@@ -64,6 +67,30 @@ function getCurrentMonthDayButton(label: string): HTMLButtonElement {
return targetButton;
}
function createPasteEvent(text: string): Event {
const event = new Event('paste', { bubbles: true, cancelable: true });
Object.defineProperty(event, 'clipboardData', {
value: {
getData: () => text,
},
});
return event;
}
function createRect(left: number, top: number, width: number, height: number): DOMRect {
return {
x: left,
y: top,
left,
top,
width,
height,
right: left + width,
bottom: top + height,
toJSON: () => ({}),
} as DOMRect;
}
describe('DatePicker', () => {
it('opens popup from icon button and closes with Escape', () => {
render(<DatePicker label="Schedule" type="date-time" value="2031/05/20 14:30" onChange={() => {}} />);
@@ -80,6 +107,12 @@ describe('DatePicker', () => {
expect(
screen.queryByRole('dialog', { name: 'Date and time picker popup' }),
).not.toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: 'Open date picker' }));
fireEvent.click(screen.getByRole('button', { name: 'Close date picker' }));
expect(
screen.queryByRole('dialog', { name: 'Date and time picker popup' }),
).not.toBeInTheDocument();
});
it('supports segment-by-segment editing with custom format and auto-advance', async () => {
@@ -288,6 +321,25 @@ describe('DatePicker', () => {
expect(screen.queryByRole('dialog', { name: 'Date picker popup' })).not.toBeInTheDocument();
});
it('commits calendar date changes in date-time mode without closing the popup', () => {
const onValueChange = vi.fn();
render(
<ControlledDatePicker
type="date-time"
initialValue="2031/05/20 14:30"
onValueChange={onValueChange}
/>,
);
fireEvent.click(screen.getByRole('button', { name: 'Open date picker' }));
pickCurrentMonthDay('15');
const input = screen.getByLabelText('Schedule') as HTMLInputElement;
expect(input.value).toMatch(/^\d{4}\/\d{2}\/15 14:30$/);
expect(onValueChange).toHaveBeenCalled();
expect(screen.getByRole('dialog', { name: 'Date and time picker popup' })).toBeInTheDocument();
});
it('renders time mode selectors only and keeps popup open after selection', () => {
const onValueChange = vi.fn();
render(<ControlledDatePicker type="time" initialValue="09:00" onValueChange={onValueChange} />);
@@ -344,6 +396,37 @@ describe('DatePicker', () => {
expect(screen.getByText('Invalid date')).toBeInTheDocument();
});
it('forwards inputRef for callback and object refs', () => {
const callbackRef = vi.fn();
const objectRef = createRef<HTMLInputElement>();
const { rerender } = render(
<DatePicker
label="Schedule"
type="date-time"
value="2031/05/20 14:30"
onChange={() => {}}
inputRef={callbackRef}
/>,
);
expect(callbackRef).toHaveBeenCalled();
const callbackNode = callbackRef.mock.calls.find(([node]) => node instanceof HTMLInputElement)?.[0];
expect(callbackNode).toBeInstanceOf(HTMLInputElement);
rerender(
<DatePicker
label="Schedule"
type="date-time"
value="2031/05/20 14:30"
onChange={() => {}}
inputRef={objectRef}
/>,
);
expect(objectRef.current).toBeInstanceOf(HTMLInputElement);
});
it('supports inline layout', () => {
const { container } = render(
<DatePicker label="Start time" type="time" value="09:00" onChange={() => {}} layout="inline" />,
@@ -352,4 +435,306 @@ describe('DatePicker', () => {
expect(container.querySelector('label')).toHaveClass('inline-flex');
expect(container.querySelector('label > div')).not.toHaveClass('mt-1');
});
it('handles outside vs inside pointer interactions for popup close behavior', () => {
render(<DatePicker label="Schedule" type="date-time" value="2031/05/20 14:30" onChange={() => {}} />);
fireEvent.click(screen.getByRole('button', { name: 'Open date picker' }));
const dialog = screen.getByRole('dialog', { name: 'Date and time picker popup' });
fireEvent.mouseDown(dialog);
expect(screen.getByRole('dialog', { name: 'Date and time picker popup' })).toBeInTheDocument();
fireEvent.mouseDown(document.body);
expect(
screen.queryByRole('dialog', { name: 'Date and time picker popup' }),
).not.toBeInTheDocument();
});
it('supports month/year chooser interactions and month navigation buttons', async () => {
render(<DatePicker label="Schedule" type="date" value="2031/05/20" onChange={() => {}} />);
fireEvent.click(screen.getByRole('button', { name: 'Open date picker' }));
fireEvent.click(screen.getByRole('button', { name: 'Previous month' }));
fireEvent.click(screen.getByRole('button', { name: 'Next month' }));
const chooserButtons = document.querySelectorAll('.datepicker-chooser-btn');
const monthChooserButton = chooserButtons[0] as HTMLButtonElement;
const yearChooserButton = chooserButtons[1] as HTMLButtonElement;
const initialMonthText = monthChooserButton.textContent;
fireEvent.click(monthChooserButton);
const monthList = screen.getByRole('listbox', { name: 'Choose month' });
const monthOptions = within(monthList).getAllByRole('button');
const nextMonth = monthOptions.find((option) => option.textContent !== initialMonthText) ?? monthOptions[0];
fireEvent.click(nextMonth);
await waitFor(() => {
expect(screen.queryByRole('listbox', { name: 'Choose month' })).not.toBeInTheDocument();
});
expect((document.querySelectorAll('.datepicker-chooser-btn')[0] as HTMLButtonElement).textContent).toBe(
nextMonth.textContent,
);
const initialYearText = yearChooserButton.textContent;
fireEvent.click(yearChooserButton);
const yearList = screen.getByRole('listbox', { name: 'Choose year' });
const yearOptions = within(yearList).getAllByRole('button');
const nextYear = yearOptions.find((option) => option.textContent !== initialYearText) ?? yearOptions[0];
fireEvent.click(nextYear);
await waitFor(() => {
expect(screen.queryByRole('listbox', { name: 'Choose year' })).not.toBeInTheDocument();
});
expect((document.querySelectorAll('.datepicker-chooser-btn')[1] as HTMLButtonElement).textContent).toBe(
nextYear.textContent,
);
});
it('guards month navigation at absolute calendar boundaries', () => {
const first = render(
<DatePicker label="Schedule" type="date" value="0000/01/15" onChange={() => {}} />,
);
fireEvent.click(screen.getByRole('button', { name: 'Open date picker' }));
fireEvent.click(screen.getByRole('button', { name: 'Previous month' }));
const lowerYearButton = document.querySelectorAll('.datepicker-chooser-btn')[1] as HTMLButtonElement;
expect(lowerYearButton.textContent).toBe('0');
first.unmount();
render(<DatePicker label="Schedule" type="date" value="9999/12/15" onChange={() => {}} />);
fireEvent.click(screen.getByRole('button', { name: 'Open date picker' }));
fireEvent.click(screen.getByRole('button', { name: 'Next month' }));
const upperYearButton = document.querySelectorAll('.datepicker-chooser-btn')[1] as HTMLButtonElement;
expect(upperYearButton.textContent).toBe('9999');
});
it('supports keyboard navigation commands and segment reset shortcuts', async () => {
const onBlur = vi.fn();
render(
<ControlledDatePicker
type="date-time"
format="dd/mm/yyyy HH:mm"
initialValue="22/02/2026 14:30"
onBlur={onBlur}
/>,
);
const input = screen.getByLabelText('Schedule') as HTMLInputElement;
fireEvent.focus(input);
await waitFor(() => {
expect(input.selectionStart).toBe(0);
expect(input.selectionEnd).toBe(2);
});
fireEvent.keyDown(input, { key: '1' });
fireEvent.keyDown(input, { key: 'ArrowRight' });
await waitFor(() => {
expect(input.value.startsWith('01/')).toBe(true);
expect(input.selectionStart).toBe(3);
});
fireEvent.mouseUp(input);
fireEvent.click(input);
fireEvent.keyDown(input, { key: 'ArrowDown' });
expect(screen.getByRole('dialog', { name: 'Date and time picker popup' })).toBeInTheDocument();
fireEvent.keyDown(input, { key: 'ArrowRight' });
await waitFor(() => expect(input.selectionStart).toBe(3));
fireEvent.keyDown(input, { key: 'ArrowLeft' });
await waitFor(() => expect((input.selectionStart ?? 0) <= 3).toBe(true));
fireEvent.keyDown(input, { key: 'Tab' });
await waitFor(() => expect((input.selectionStart ?? 0) >= 0).toBe(true));
fireEvent.keyDown(input, { key: 'Tab', shiftKey: true });
await waitFor(() => expect((input.selectionStart ?? 0) >= 0).toBe(true));
fireEvent.keyDown(input, { key: 'Backspace' });
await waitFor(() => {
expect(input.value.startsWith('01/')).toBe(true);
});
fireEvent.keyDown(input, { key: '/' });
await waitFor(() => expect(input.selectionStart).toBe(3));
fireEvent.keyDown(input, { key: 'Delete' });
await waitFor(() => {
expect(input.value.slice(3, 5)).toBe('01');
});
fireEvent.keyDown(input, { key: '/' });
await waitFor(() => expect(input.selectionStart).toBe(6));
fireEvent.keyDown(input, { key: 'Delete' });
fireEvent.keyDown(input, { key: ' ' });
fireEvent.keyDown(input, { key: 'Delete' });
await waitFor(() => {
expect(/\s00:|:00$/.test(input.value)).toBe(true);
});
fireEvent.keyDown(input, { key: 'Enter' });
fireEvent.keyDown(input, { key: 'x' });
fireEvent.blur(input);
expect(onBlur).toHaveBeenCalledTimes(1);
});
it('handles paste validation and value commits', async () => {
render(
<ControlledDatePicker
type="date-time"
format="dd/mm/yyyy HH:mm"
initialValue="22/02/2026 14:30"
/>,
);
const input = screen.getByLabelText('Schedule') as HTMLInputElement;
await act(async () => {
input.dispatchEvent(createPasteEvent('invalid value'));
});
expect(input.value).toBe('22/02/2026 14:30');
await act(async () => {
input.dispatchEvent(createPasteEvent('11/03/2027 16:45'));
});
expect(input.value).toBe('11/03/2027 16:45');
});
it('returns early from interaction handlers when disabled', () => {
render(
<DatePicker
label="Schedule"
type="date-time"
format="dd/mm/yyyy HH:mm"
value="22/02/2026 14:30"
disabled
onChange={() => {}}
/>,
);
const input = screen.getByLabelText('Schedule') as HTMLInputElement;
fireEvent.focus(input);
fireEvent.mouseUp(input);
fireEvent.click(input);
fireEvent.keyDown(input, { key: 'ArrowDown' });
const disabledPaste = createPasteEvent('11/03/2027 16:45');
input.dispatchEvent(disabledPaste);
expect(disabledPaste.defaultPrevented).toBe(false);
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
});
it('falls back to direct assignment and synthetic onChange when native dispatch is stubbed', async () => {
const onChange = vi.fn();
const originalGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
render(
<DatePicker
label="Schedule"
type="date-time"
format="dd/mm/yyyy HH:mm"
value="22/02/2026 14:30"
onChange={onChange}
/>,
);
const input = screen.getByLabelText('Schedule') as HTMLInputElement;
const nativeDispatchEvent = input.dispatchEvent.bind(input);
vi.spyOn(input, 'dispatchEvent').mockImplementation((event: Event) => {
if (event.type === 'change') {
return true;
}
return nativeDispatchEvent(event);
});
vi.spyOn(Object, 'getOwnPropertyDescriptor').mockImplementation((target, property) => {
if (target === HTMLInputElement.prototype && property === 'value') {
return {
configurable: true,
enumerable: true,
get: originalGetOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.get,
};
}
return originalGetOwnPropertyDescriptor(target, property);
});
fireEvent.focus(input);
input.setSelectionRange(0, 2);
fireEvent.keyDown(input, { key: '1' });
await waitFor(() => {
expect(onChange).toHaveBeenCalled();
});
});
it('safely handles pending segment selection during unmount', () => {
vi.useFakeTimers();
const { unmount } = render(
<DatePicker
label="Schedule"
type="date-time"
format="dd/mm/yyyy HH:mm"
value="22/02/2026 14:30"
onChange={() => {}}
/>,
);
const input = screen.getByLabelText('Schedule') as HTMLInputElement;
fireEvent.focus(input);
unmount();
expect(() => {
vi.runAllTimers();
}).not.toThrow();
});
it('recalculates popup position on window resize and scroll', async () => {
const originalInnerWidth = Object.getOwnPropertyDescriptor(window, 'innerWidth');
const originalInnerHeight = Object.getOwnPropertyDescriptor(window, 'innerHeight');
const rectSpy = vi
.spyOn(HTMLElement.prototype, 'getBoundingClientRect')
.mockImplementation(function mockRect(this: HTMLElement) {
if (this.classList.contains('datepicker-popup')) {
return createRect(0, 0, 300, 200);
}
if (this.classList.contains('relative') && this.querySelector('input')) {
return createRect(500, 80, 120, 40);
}
return createRect(0, 0, 100, 30);
});
Object.defineProperty(window, 'innerWidth', { configurable: true, value: 600 });
Object.defineProperty(window, 'innerHeight', { configurable: true, value: 480 });
render(<DatePicker label="Schedule" type="date-time" value="2031/05/20 14:30" onChange={() => {}} />);
fireEvent.click(screen.getByRole('button', { name: 'Open date picker' }));
const dialog = screen.getByRole('dialog', { name: 'Date and time picker popup' });
expect(dialog).toBeInTheDocument();
await waitFor(() => {
expect(dialog.style.left).toBe('292px');
});
fireEvent(window, new Event('resize'));
fireEvent(window, new Event('scroll'));
expect(screen.getByRole('dialog', { name: 'Date and time picker popup' })).toBeInTheDocument();
expect(dialog.style.left).toBe('292px');
rectSpy.mockRestore();
if (originalInnerWidth) {
Object.defineProperty(window, 'innerWidth', originalInnerWidth);
}
if (originalInnerHeight) {
Object.defineProperty(window, 'innerHeight', originalInnerHeight);
}
});
});

View File

@@ -52,4 +52,9 @@ describe('Dropdown', () => {
expect(select).toHaveClass('custom-select');
expect(screen.getByText('Role').closest('label')).toHaveClass('custom-wrapper');
});
it('supports rendering without a label', () => {
const { container } = render(<Dropdown value="USER" choices={choices} />);
expect(container.querySelector('label > span')).toBeNull();
});
});

View File

@@ -89,4 +89,9 @@ describe('InputField', () => {
expect(container.querySelector('label')).toHaveClass('inline-flex');
expect(container.querySelector('label > div')).not.toHaveClass('mt-1');
});
it('supports rendering without a label', () => {
const { container } = render(<InputField type="text" value="" onChange={() => {}} />);
expect(container.querySelector('label > span')).toBeNull();
});
});

View File

@@ -30,6 +30,7 @@ export default defineConfig({
test: {
environment: 'jsdom',
setupFiles: ['./tests/setup.ts'],
testTimeout: 10000,
coverage: {
provider: 'v8',
include: ['src/**/*.{ts,tsx}'],

579
yarn.lock
View File

@@ -504,9 +504,9 @@
"@codemirror/legacy-modes" "^6.4.0"
"@codemirror/language@^6.0.0", "@codemirror/language@^6.11.3", "@codemirror/language@^6.3.0", "@codemirror/language@^6.3.2", "@codemirror/language@^6.4.0", "@codemirror/language@^6.6.0", "@codemirror/language@^6.8.0":
version "6.12.1"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@codemirror/language/-/language-6.12.1.tgz#d615f7b099a39248312feaaf0bfafce4418aac1b"
integrity sha512-Fa6xkSiuGKc8XC8Cn96T+TQHYj4ZZ7RdFmXA3i9xe/3hLHfwPZdM+dqfX0Cp0zQklBKhVD8Yzc8LS45rkqcwpQ==
version "6.12.2"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@codemirror/language/-/language-6.12.2.tgz#7db5a46757411cf251e8f450474c05710c27d42c"
integrity sha512-jEPmz2nGGDxhRTg3lTpzmIyGKxz3Gp3SJES4b0nAuE5SWQoKdT5GoQ69cwMmFd+wvFUhYirtDTr0/DRHpQAyWg==
dependencies:
"@codemirror/state" "^6.0.0"
"@codemirror/view" "^6.23.0"
@@ -558,7 +558,7 @@
dependencies:
"@marijn/find-cluster-break" "^1.0.0"
"@codemirror/view@^6.0.0", "@codemirror/view@^6.17.0", "@codemirror/view@^6.23.0", "@codemirror/view@^6.27.0", "@codemirror/view@^6.35.0", "@codemirror/view@^6.37.0", "@codemirror/view@^6.7.1":
"@codemirror/view@^6.0.0", "@codemirror/view@^6.17.0", "@codemirror/view@^6.27.0", "@codemirror/view@^6.35.0", "@codemirror/view@^6.37.0", "@codemirror/view@^6.7.1":
version "6.39.15"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@codemirror/view/-/view-6.39.15.tgz#7665f465b7fad1a1cae15b2689ffee2b47b18246"
integrity sha512-aCWjgweIIXLBHh7bY6cACvXuyrZ0xGafjQ2VInjp4RM4gMfscK5uESiNdrH0pE+e1lZr2B4ONGsjchl2KsKZzg==
@@ -568,6 +568,16 @@
style-mod "^4.1.0"
w3c-keyname "^2.2.4"
"@codemirror/view@^6.23.0":
version "6.39.16"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@codemirror/view/-/view-6.39.16.tgz#e9d876aba20b31df7858abd7c2a845319c70b302"
integrity sha512-m6S22fFpKtOWhq8HuhzsI1WzUP/hB9THbDj0Tl5KX4gbO6Y91hwBl7Yky33NdvB6IffuRFiBxf1R8kJMyXmA4Q==
dependencies:
"@codemirror/state" "^6.5.0"
crelt "^1.0.6"
style-mod "^4.1.0"
w3c-keyname "^2.2.4"
"@codesandbox/nodebox@0.1.8":
version "0.1.8"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@codesandbox/nodebox/-/nodebox-0.1.8.tgz#2dc701005cedefac386f17a69a4c9a4f38c2325d"
@@ -788,26 +798,26 @@
resolved "https://nexus.beatrice.wtf/repository/npm-group/@eslint-community/regexpp/-/regexpp-4.12.2.tgz#bccdf615bcf7b6e8db830ec0b8d21c9a25de597b"
integrity sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==
"@eslint/config-array@^0.23.2":
version "0.23.2"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@eslint/config-array/-/config-array-0.23.2.tgz#db85beeff7facc685a5775caacb1c845669b9470"
integrity sha512-YF+fE6LV4v5MGWRGj7G404/OZzGNepVF8fxk7jqmqo3lrza7a0uUcDnROGRBG1WFC1omYUS/Wp1f42i0M+3Q3A==
"@eslint/config-array@^0.23.3":
version "0.23.3"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@eslint/config-array/-/config-array-0.23.3.tgz#3f4a93dd546169c09130cbd10f2415b13a20a219"
integrity sha512-j+eEWmB6YYLwcNOdlwQ6L2OsptI/LO6lNBuLIqe5R7RetD658HLoF+Mn7LzYmAWWNNzdC6cqP+L6r8ujeYXWLw==
dependencies:
"@eslint/object-schema" "^3.0.2"
"@eslint/object-schema" "^3.0.3"
debug "^4.3.1"
minimatch "^10.2.1"
minimatch "^10.2.4"
"@eslint/config-helpers@^0.5.2":
version "0.5.2"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@eslint/config-helpers/-/config-helpers-0.5.2.tgz#314c7b03d02a371ad8c0a7f6821d5a8a8437ba9d"
integrity sha512-a5MxrdDXEvqnIq+LisyCX6tQMPF/dSJpCfBgBauY+pNZ28yCtSsTvyTYrMhaI+LK26bVyCJfJkT0u8KIj2i1dQ==
version "0.5.3"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@eslint/config-helpers/-/config-helpers-0.5.3.tgz#721fe6bbb90d74b0c80d6ff2428e5bbcb002becb"
integrity sha512-lzGN0onllOZCGroKJmRwY6QcEHxbjBw1gwB8SgRSqK8YbbtEXMvKynsXc3553ckIEBxsbMBU7oOZXKIPGZNeZw==
dependencies:
"@eslint/core" "^1.1.0"
"@eslint/core" "^1.1.1"
"@eslint/core@^1.1.0":
version "1.1.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@eslint/core/-/core-1.1.0.tgz#51f5cd970e216fbdae6721ac84491f57f965836d"
integrity sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==
"@eslint/core@^1.1.1":
version "1.1.1"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@eslint/core/-/core-1.1.1.tgz#450f3d2be2d463ccd51119544092256b4e88df32"
integrity sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==
dependencies:
"@types/json-schema" "^7.0.15"
@@ -816,17 +826,17 @@
resolved "https://nexus.beatrice.wtf/repository/npm-group/@eslint/js/-/js-10.0.1.tgz#1e8a876f50117af8ab67e47d5ad94d38d6622583"
integrity sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==
"@eslint/object-schema@^3.0.2":
version "3.0.2"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@eslint/object-schema/-/object-schema-3.0.2.tgz#c59c6a94aa4b428ed7f1615b6a4495c0a21f7a22"
integrity sha512-HOy56KJt48Bx8KmJ+XGQNSUMT/6dZee/M54XyUyuvTvPXJmsERRvBchsUVx1UMe1WwIH49XLAczNC7V2INsuUw==
"@eslint/object-schema@^3.0.3":
version "3.0.3"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@eslint/object-schema/-/object-schema-3.0.3.tgz#5bf671e52e382e4adc47a9906f2699374637db6b"
integrity sha512-iM869Pugn9Nsxbh/YHRqYiqd23AmIbxJOcpUMOuWCVNdoQJ5ZtwL6h3t0bcZzJUlC3Dq9jCFCESBZnX0GTv7iQ==
"@eslint/plugin-kit@^0.6.0":
version "0.6.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@eslint/plugin-kit/-/plugin-kit-0.6.0.tgz#e0cb12ec66719cb2211ad36499fb516f2a63899d"
integrity sha512-bIZEUzOI1jkhviX2cp5vNyXQc6olzb2ohewQubuYlMXZ2Q/XjBO0x0XhGPvc9fjSIiUN0vw+0hq53BJ4eQSJKQ==
"@eslint/plugin-kit@^0.6.1":
version "0.6.1"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@eslint/plugin-kit/-/plugin-kit-0.6.1.tgz#eb9e6689b56ce8bc1855bb33090e63f3fc115e8e"
integrity sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==
dependencies:
"@eslint/core" "^1.1.0"
"@eslint/core" "^1.1.1"
levn "^0.4.1"
"@exodus/bytes@^1.11.0", "@exodus/bytes@^1.6.0":
@@ -1879,7 +1889,7 @@
resolved "https://nexus.beatrice.wtf/repository/npm-group/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz#4584a8a87b29188a4c1fe987a9fcf701e256d86c"
integrity sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==
"@standard-schema/spec@^1.0.0":
"@standard-schema/spec@^1.1.0":
version "1.1.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@standard-schema/spec/-/spec-1.1.0.tgz#a79b55dbaf8604812f52d140b2c9ab41bc150bb8"
integrity sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==
@@ -1890,45 +1900,52 @@
integrity sha512-Gfkvwk9o9kE9r9XNBmJRfV8zONvXThnm1tcuojL04Uy5uRyqg93DC83lDebl0rocZCfKSjUv+fWYtMQmEDJldg==
"@storybook/addon-a11y@^10.2.10":
version "10.2.10"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@storybook/addon-a11y/-/addon-a11y-10.2.10.tgz#8c80cdcce50eecc52aa7b0fec69dd2bcb92eef98"
integrity sha512-1S9pDXgvbHhBStGarCvfJ3/rfcaiAcQHRhuM3Nk4WGSIYtC1LCSRuzYdDYU0aNRpdCbCrUA7kUCbqvIE3tH+3Q==
version "10.2.18"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@storybook/addon-a11y/-/addon-a11y-10.2.18.tgz#cd9abe550be9a08e43ea6a003a7738530ef8ac92"
integrity sha512-ysAPbCNqKEzei+PAUYuloV//STabW/wEkMcpx3VA74iNzw6oHf7nI270m7kCpYMHmu0uDYGvvb9z/0rZyV2ADw==
dependencies:
"@storybook/global" "^5.0.0"
axe-core "^4.2.0"
"@storybook/addon-docs@^10.2.10":
version "10.2.10"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@storybook/addon-docs/-/addon-docs-10.2.10.tgz#22d1a8dae3b04d5e9e1e131ae7f97a8ab722e83d"
integrity sha512-2wIYtdvZIzPbQ5194M5Igpy8faNbQ135nuO5ZaZ2VuttqGr+IJcGnDP42zYwbAsGs28G8ohpkbSgIzVyJWUhPQ==
version "10.2.18"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@storybook/addon-docs/-/addon-docs-10.2.18.tgz#002167625b11e9faecdde433c6f1791e4a19f5e9"
integrity sha512-9nFpeuxYosSOvir3zdcbfyozwQWqqAKrrc0ikqBIZN+mpYdmbPWYdAWCI/YjV06EY5uWEVwGucXUXPCxUvP6NQ==
dependencies:
"@mdx-js/react" "^3.0.0"
"@storybook/csf-plugin" "10.2.10"
"@storybook/csf-plugin" "10.2.18"
"@storybook/icons" "^2.0.1"
"@storybook/react-dom-shim" "10.2.10"
"@storybook/react-dom-shim" "10.2.18"
react "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
react-dom "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
ts-dedent "^2.0.0"
"@storybook/addon-themes@^10.2.10":
version "10.2.10"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@storybook/addon-themes/-/addon-themes-10.2.10.tgz#2daefc26d1c9071ff49948d92805908b7d54caf5"
integrity sha512-j7ixCgzpWeTU7K4BkNHtEg3NdmRg9YW7ynvv0OjD3vaz4+FUVWOq7PPwb3SktLS1tOl4UA13IpApD8nSpBiY6A==
version "10.2.17"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@storybook/addon-themes/-/addon-themes-10.2.17.tgz#33cbb5a443b0b5041cbdb891eebf8aae700ed051"
integrity sha512-5AJ6h/i967CEDG3DNstfgKo9ysDNIOb1pnbn8VbcD/Fw8D2dZm7pLkTAQOnxu6lFQaIU10DIiVp7cviBMasDUg==
dependencies:
ts-dedent "^2.0.0"
"@storybook/builder-vite@10.2.10":
version "10.2.10"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@storybook/builder-vite/-/builder-vite-10.2.10.tgz#0f9889873291a7b88857c45224d4063e204d3a62"
integrity sha512-Wd6CYL7LvRRNiXMz977x9u/qMm7nmMw/7Dow2BybQo+Xbfy1KhVjIoZ/gOiG515zpojSozctNrJUbM0+jH1jwg==
"@storybook/builder-vite@10.2.17":
version "10.2.17"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@storybook/builder-vite/-/builder-vite-10.2.17.tgz#87823a5289c3b2d6cc82f07676b52cfc41372599"
integrity sha512-m/OBveTLm5ds/tUgHmmbKzgSi/oeCpQwm5rZa49vP2BpAd41Q7ER6TzkOoISzPoNNMAcbVmVc5vn7k6hdbPSHw==
dependencies:
"@storybook/csf-plugin" "10.2.10"
"@storybook/csf-plugin" "10.2.17"
ts-dedent "^2.0.0"
"@storybook/csf-plugin@10.2.10":
version "10.2.10"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@storybook/csf-plugin/-/csf-plugin-10.2.10.tgz#038cd8e41884f2f437502504d02b8c0a24ed0b39"
integrity sha512-aFvgaNDAnKMjuyhPK5ialT22pPqMN0XfPBNPeeNVPYztngkdKBa8WFqF/umDd47HxAjebq+vn6uId1xHyOHH3g==
"@storybook/csf-plugin@10.2.17":
version "10.2.17"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@storybook/csf-plugin/-/csf-plugin-10.2.17.tgz#a3d1da13e67f7d6ce3cb0a4cfee9badc4411b37e"
integrity sha512-crHH8i/4mwzeXpWRPgwvwX2vjytW42zyzTRySUax5dTU8o9sjk4y+Z9hkGx3Nmu1TvqseS8v1Z20saZr/tQcWw==
dependencies:
unplugin "^2.3.5"
"@storybook/csf-plugin@10.2.18":
version "10.2.18"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@storybook/csf-plugin/-/csf-plugin-10.2.18.tgz#99d84e6a38677233565b3d86b23dc12a83be5c8a"
integrity sha512-JWJ39Dh3WVTt74fb+GNFnEY+4G394UQ6pAidc7FWeE7OfMPDWFZnMgLxE6oR2GMHm7Gc74yvD3g/EbWaJrOHsw==
dependencies:
unplugin "^2.3.5"
@@ -1942,33 +1959,38 @@
resolved "https://nexus.beatrice.wtf/repository/npm-group/@storybook/icons/-/icons-2.0.1.tgz#1bd351db1d33bfccbbafa7b64fb413168f1a6616"
integrity sha512-/smVjw88yK3CKsiuR71vNgWQ9+NuY2L+e8X7IMrFjexjm6ZR8ULrV2DRkTA61aV6ryefslzHEGDInGpnNeIocg==
"@storybook/react-dom-shim@10.2.10":
version "10.2.10"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@storybook/react-dom-shim/-/react-dom-shim-10.2.10.tgz#ce1b439573fa01fc4fd461cff22bda23abf39a4a"
integrity sha512-TmBrhyLHn8B8rvDHKk5uW5BqzO1M1T+fqFNWg88NIAJOoyX4Uc90FIJjDuN1OJmWKGwB5vLmPwaKBYsTe1yS+w==
"@storybook/react-dom-shim@10.2.17":
version "10.2.17"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@storybook/react-dom-shim/-/react-dom-shim-10.2.17.tgz#9d7b3e600c190fa643b8d0ad92422df6bd26fc2c"
integrity sha512-x9Kb7eUSZ1zGsEw/TtWrvs1LwWIdNp8qoOQCgPEjdB07reSJcE8R3+ASWHJThmd4eZf66ZALPJyerejake4Osw==
"@storybook/react-dom-shim@10.2.18":
version "10.2.18"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@storybook/react-dom-shim/-/react-dom-shim-10.2.18.tgz#c37b57cf6ddd6794de0e45f4a39373fab4d6efb9"
integrity sha512-LhVH5oTknCEF4cG5LDM81O1G/bzD15/lbsS6iqtJDqWsncrukwiUweA0uoRp2Uoc3E3/wW2qHs81sdLBi3qsMQ==
"@storybook/react-vite@^10.2.10":
version "10.2.10"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@storybook/react-vite/-/react-vite-10.2.10.tgz#cf1e970189167786fe1e314eeef025b50a49e4f1"
integrity sha512-C652GhZHXURi+gFqqLKmZPskEq1FQto4VCf/eQea2exmdVS0nOB+FFWQZNCivX6mpkDHza8UxRZNFpDB0mWcJQ==
version "10.2.17"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@storybook/react-vite/-/react-vite-10.2.17.tgz#54aa766c4254f8b1c7958ccc343033db08b88867"
integrity sha512-E/1hNmxVsjy9l3TuaNufSqkdz8saTJUGEs8GRCjKlF7be2wljIwewUxjAT3efk+bxOCw76ZmqGHk6MnRa3y7Gw==
dependencies:
"@joshwooding/vite-plugin-react-docgen-typescript" "^0.6.4"
"@rollup/pluginutils" "^5.0.2"
"@storybook/builder-vite" "10.2.10"
"@storybook/react" "10.2.10"
"@storybook/builder-vite" "10.2.17"
"@storybook/react" "10.2.17"
empathic "^2.0.0"
magic-string "^0.30.0"
react-docgen "^8.0.0"
resolve "^1.22.8"
tsconfig-paths "^4.2.0"
"@storybook/react@10.2.10", "@storybook/react@^10.2.10":
version "10.2.10"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@storybook/react/-/react-10.2.10.tgz#38116ead3e1bbb96acfa043db3545e36146cd32f"
integrity sha512-PcsChzPI8lhllB9exV7nFb96093i6sTwIl0jpPjaTFPQCRoueR9E/YeP3qSKQL9xt4cmii0cW7F0RUx25rW93Q==
"@storybook/react@10.2.17", "@storybook/react@^10.2.10":
version "10.2.17"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@storybook/react/-/react-10.2.17.tgz#ec2788a4d163732dfb7a86f9dc878f448d5e3fd9"
integrity sha512-875AVMYil2X9Civil6GFZ8koIzlKxcXbl2eJ7+/GPbhIonTNmwx0qbWPHttjZXUvFuQ4RRtb9KkBwy4TCb/LeA==
dependencies:
"@storybook/global" "^5.0.0"
"@storybook/react-dom-shim" "10.2.10"
"@storybook/react-dom-shim" "10.2.17"
react-docgen "^8.0.2"
"@testing-library/dom@^10.4.1":
@@ -2119,9 +2141,9 @@
integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==
"@types/node@^25.3.0":
version "25.3.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@types/node/-/node-25.3.0.tgz#749b1bd4058e51b72e22bd41e9eab6ebd0180470"
integrity sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==
version "25.4.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@types/node/-/node-25.4.0.tgz#f25d8467984d6667cc4c1be1e2f79593834aaedb"
integrity sha512-9wLpoeWuBlcbBpOY3XmzSTG3oscB6xjBEEtn+pYXTfhyXhIxC5FsBer2KTopBlvKEiW9l13po9fq+SJY/5lkhw==
dependencies:
undici-types "~7.18.0"
@@ -2152,106 +2174,106 @@
resolved "https://nexus.beatrice.wtf/repository/npm-group/@types/unist/-/unist-2.0.11.tgz#11af57b127e32487774841f7a4e54eab166d03c4"
integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==
"@typescript-eslint/eslint-plugin@8.56.0":
version "8.56.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.0.tgz#5aec3db807a6b8437ea5d5ebf7bd16b4119aba8d"
integrity sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==
"@typescript-eslint/eslint-plugin@8.57.0":
version "8.57.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.0.tgz#6e4085604ab63f55b3dcc61ce2c16965b2c36374"
integrity sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ==
dependencies:
"@eslint-community/regexpp" "^4.12.2"
"@typescript-eslint/scope-manager" "8.56.0"
"@typescript-eslint/type-utils" "8.56.0"
"@typescript-eslint/utils" "8.56.0"
"@typescript-eslint/visitor-keys" "8.56.0"
"@typescript-eslint/scope-manager" "8.57.0"
"@typescript-eslint/type-utils" "8.57.0"
"@typescript-eslint/utils" "8.57.0"
"@typescript-eslint/visitor-keys" "8.57.0"
ignore "^7.0.5"
natural-compare "^1.4.0"
ts-api-utils "^2.4.0"
"@typescript-eslint/parser@8.56.0":
version "8.56.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/parser/-/parser-8.56.0.tgz#8ecff1678b8b1a742d29c446ccf5eeea7f971d72"
integrity sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==
"@typescript-eslint/parser@8.57.0":
version "8.57.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/parser/-/parser-8.57.0.tgz#444c57a943e8b04f255cda18a94c8e023b46b08c"
integrity sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g==
dependencies:
"@typescript-eslint/scope-manager" "8.56.0"
"@typescript-eslint/types" "8.56.0"
"@typescript-eslint/typescript-estree" "8.56.0"
"@typescript-eslint/visitor-keys" "8.56.0"
"@typescript-eslint/scope-manager" "8.57.0"
"@typescript-eslint/types" "8.57.0"
"@typescript-eslint/typescript-estree" "8.57.0"
"@typescript-eslint/visitor-keys" "8.57.0"
debug "^4.4.3"
"@typescript-eslint/project-service@8.56.0":
version "8.56.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/project-service/-/project-service-8.56.0.tgz#bb8562fecd8f7922e676fc6a1189c20dd7991d73"
integrity sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==
"@typescript-eslint/project-service@8.57.0":
version "8.57.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/project-service/-/project-service-8.57.0.tgz#2014ed527bcd0eff8aecb7e44879ae3150604ab3"
integrity sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w==
dependencies:
"@typescript-eslint/tsconfig-utils" "^8.56.0"
"@typescript-eslint/types" "^8.56.0"
"@typescript-eslint/tsconfig-utils" "^8.57.0"
"@typescript-eslint/types" "^8.57.0"
debug "^4.4.3"
"@typescript-eslint/scope-manager@8.56.0":
version "8.56.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/scope-manager/-/scope-manager-8.56.0.tgz#604030a4c6433df3728effdd441d47f45a86edb4"
integrity sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==
"@typescript-eslint/scope-manager@8.57.0":
version "8.57.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/scope-manager/-/scope-manager-8.57.0.tgz#7d2a2aeaaef2ae70891b21939fadb4cb0b19f840"
integrity sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw==
dependencies:
"@typescript-eslint/types" "8.56.0"
"@typescript-eslint/visitor-keys" "8.56.0"
"@typescript-eslint/types" "8.57.0"
"@typescript-eslint/visitor-keys" "8.57.0"
"@typescript-eslint/tsconfig-utils@8.56.0", "@typescript-eslint/tsconfig-utils@^8.56.0":
version "8.56.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.0.tgz#2538ce83cbc376e685487960cbb24b65fe2abc4e"
integrity sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==
"@typescript-eslint/tsconfig-utils@8.57.0", "@typescript-eslint/tsconfig-utils@^8.57.0":
version "8.57.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.0.tgz#cf2f2822af3887d25dd325b6bea6c3f60a83a0b4"
integrity sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA==
"@typescript-eslint/type-utils@8.56.0":
version "8.56.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/type-utils/-/type-utils-8.56.0.tgz#72b4edc1fc73988998f1632b3ec99c2a66eaac6e"
integrity sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==
"@typescript-eslint/type-utils@8.57.0":
version "8.57.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/type-utils/-/type-utils-8.57.0.tgz#2877af4c2e8f0998b93a07dad1c34ce1bb669448"
integrity sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ==
dependencies:
"@typescript-eslint/types" "8.56.0"
"@typescript-eslint/typescript-estree" "8.56.0"
"@typescript-eslint/utils" "8.56.0"
"@typescript-eslint/types" "8.57.0"
"@typescript-eslint/typescript-estree" "8.57.0"
"@typescript-eslint/utils" "8.57.0"
debug "^4.4.3"
ts-api-utils "^2.4.0"
"@typescript-eslint/types@8.56.0", "@typescript-eslint/types@^8.56.0":
version "8.56.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/types/-/types-8.56.0.tgz#a2444011b9a98ca13d70411d2cbfed5443b3526a"
integrity sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==
"@typescript-eslint/types@8.57.0", "@typescript-eslint/types@^8.57.0":
version "8.57.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/types/-/types-8.57.0.tgz#4fa5385ffd1cd161fa5b9dce93e0493d491b8dc6"
integrity sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg==
"@typescript-eslint/typescript-estree@8.56.0":
version "8.56.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.0.tgz#fadbc74c14c5bac947db04980ff58bb178701c2e"
integrity sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==
"@typescript-eslint/typescript-estree@8.57.0":
version "8.57.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.0.tgz#e0e4a89bfebb207de314826df876e2dabc7dea04"
integrity sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q==
dependencies:
"@typescript-eslint/project-service" "8.56.0"
"@typescript-eslint/tsconfig-utils" "8.56.0"
"@typescript-eslint/types" "8.56.0"
"@typescript-eslint/visitor-keys" "8.56.0"
"@typescript-eslint/project-service" "8.57.0"
"@typescript-eslint/tsconfig-utils" "8.57.0"
"@typescript-eslint/types" "8.57.0"
"@typescript-eslint/visitor-keys" "8.57.0"
debug "^4.4.3"
minimatch "^9.0.5"
minimatch "^10.2.2"
semver "^7.7.3"
tinyglobby "^0.2.15"
ts-api-utils "^2.4.0"
"@typescript-eslint/utils@8.56.0":
version "8.56.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/utils/-/utils-8.56.0.tgz#063ce6f702ec603de1b83ee795ed5e877d6f7841"
integrity sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==
"@typescript-eslint/utils@8.57.0":
version "8.57.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/utils/-/utils-8.57.0.tgz#c7193385b44529b788210d20c94c11de79ad3498"
integrity sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ==
dependencies:
"@eslint-community/eslint-utils" "^4.9.1"
"@typescript-eslint/scope-manager" "8.56.0"
"@typescript-eslint/types" "8.56.0"
"@typescript-eslint/typescript-estree" "8.56.0"
"@typescript-eslint/scope-manager" "8.57.0"
"@typescript-eslint/types" "8.57.0"
"@typescript-eslint/typescript-estree" "8.57.0"
"@typescript-eslint/visitor-keys@8.56.0":
version "8.56.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.0.tgz#7d6592ab001827d3ce052155edf7ecad19688d7d"
integrity sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==
"@typescript-eslint/visitor-keys@8.57.0":
version "8.57.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.0.tgz#23aea662279bb66209700854453807a119350f85"
integrity sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg==
dependencies:
"@typescript-eslint/types" "8.56.0"
"@typescript-eslint/types" "8.57.0"
eslint-visitor-keys "^5.0.0"
"@vitejs/plugin-react@^5.0.0":
version "5.1.4"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@vitejs/plugin-react/-/plugin-react-5.1.4.tgz#5b477e060bf612a7394c4febacc5de33a219b0e4"
integrity sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA==
version "5.2.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz#108bd0f566f288ce3566982df4eff137ded7b15f"
integrity sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==
dependencies:
"@babel/core" "^7.29.0"
"@babel/plugin-transform-react-jsx-self" "^7.27.1"
@@ -2261,19 +2283,19 @@
react-refresh "^0.18.0"
"@vitest/coverage-v8@^4.0.18":
version "4.0.18"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@vitest/coverage-v8/-/coverage-v8-4.0.18.tgz#b9c4db7479acd51d5f0ced91b2853c29c3d0cda7"
integrity sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==
version "4.1.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@vitest/coverage-v8/-/coverage-v8-4.1.0.tgz#7ef70bc23e588564fd0ff7e755cbdcd627de8e6c"
integrity sha512-nDWulKeik2bL2Va/Wl4x7DLuTKAXa906iRFooIRPR+huHkcvp9QDkPQ2RJdmjOFrqOqvNfoSQLF68deE3xC3CQ==
dependencies:
"@bcoe/v8-coverage" "^1.0.2"
"@vitest/utils" "4.0.18"
ast-v8-to-istanbul "^0.3.10"
"@vitest/utils" "4.1.0"
ast-v8-to-istanbul "^1.0.0"
istanbul-lib-coverage "^3.2.2"
istanbul-lib-report "^3.0.1"
istanbul-reports "^3.2.0"
magicast "^0.5.1"
magicast "^0.5.2"
obug "^2.1.1"
std-env "^3.10.0"
std-env "^4.0.0-rc.1"
tinyrainbow "^3.0.3"
"@vitest/expect@3.2.4":
@@ -2287,24 +2309,24 @@
chai "^5.2.0"
tinyrainbow "^2.0.0"
"@vitest/expect@4.0.18":
version "4.0.18"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@vitest/expect/-/expect-4.0.18.tgz#361510d99fbf20eb814222e4afcb8539d79dc94d"
integrity sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==
"@vitest/expect@4.1.0":
version "4.1.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@vitest/expect/-/expect-4.1.0.tgz#2f6c7d19cfbe778bfb42d73f77663ec22163fcbb"
integrity sha512-EIxG7k4wlWweuCLG9Y5InKFwpMEOyrMb6ZJ1ihYu02LVj/bzUwn2VMU+13PinsjRW75XnITeFrQBMH5+dLvCDA==
dependencies:
"@standard-schema/spec" "^1.0.0"
"@standard-schema/spec" "^1.1.0"
"@types/chai" "^5.2.2"
"@vitest/spy" "4.0.18"
"@vitest/utils" "4.0.18"
chai "^6.2.1"
"@vitest/spy" "4.1.0"
"@vitest/utils" "4.1.0"
chai "^6.2.2"
tinyrainbow "^3.0.3"
"@vitest/mocker@4.0.18":
version "4.0.18"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@vitest/mocker/-/mocker-4.0.18.tgz#b9735da114ef65ea95652c5bdf13159c6fab4865"
integrity sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==
"@vitest/mocker@4.1.0":
version "4.1.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@vitest/mocker/-/mocker-4.1.0.tgz#2aabf6079ad472f89a212d322f7d5da7ad628a0e"
integrity sha512-evxREh+Hork43+Y4IOhTo+h5lGmVRyjqI739Rz4RlUPqwrkFFDF6EMvOOYjTx4E8Tl6gyCLRL8Mu7Ry12a13Tw==
dependencies:
"@vitest/spy" "4.0.18"
"@vitest/spy" "4.1.0"
estree-walker "^3.0.3"
magic-string "^0.30.21"
@@ -2315,27 +2337,28 @@
dependencies:
tinyrainbow "^2.0.0"
"@vitest/pretty-format@4.0.18":
version "4.0.18"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@vitest/pretty-format/-/pretty-format-4.0.18.tgz#fbccd4d910774072ec15463553edb8ca5ce53218"
integrity sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==
"@vitest/pretty-format@4.1.0":
version "4.1.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@vitest/pretty-format/-/pretty-format-4.1.0.tgz#b6ccf2868130a647d24af3696d58c09a95eb83c1"
integrity sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A==
dependencies:
tinyrainbow "^3.0.3"
"@vitest/runner@4.0.18":
version "4.0.18"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@vitest/runner/-/runner-4.0.18.tgz#c2c0a3ed226ec85e9312f9cc8c43c5b3a893a8b1"
integrity sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==
"@vitest/runner@4.1.0":
version "4.1.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@vitest/runner/-/runner-4.1.0.tgz#4e12c0f086eb3a4ae3fae84d9d68b22d02942cbf"
integrity sha512-Duvx2OzQ7d6OjchL+trw+aSrb9idh7pnNfxrklo14p3zmNL4qPCDeIJAK+eBKYjkIwG96Bc6vYuxhqDXQOWpoQ==
dependencies:
"@vitest/utils" "4.0.18"
"@vitest/utils" "4.1.0"
pathe "^2.0.3"
"@vitest/snapshot@4.0.18":
version "4.0.18"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@vitest/snapshot/-/snapshot-4.0.18.tgz#bcb40fd6d742679c2ac927ba295b66af1c6c34c5"
integrity sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==
"@vitest/snapshot@4.1.0":
version "4.1.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@vitest/snapshot/-/snapshot-4.1.0.tgz#67372979da692ccf5dfa4a3bb603f683c0640202"
integrity sha512-0Vy9euT1kgsnj1CHttwi9i9o+4rRLEaPRSOJ5gyv579GJkNpgJK+B4HSv/rAWixx2wdAFci1X4CEPjiu2bXIMg==
dependencies:
"@vitest/pretty-format" "4.0.18"
"@vitest/pretty-format" "4.1.0"
"@vitest/utils" "4.1.0"
magic-string "^0.30.21"
pathe "^2.0.3"
@@ -2346,10 +2369,10 @@
dependencies:
tinyspy "^4.0.3"
"@vitest/spy@4.0.18":
version "4.0.18"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@vitest/spy/-/spy-4.0.18.tgz#ba0f20503fb6d08baf3309d690b3efabdfa88762"
integrity sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==
"@vitest/spy@4.1.0":
version "4.1.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@vitest/spy/-/spy-4.1.0.tgz#b9143a63cca83de34ac1777c733f8561b73fa9ba"
integrity sha512-pz77k+PgNpyMDv2FV6qmk5ZVau6c3R8HC8v342T2xlFxQKTrSeYw9waIJG8KgV9fFwAtTu4ceRzMivPTH6wSxw==
"@vitest/utils@3.2.4":
version "3.2.4"
@@ -2360,12 +2383,13 @@
loupe "^3.1.4"
tinyrainbow "^2.0.0"
"@vitest/utils@4.0.18":
version "4.0.18"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@vitest/utils/-/utils-4.0.18.tgz#9636b16d86a4152ec68a8d6859cff702896433d4"
integrity sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==
"@vitest/utils@4.1.0":
version "4.1.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/@vitest/utils/-/utils-4.1.0.tgz#2baf26a2a28c4aabe336315dc59722df2372c38d"
integrity sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw==
dependencies:
"@vitest/pretty-format" "4.0.18"
"@vitest/pretty-format" "4.1.0"
convert-source-map "^2.0.0"
tinyrainbow "^3.0.3"
acorn-jsx@^5.0.0, acorn-jsx@^5.3.2:
@@ -2383,7 +2407,7 @@ agent-base@^7.1.0, agent-base@^7.1.2:
resolved "https://nexus.beatrice.wtf/repository/npm-group/agent-base/-/agent-base-7.1.4.tgz#e3cd76d4c548ee895d3c3fd8dc1f6c5b9032e7a8"
integrity sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==
ajv@^6.12.4:
ajv@^6.14.0:
version "6.14.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/ajv/-/ajv-6.14.0.tgz#fd067713e228210636ebb08c60bd3765d6dbe73a"
integrity sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==
@@ -2462,10 +2486,10 @@ ast-types@^0.16.1:
dependencies:
tslib "^2.0.1"
ast-v8-to-istanbul@^0.3.10:
version "0.3.11"
resolved "https://nexus.beatrice.wtf/repository/npm-group/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.11.tgz#725b1f5e2ffdc8d71620cb5e78d6dc976d65e97a"
integrity sha512-Qya9fkoofMjCBNVdWINMjB5KZvkYfaO9/anwkWnjxibpWUxo5iHl2sOdP7/uAqaRuUYuoo8rDwnbaaKVFxoUvw==
ast-v8-to-istanbul@^1.0.0:
version "1.0.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz#d1e8bfc79fa9c452972ff91897633bda4e5e7577"
integrity sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==
dependencies:
"@jridgewell/trace-mapping" "^0.3.31"
estree-walker "^3.0.3"
@@ -2487,9 +2511,9 @@ base64-js@^1.3.1:
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
baseline-browser-mapping@^2.9.0:
version "2.10.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz#5b09935025bf8a80e29130251e337c6a7fc8cbb9"
integrity sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==
version "2.10.8"
resolved "https://nexus.beatrice.wtf/repository/npm-group/baseline-browser-mapping/-/baseline-browser-mapping-2.10.8.tgz#23d1cea1a85b181c2b8660b6cfe626dc2fb15630"
integrity sha512-PCLz/LXGBsNTErbtB6i5u4eLpHeMfi93aUv5duMmj6caNu6IphS4q6UevDnL36sZQv9lrP11dbPKGMaXPwMKfQ==
bidi-js@^1.0.3:
version "1.0.3"
@@ -2504,9 +2528,9 @@ binary-extensions@^2.0.0:
integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
brace-expansion@^5.0.2:
version "5.0.3"
resolved "https://nexus.beatrice.wtf/repository/npm-group/brace-expansion/-/brace-expansion-5.0.3.tgz#6a9c6c268f85b53959ec527aeafe0f7300258eef"
integrity sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==
version "5.0.4"
resolved "https://nexus.beatrice.wtf/repository/npm-group/brace-expansion/-/brace-expansion-5.0.4.tgz#614daaecd0a688f660bbbc909a8748c3d80d4336"
integrity sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==
dependencies:
balanced-match "^4.0.2"
@@ -2549,9 +2573,9 @@ camelcase-css@^2.0.1:
integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
caniuse-lite@^1.0.30001759:
version "1.0.30001774"
resolved "https://nexus.beatrice.wtf/repository/npm-group/caniuse-lite/-/caniuse-lite-1.0.30001774.tgz#0e576b6f374063abcd499d202b9ba1301be29b70"
integrity sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==
version "1.0.30001778"
resolved "https://nexus.beatrice.wtf/repository/npm-group/caniuse-lite/-/caniuse-lite-1.0.30001778.tgz#79a8a124e3473a20b70616497b987c30d06570a0"
integrity sha512-PN7uxFL+ExFJO61aVmP1aIEG4i9whQd4eoSCebav62UwDyp5OHh06zN4jqKSMePVgxHifCw1QJxdRkA1Pisekg==
ccount@^2.0.0:
version "2.0.1"
@@ -2569,7 +2593,7 @@ chai@^5.2.0:
loupe "^3.1.0"
pathval "^2.0.0"
chai@^6.2.1:
chai@^6.2.2:
version "6.2.2"
resolved "https://nexus.beatrice.wtf/repository/npm-group/chai/-/chai-6.2.2.tgz#ae41b52c9aca87734505362717f3255facda360e"
integrity sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==
@@ -2838,9 +2862,9 @@ downshift@^7.6.0:
tslib "^2.3.0"
electron-to-chromium@^1.5.263:
version "1.5.302"
resolved "https://nexus.beatrice.wtf/repository/npm-group/electron-to-chromium/-/electron-to-chromium-1.5.302.tgz#032a5802b31f7119269959c69fe2015d8dad5edb"
integrity sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==
version "1.5.313"
resolved "https://nexus.beatrice.wtf/repository/npm-group/electron-to-chromium/-/electron-to-chromium-1.5.313.tgz#193e9ae2c2ab6915acb41e833068381e4ef0b3e4"
integrity sha512-QBMrTWEf00GXZmJyx2lbYD45jpI3TUFnNIzJ5BBc8piGUDwMPa1GV6HJWTZVvY/eiN3fSopl7NRbgGp9sZ9LTA==
empathic@^2.0.0:
version "2.0.0"
@@ -2852,10 +2876,10 @@ entities@^6.0.0:
resolved "https://nexus.beatrice.wtf/repository/npm-group/entities/-/entities-6.0.1.tgz#c28c34a43379ca7f61d074130b2f5f7020a30694"
integrity sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==
es-module-lexer@^1.7.0:
version "1.7.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/es-module-lexer/-/es-module-lexer-1.7.0.tgz#9159601561880a85f2734560a9099b2c31e5372a"
integrity sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==
es-module-lexer@^2.0.0:
version "2.0.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/es-module-lexer/-/es-module-lexer-2.0.0.tgz#f657cd7a9448dcdda9c070a3cb75e5dc1e85f5b1"
integrity sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==
es5-ext@^0.10.35, es5-ext@^0.10.62, es5-ext@^0.10.64, es5-ext@~0.10.14:
version "0.10.64"
@@ -2948,14 +2972,14 @@ eslint-plugin-react-hooks@^7.1.0-canary-ab18f33d-20260220:
zod-validation-error "^3.5.0 || ^4.0.0"
eslint-plugin-react-refresh@^0.5.1:
version "0.5.1"
resolved "https://nexus.beatrice.wtf/repository/npm-group/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.1.tgz#d13f1cfea4718a108060a41219d1849287278adc"
integrity sha512-Y5sJsreCUdGcF4mLD70iJNa47Z6CX4MsqJoJBARDC/fBhmacSby7k73UuValr0F9M7GfWKpEqS4NMsniWkVxQw==
version "0.5.2"
resolved "https://nexus.beatrice.wtf/repository/npm-group/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.2.tgz#39e11021be10e1cd9adab2bdeabc65b17222409f"
integrity sha512-hmgTH57GfzoTFjVN0yBwTggnsVUF2tcqi7RJZHqi9lIezSs4eFyAMktA68YD4r5kNw1mxyY4dmkyoFDb3FIqrA==
eslint-scope@^9.1.1:
version "9.1.1"
resolved "https://nexus.beatrice.wtf/repository/npm-group/eslint-scope/-/eslint-scope-9.1.1.tgz#f6a209486e38bd28356b5feb07d445cc99c89967"
integrity sha512-GaUN0sWim5qc8KVErfPBWmc31LEsOkrUJbvJZV+xuL3u2phMUK4HIvXlWAakfC8W4nzlK+chPEAkYOYb5ZScIw==
eslint-scope@^9.1.2:
version "9.1.2"
resolved "https://nexus.beatrice.wtf/repository/npm-group/eslint-scope/-/eslint-scope-9.1.2.tgz#b9de6ace2fab1cff24d2e58d85b74c8fcea39802"
integrity sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==
dependencies:
"@types/esrecurse" "^4.3.1"
"@types/estree" "^1.0.8"
@@ -2973,25 +2997,25 @@ eslint-visitor-keys@^5.0.0, eslint-visitor-keys@^5.0.1:
integrity sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==
eslint@^10:
version "10.0.1"
resolved "https://nexus.beatrice.wtf/repository/npm-group/eslint/-/eslint-10.0.1.tgz#b5c5f7706782a21590ba6451e7a30d2947273c2d"
integrity sha512-20MV9SUdeN6Jd84xESsKhRly+/vxI+hwvpBMA93s+9dAcjdCuCojn4IqUGS3lvVaqjVYGYHSRMCpeFtF2rQYxQ==
version "10.0.3"
resolved "https://nexus.beatrice.wtf/repository/npm-group/eslint/-/eslint-10.0.3.tgz#360a7de7f2706eb8a32caa17ca983f0089efe694"
integrity sha512-COV33RzXZkqhG9P2rZCFl9ZmJ7WL+gQSCRzE7RhkbclbQPtLAWReL7ysA0Sh4c8Im2U9ynybdR56PV0XcKvqaQ==
dependencies:
"@eslint-community/eslint-utils" "^4.8.0"
"@eslint-community/regexpp" "^4.12.2"
"@eslint/config-array" "^0.23.2"
"@eslint/config-array" "^0.23.3"
"@eslint/config-helpers" "^0.5.2"
"@eslint/core" "^1.1.0"
"@eslint/plugin-kit" "^0.6.0"
"@eslint/core" "^1.1.1"
"@eslint/plugin-kit" "^0.6.1"
"@humanfs/node" "^0.16.6"
"@humanwhocodes/module-importer" "^1.0.1"
"@humanwhocodes/retry" "^0.4.2"
"@types/estree" "^1.0.6"
ajv "^6.12.4"
ajv "^6.14.0"
cross-spawn "^7.0.6"
debug "^4.3.2"
escape-string-regexp "^4.0.0"
eslint-scope "^9.1.1"
eslint-scope "^9.1.2"
eslint-visitor-keys "^5.0.1"
espree "^11.1.1"
esquery "^1.7.0"
@@ -3004,7 +3028,7 @@ eslint@^10:
imurmurhash "^0.1.4"
is-glob "^4.0.0"
json-stable-stringify-without-jsonify "^1.0.1"
minimatch "^10.2.1"
minimatch "^10.2.4"
natural-compare "^1.4.0"
optionator "^0.9.3"
@@ -3019,9 +3043,9 @@ esniff@^2.0.1:
type "^2.7.2"
espree@^11.1.1:
version "11.1.1"
resolved "https://nexus.beatrice.wtf/repository/npm-group/espree/-/espree-11.1.1.tgz#866f6bc9ccccd6f28876b7a6463abb281b9cb847"
integrity sha512-AVHPqQoZYc+RUM4/3Ly5udlZY/U4LS8pIG05jEjWM2lQMU/oaZ7qshzAl2YP1tfNmXfftH3ohurfwNAug+MnsQ==
version "11.2.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/espree/-/espree-11.2.0.tgz#01d5e47dc332aaba3059008362454a8cc34ccaa5"
integrity sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==
dependencies:
acorn "^8.16.0"
acorn-jsx "^5.3.2"
@@ -3089,7 +3113,7 @@ event-emitter@^0.3.5:
d "1"
es5-ext "~0.10.14"
expect-type@^1.2.2:
expect-type@^1.3.0:
version "1.3.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/expect-type/-/expect-type-1.3.0.tgz#0d58ed361877a31bbc4dd6cf71bbfef7faf6bd68"
integrity sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==
@@ -3177,9 +3201,9 @@ flat-cache@^4.0.0:
keyv "^4.5.4"
flatted@^3.2.9:
version "3.3.3"
resolved "https://nexus.beatrice.wtf/repository/npm-group/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358"
integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==
version "3.4.1"
resolved "https://nexus.beatrice.wtf/repository/npm-group/flatted/-/flatted-3.4.1.tgz#84ccd9579e76e9cc0d246c11d8be0beb019143e6"
integrity sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==
format@^0.2.0:
version "0.2.2"
@@ -3230,9 +3254,9 @@ glob@^13.0.1:
path-scurry "^2.0.2"
globals@^17.3.0:
version "17.3.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/globals/-/globals-17.3.0.tgz#8b96544c2fa91afada02747cc9731c002a96f3b9"
integrity sha512-yMqGUQVVCkD4tqjOJf3TnrvaaHDMYp4VlUSObbkIiuCPe/ofdMBFIAcBbCSRFWOnos6qRiTVStDwqPLUclaxIw==
version "17.4.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/globals/-/globals-17.4.0.tgz#33d7d297ed1536b388a0e2f4bcd0ff19c8ff91b5"
integrity sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==
has-flag@^4.0.0:
version "4.0.0"
@@ -3590,7 +3614,7 @@ magic-string@^0.30.0, magic-string@^0.30.21:
dependencies:
"@jridgewell/sourcemap-codec" "^1.5.5"
magicast@^0.5.1:
magicast@^0.5.2:
version "0.5.2"
resolved "https://nexus.beatrice.wtf/repository/npm-group/magicast/-/magicast-0.5.2.tgz#70cea9df729c164485049ea5df85a390281dfb9d"
integrity sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==
@@ -4161,17 +4185,10 @@ min-indent@^1.0.0:
resolved "https://nexus.beatrice.wtf/repository/npm-group/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
minimatch@^10.2.1, minimatch@^10.2.2:
version "10.2.2"
resolved "https://nexus.beatrice.wtf/repository/npm-group/minimatch/-/minimatch-10.2.2.tgz#361603ee323cfb83496fea2ae17cc44ea4e1f99f"
integrity sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==
dependencies:
brace-expansion "^5.0.2"
minimatch@^9.0.5:
version "9.0.6"
resolved "https://nexus.beatrice.wtf/repository/npm-group/minimatch/-/minimatch-9.0.6.tgz#a7e3bccfcb3d78ec1bf8d51c9ba749080237a5c8"
integrity sha512-kQAVowdR33euIqeA0+VZTDqU+qo1IeVY+hrKYtZMio3Pg0P0vuh/kwRylLUddJhB6pf3q/botcOvRtx4IN1wqQ==
minimatch@^10.2.2, minimatch@^10.2.4:
version "10.2.4"
resolved "https://nexus.beatrice.wtf/repository/npm-group/minimatch/-/minimatch-10.2.4.tgz#465b3accbd0218b8281f5301e27cedc697f96fde"
integrity sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==
dependencies:
brace-expansion "^5.0.2"
@@ -4220,9 +4237,9 @@ next-tick@^1.1.0:
integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==
node-releases@^2.0.27:
version "2.0.27"
resolved "https://nexus.beatrice.wtf/repository/npm-group/node-releases/-/node-releases-2.0.27.tgz#eedca519205cf20f650f61d56b070db111231e4e"
integrity sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==
version "2.0.36"
resolved "https://nexus.beatrice.wtf/repository/npm-group/node-releases/-/node-releases-2.0.36.tgz#99fd6552aaeda9e17c4713b57a63964a2e325e9d"
integrity sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==
normalize-path@^3.0.0, normalize-path@~3.0.0:
version "3.0.0"
@@ -4412,9 +4429,9 @@ postcss-value-parser@^4.0.0:
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
postcss@^8.4.47, postcss@^8.4.49, postcss@^8.5.6:
version "8.5.6"
resolved "https://nexus.beatrice.wtf/repository/npm-group/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c"
integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==
version "8.5.8"
resolved "https://nexus.beatrice.wtf/repository/npm-group/postcss/-/postcss-8.5.8.tgz#6230ecc8fb02e7a0f6982e53990937857e13f399"
integrity sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==
dependencies:
nanoid "^3.3.11"
picocolors "^1.1.1"
@@ -4545,16 +4562,16 @@ react-remove-scroll@^2.6.3:
use-sidecar "^1.1.3"
react-router-dom@^7.0.0:
version "7.13.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/react-router-dom/-/react-router-dom-7.13.0.tgz#8b5f7204fadca680f0e94f207c163f0dcd1cfdf5"
integrity sha512-5CO/l5Yahi2SKC6rGZ+HDEjpjkGaG/ncEP7eWFTvFxbHP8yeeI0PxTDjimtpXYlR3b3i9/WIL4VJttPrESIf2g==
version "7.13.1"
resolved "https://nexus.beatrice.wtf/repository/npm-group/react-router-dom/-/react-router-dom-7.13.1.tgz#74c045acc333ca94612b889cd1b1e1ee9534dead"
integrity sha512-UJnV3Rxc5TgUPJt2KJpo1Jpy0OKQr0AjgbZzBFjaPJcFOb2Y8jA5H3LT8HUJAiRLlWrEXWHbF1Z4SCZaQjWDHw==
dependencies:
react-router "7.13.0"
react-router "7.13.1"
react-router@7.13.0:
version "7.13.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/react-router/-/react-router-7.13.0.tgz#de9484aee764f4f65b93275836ff5944d7f5bd3b"
integrity sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw==
react-router@7.13.1:
version "7.13.1"
resolved "https://nexus.beatrice.wtf/repository/npm-group/react-router/-/react-router-7.13.1.tgz#5e2b3ebafd6c78d9775e135474bf5060645077f7"
integrity sha512-td+xP4X2/6BJvZoX6xw++A2DdEi++YypA69bJUV5oVvqf6/9/9nNlD70YO1e9d3MyamJEBQFEzk6mbfDYbqrSA==
dependencies:
cookie "^1.0.1"
set-cookie-parser "^2.6.0"
@@ -4746,15 +4763,15 @@ static-browser-server@1.0.3:
mime-db "^1.52.0"
outvariant "^1.3.0"
std-env@^3.10.0:
version "3.10.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/std-env/-/std-env-3.10.0.tgz#d810b27e3a073047b2b5e40034881f5ea6f9c83b"
integrity sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==
std-env@^4.0.0-rc.1:
version "4.0.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/std-env/-/std-env-4.0.0.tgz#ba3dc31c3a46bc5ba21138aa20a6a4ceb5bb9b7e"
integrity sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==
storybook@^10.2.10:
version "10.2.10"
resolved "https://nexus.beatrice.wtf/repository/npm-group/storybook/-/storybook-10.2.10.tgz#b0a008c239690889fc52ae95a35305d4c64b4306"
integrity sha512-N4U42qKgzMHS7DjqLz5bY4P7rnvJtYkWFCyKspZr3FhPUuy6CWOae3aYC2BjXkHrdug0Jyta6VxFTuB1tYUKhg==
version "10.2.17"
resolved "https://nexus.beatrice.wtf/repository/npm-group/storybook/-/storybook-10.2.17.tgz#32ac551d7c47e9a1d71d4caedabe638fa03bc2ea"
integrity sha512-yueTpl5YJqLzQqs3CanxNdAAfFU23iP0j+JVJURE4ghfEtRmWfWoZWLGkVcyjmgum7UmjwAlqRuOjQDNvH89kw==
dependencies:
"@storybook/global" "^5.0.0"
"@storybook/icons" "^2.0.1"
@@ -4910,9 +4927,9 @@ tinyrainbow@^2.0.0:
integrity sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==
tinyrainbow@^3.0.3:
version "3.0.3"
resolved "https://nexus.beatrice.wtf/repository/npm-group/tinyrainbow/-/tinyrainbow-3.0.3.tgz#984a5b1c1b25854a9b6bccbe77964d0593d1ea42"
integrity sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==
version "3.1.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/tinyrainbow/-/tinyrainbow-3.1.0.tgz#1d8a623893f95cf0a2ddb9e5d11150e191409421"
integrity sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==
tinyspy@^4.0.3:
version "4.0.4"
@@ -4994,14 +5011,14 @@ type@^2.7.2:
integrity sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==
typescript-eslint@^8.56.0:
version "8.56.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/typescript-eslint/-/typescript-eslint-8.56.0.tgz#f4686ccaaf2fb86daf0133820da40ca5961a2236"
integrity sha512-c7toRLrotJ9oixgdW7liukZpsnq5CZ7PuKztubGYlNppuTqhIoWfhgHo/7EU0v06gS2l/x0i2NEFK1qMIf0rIg==
version "8.57.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/typescript-eslint/-/typescript-eslint-8.57.0.tgz#82764795d316ed1c72a489727c43c3a87373f100"
integrity sha512-W8GcigEMEeB07xEZol8oJ26rigm3+bfPHxHvwbYUlu1fUDsGuQ7Hiskx5xGW/xM4USc9Ephe3jtv7ZYPQntHeA==
dependencies:
"@typescript-eslint/eslint-plugin" "8.56.0"
"@typescript-eslint/parser" "8.56.0"
"@typescript-eslint/typescript-estree" "8.56.0"
"@typescript-eslint/utils" "8.56.0"
"@typescript-eslint/eslint-plugin" "8.57.0"
"@typescript-eslint/parser" "8.57.0"
"@typescript-eslint/typescript-estree" "8.57.0"
"@typescript-eslint/utils" "8.57.0"
typescript@^5.6.2:
version "5.9.3"
@@ -5131,7 +5148,7 @@ vfile-message@^4.0.0:
"@types/unist" "^3.0.0"
unist-util-stringify-position "^4.0.0"
"vite@^6.0.0 || ^7.0.0", vite@^7.0.0:
"vite@^6.0.0 || ^7.0.0 || ^8.0.0-0", vite@^7.0.0:
version "7.3.1"
resolved "https://nexus.beatrice.wtf/repository/npm-group/vite/-/vite-7.3.1.tgz#7f6cfe8fb9074138605e822a75d9d30b814d6507"
integrity sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==
@@ -5146,29 +5163,29 @@ vfile-message@^4.0.0:
fsevents "~2.3.3"
vitest@^4.0.18:
version "4.0.18"
resolved "https://nexus.beatrice.wtf/repository/npm-group/vitest/-/vitest-4.0.18.tgz#56f966353eca0b50f4df7540cd4350ca6d454a05"
integrity sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==
version "4.1.0"
resolved "https://nexus.beatrice.wtf/repository/npm-group/vitest/-/vitest-4.1.0.tgz#b598abbe83f0c9e93d18cf3c5f23c75a525f8e82"
integrity sha512-YbDrMF9jM2Lqc++2530UourxZHmkKLxrs4+mYhEwqWS97WJ7wOYEkcr+QfRgJ3PW9wz3odRijLZjHEaRLTNbqw==
dependencies:
"@vitest/expect" "4.0.18"
"@vitest/mocker" "4.0.18"
"@vitest/pretty-format" "4.0.18"
"@vitest/runner" "4.0.18"
"@vitest/snapshot" "4.0.18"
"@vitest/spy" "4.0.18"
"@vitest/utils" "4.0.18"
es-module-lexer "^1.7.0"
expect-type "^1.2.2"
"@vitest/expect" "4.1.0"
"@vitest/mocker" "4.1.0"
"@vitest/pretty-format" "4.1.0"
"@vitest/runner" "4.1.0"
"@vitest/snapshot" "4.1.0"
"@vitest/spy" "4.1.0"
"@vitest/utils" "4.1.0"
es-module-lexer "^2.0.0"
expect-type "^1.3.0"
magic-string "^0.30.21"
obug "^2.1.1"
pathe "^2.0.3"
picomatch "^4.0.3"
std-env "^3.10.0"
std-env "^4.0.0-rc.1"
tinybench "^2.9.0"
tinyexec "^1.0.2"
tinyglobby "^0.2.15"
tinyrainbow "^3.0.3"
vite "^6.0.0 || ^7.0.0"
vite "^6.0.0 || ^7.0.0 || ^8.0.0-0"
why-is-node-running "^2.3.0"
w3c-keyname@^2.2.4: