diff --git a/.github/workflows/fe-ci.yml b/.github/workflows/fe-ci.yml new file mode 100644 index 00000000..d9dd454d --- /dev/null +++ b/.github/workflows/fe-ci.yml @@ -0,0 +1,53 @@ +name: fe-ci + +on: + pull_request: + branches: + - dev + paths: + - "frontend/**" + +jobs: + frontend: + runs-on: ubuntu-latest + + defaults: + run: + working-directory: ./frontend + + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Cache node_modules + uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm- + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Set .env file + run: | + echo "${{ secrets.FE_ENV }}" > .env + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Lint + run: pnpm lint + + - name: Build Frontend + run: pnpm build + + - name: Run Tests + run: pnpm test diff --git a/frontend/apps/client/__tests__/mocks/events.ts b/frontend/apps/client/__tests__/mocks/events.ts new file mode 100644 index 00000000..99868f2c --- /dev/null +++ b/frontend/apps/client/__tests__/mocks/events.ts @@ -0,0 +1,19 @@ +import type { PersonalEventResponse } from '@/features/my-calendar/model'; + +export const createCards = (num: number): PersonalEventResponse[] => + Array.from({ length: num }, (_, i) => { + const id = i + 1; + const baseDate = new Date('2023-10-01T00:00:00'); + const start = new Date(baseDate.getTime() + i * 30 * 60 * 1000); + const end = new Date(start.getTime() + 60 * 60 * 1000); + + return { + id, + title: `Test Event ${id}`, + startDateTime: start.toISOString(), + endDateTime: end.toISOString(), + isAdjustable: id % 2 === 1, + googleEventId: `google-event-id-${id}`, + calendarId: `calendar-id-${id}`, + }; + }); diff --git a/frontend/apps/client/__tests__/unit/my-calendar/card.tsx b/frontend/apps/client/__tests__/unit/my-calendar/card.tsx new file mode 100644 index 00000000..850c3d9c --- /dev/null +++ b/frontend/apps/client/__tests__/unit/my-calendar/card.tsx @@ -0,0 +1,43 @@ +import { render } from '@testing-library/react'; + +import { CalendarCardList } from '@/features/my-calendar/ui/CalendarCardList'; + +import { createCards } from '../../mocks/events'; + +describe('CalendarCardList', () => { + it('일반 일정 카드 리스트 컨테이너 렌더링', () => { + // given + const cards = createCards(10); + + // when + const { container } = render(); + const cardList = container.querySelector('[class*="CalendarCardList"]'); + + // then + expect(cardList).toBeVisible(); + }); + it('일반 일정 카드 아이템 렌더링', () => { + // given + const cards = createCards(10); + + // when + const { container } = render(); + + // then + const cardList = container.querySelector('[class*="CalendarCardList"]'); + expect(cardList?.childElementCount).toBe(cards.length); + }); + it.skip('겹치는 날짜 정렬 알고리즘 카드 렌더링 시간 100ms 이하', () => { + // given + const cards = createCards(1000); + + // when + const start = performance.now(); + render(); + const end = performance.now(); + + // then + expect(end - start).toBeLessThan(100); + }); +}, +); \ No newline at end of file diff --git a/frontend/apps/client/package.json b/frontend/apps/client/package.json index a84713f0..de844a68 100644 --- a/frontend/apps/client/package.json +++ b/frontend/apps/client/package.json @@ -25,8 +25,6 @@ "@tanstack/react-query": "^5.66.0", "@tanstack/react-router": "^1.109.2", "jotai": "^2.12.1", - "react": "^19.0.0", - "react-dom": "^19.0.0", "zod": "^3.24.1" }, "devDependencies": { diff --git a/frontend/apps/client/setup-file.ts b/frontend/apps/client/setup-file.ts new file mode 100644 index 00000000..331666ce --- /dev/null +++ b/frontend/apps/client/setup-file.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom'; \ No newline at end of file diff --git a/frontend/apps/client/src/features/my-calendar/ui/CalendarCardList/DefaultCard.tsx b/frontend/apps/client/src/features/my-calendar/ui/CalendarCardList/DefaultCard.tsx new file mode 100644 index 00000000..b98d4d22 --- /dev/null +++ b/frontend/apps/client/src/features/my-calendar/ui/CalendarCardList/DefaultCard.tsx @@ -0,0 +1,51 @@ +import { calcPositionByDate } from '@endolphin/core/utils'; +import type { EndolphinDate } from '@endolphin/date-time'; + +import { TIME_HEIGHT } from '@/constants/date'; + +import type { PersonalEventResponse } from '../../model'; +import { CalendarCard } from '../CalendarCard'; + +const calcSize = (height: number) => { + if (height < TIME_HEIGHT) return 'sm'; + if (height < TIME_HEIGHT * 2.5) return 'md'; + return 'lg'; +}; + +export const DefaultCard = ( + { card, start, end, idx }: + { card: PersonalEventResponse; start: EndolphinDate; end: EndolphinDate; idx: number }, +) => { + const LEFT_MARGIN = 24; + const RIGHT_MARGIN = 8; + const SIDEBAR_WIDTH = 72; + const TOP_GAP = 16; + const DAYS = 7; + const { x: sx, y: sy } = calcPositionByDate(start.getDate()); + const { y: ey } = calcPositionByDate(end.getDate()); + + if (sy === ey) return null; + + const height = ey - sy; + return ( + + ); +}; + \ No newline at end of file diff --git a/frontend/apps/client/src/features/my-calendar/ui/CalendarCardList/index.css.ts b/frontend/apps/client/src/features/my-calendar/ui/CalendarCardList/index.css.ts new file mode 100644 index 00000000..bac410fd --- /dev/null +++ b/frontend/apps/client/src/features/my-calendar/ui/CalendarCardList/index.css.ts @@ -0,0 +1,18 @@ +import { recipe } from '@vanilla-extract/recipes'; + +export const cardListStyle = recipe({ + base: {}, + variants: { + disable: { + true: { + pointerEvents: 'none', + }, + false: { + pointerEvents: 'auto', + }, + }, + }, + defaultVariants: { + disable: false, + }, +}); \ No newline at end of file diff --git a/frontend/apps/client/src/features/my-calendar/ui/CalendarCardList/index.tsx b/frontend/apps/client/src/features/my-calendar/ui/CalendarCardList/index.tsx index 1b7296b3..bd162af5 100644 --- a/frontend/apps/client/src/features/my-calendar/ui/CalendarCardList/index.tsx +++ b/frontend/apps/client/src/features/my-calendar/ui/CalendarCardList/index.tsx @@ -1,78 +1,52 @@ -import { TIME_HEIGHT } from '@constants/date'; -import { calcPositionByDate, getDateParts, isAllday } from '@endolphin/core/utils'; +import { isAllday } from '@endolphin/core/utils'; +import type { GroupInfo } from '@endolphin/date-time'; +import { EndolphinDate, groupByDate, groupByOverlap, sortDates } from '@endolphin/date-time'; import type { PersonalEventResponse } from '../../model'; -import { CalendarCard } from '../CalendarCard'; +import { DefaultCard } from './DefaultCard'; +import { cardListStyle } from './index.css'; -const calcSize = (height: number) => { - if (height < TIME_HEIGHT) return 'sm'; - if (height < TIME_HEIGHT * 2.5) return 'md'; - return 'lg'; +const createGroupInfo = (card: PersonalEventResponse): GroupInfo => { + const start = new EndolphinDate(card.startDateTime); + const end = new EndolphinDate(card.endDateTime); + const { year: sy, month: sm, day: sd } = start.getDateParts(); + const { year: ey, month: em, day: ed } = end.getDateParts(); + return { + id: card.id.toString(), + start, + end, + data: card, + sy, sm, sd, + ey, em, ed, + }; }; -const DefaultCard = ( - { card, start, end }: { card: PersonalEventResponse; start: Date; end: Date }, -) => { - const { x: sx, y: sy } = calcPositionByDate(start); - const { y: ey } = calcPositionByDate(end); - - if (sy === ey) return null; +export const CalendarCardList = ({ cards, isSelecting }: { + cards: PersonalEventResponse[]; + isSelecting: boolean; +}) => { + const isNotAlldayCards + = cards.filter((card)=>!isAllday(card.startDateTime, card.endDateTime)).map(createGroupInfo); - const height = ey - sy; return ( - +
+ {groupByDate(isNotAlldayCards).map((dayCards) => + groupByOverlap(dayCards.sort((a, b)=> + sortDates( + { start: a.start, end: a.end }, + { start: b.start, end: b.end }, + ))) + .map(({ id, data, start, end, idx }) => ( + + ), + ), + )} +
); -}; - -export const CalendarCardList = ({ cards }: { cards: PersonalEventResponse[] }) => ( - <> - {cards.filter((card) => !isAllday(card.startDateTime, card.endDateTime)) - .map((card) => { - const start = new Date(card.startDateTime); - const end = new Date(card.endDateTime); - const { year: sy, month: sm, day: sd } = getDateParts(start); - const { year: ey, month: em, day: ed } = getDateParts(end); - - if (sd !== ed) { - return ( -
- - -
- ); - } - - return ( - - ); - })} - -); \ No newline at end of file +}; \ No newline at end of file diff --git a/frontend/apps/client/src/features/my-calendar/ui/MyCalendar/CalendarTable.tsx b/frontend/apps/client/src/features/my-calendar/ui/MyCalendar/CalendarTable.tsx index b45416eb..a4d1146e 100644 --- a/frontend/apps/client/src/features/my-calendar/ui/MyCalendar/CalendarTable.tsx +++ b/frontend/apps/client/src/features/my-calendar/ui/MyCalendar/CalendarTable.tsx @@ -35,7 +35,7 @@ const CalendarTable = ( type='add' />} - + { }; export interface TimeInfo { + isSelecting: boolean; selectedStartTime: Date | null; selectedEndTime: Date | null; doneStartTime: Date | null; @@ -105,6 +106,7 @@ export const useSelectTime = (): TimeInfo => { ); return { + isSelecting: state.isSelecting, selectedStartTime: state.selectedTime.startTime, selectedEndTime: state.selectedTime.endTime, doneStartTime: state.doneTime.startTime, diff --git a/frontend/packages/date-time/__tests__/group.test.ts b/frontend/packages/date-time/__tests__/group.test.ts new file mode 100644 index 00000000..8da2269f --- /dev/null +++ b/frontend/packages/date-time/__tests__/group.test.ts @@ -0,0 +1,32 @@ +import { groupByDate, groupByOverlap } from '@/group'; + +import { DAY_GROUP_CASE, NON_OVERLAPPING_CASE, OVERLAPPING_CASE } from './mocks'; +import { deepCompareGroups, deepCompareOverlappedDates } from './utils'; + +describe('groupByOverlap', () => { + it('겹치지 않는 항목들을 각 그룹으로 분리', () => { + const input = NON_OVERLAPPING_CASE.input; + + const result = groupByOverlap(input); + + expect(deepCompareOverlappedDates(result, NON_OVERLAPPING_CASE.expected)).toBe(true); + }); + + it('겹치는 항목들을 같은 그룹으로 병합', () => { + const input = OVERLAPPING_CASE.input; + + const result = groupByOverlap(input); + + expect(deepCompareOverlappedDates(result, OVERLAPPING_CASE.expected)).toBe(true); + }); +}); + +describe('groupByDate', () => { + it('날짜별로 그룹화된 객체 배열을 반환', () => { + const input = DAY_GROUP_CASE.input; + + const result = groupByDate(input); + + expect(deepCompareGroups(result, DAY_GROUP_CASE.expected)).toBe(true); + }); +}); \ No newline at end of file diff --git a/frontend/packages/date-time/__tests__/mocks/index.ts b/frontend/packages/date-time/__tests__/mocks/index.ts new file mode 100644 index 00000000..3865f410 --- /dev/null +++ b/frontend/packages/date-time/__tests__/mocks/index.ts @@ -0,0 +1,167 @@ +import EndolphinDate from '@/date'; +import type { DateRangeWithId, GroupInfo, OverlapDate, ReturnItem } from '@/group'; +import type { DateRange } from '@/type'; + +export const NON_OVERLAPPING_CASE: { + input: DateRangeWithId[]; + expected: OverlapDate[]; +} = { + input: [ + { id: 'a', start: new EndolphinDate('2023-01-01'), end: new EndolphinDate('2023-01-02') }, + { id: 'b', start: new EndolphinDate('2023-01-03'), end: new EndolphinDate('2023-01-04') }, + { id: 'c', start: new EndolphinDate('2023-01-05'), end: new EndolphinDate('2023-01-06') }, + ], + expected: [ + { + id: 'a', + start: new EndolphinDate('2023-01-01'), + end: new EndolphinDate('2023-01-02'), idx: 0, + }, + { + id: 'b', + start: new EndolphinDate('2023-01-03'), + end: new EndolphinDate('2023-01-04'), idx: 0, + }, + { + id: 'c', + start: new EndolphinDate('2023-01-05'), + end: new EndolphinDate('2023-01-06'), idx: 0, + }, + ], +}; + +export const OVERLAPPING_CASE: { + input: DateRangeWithId[]; + expected: OverlapDate[]; +} = { + input: [ + { id: 'a', start: new EndolphinDate('2023-01-01'), end: new EndolphinDate('2023-01-05') }, + { id: 'b', start: new EndolphinDate('2023-01-03'), end: new EndolphinDate('2023-01-07') }, + { id: 'c', start: new EndolphinDate('2023-01-08'), end: new EndolphinDate('2023-01-10') }, + { id: 'd', start: new EndolphinDate('2023-01-09'), end: new EndolphinDate('2023-01-12') }, + ], + expected: [ + { + id: 'a', + start: new EndolphinDate('2023-01-01'), + end: new EndolphinDate('2023-01-05'), + idx: 0, + }, + { + id: 'b', + start: new EndolphinDate('2023-01-03'), + end: new EndolphinDate('2023-01-07'), + idx: 1, + }, + { + id: 'c', + start: new EndolphinDate('2023-01-08'), + end: new EndolphinDate('2023-01-10'), + idx: 0, + }, + { + id: 'd', + start: new EndolphinDate('2023-01-09'), + end: new EndolphinDate('2023-01-12'), + idx: 1, + }, + ], +}; + +export const DAY_GROUP_CASE: { + input: GroupInfo[]; + expected: ReturnItem[][]; +} = { + input: [ + { + id: '1', + data: null, + start: new EndolphinDate(2023, 1, 1, 4, 0), + end: new EndolphinDate(2023, 1, 2, 1, 0), + sy: 2023, + sm: 1, + sd: 1, + ey: 2023, + em: 1, + ed: 2, + }, + { + id: '2', + data: null, + start: new EndolphinDate(2023, 1, 2, 23, 0), + end: new EndolphinDate(2023, 1, 3, 1, 0), + sy: 2023, + sm: 1, + sd: 2, + ey: 2023, + em: 1, + ed: 3, + }, + { + id: '3', + data: null, + start: new EndolphinDate(2023, 1, 1, 10, 0), + end: new EndolphinDate(2023, 1, 1, 11, 0), + sy: 2023, + sm: 1, + sd: 1, + ey: 2023, + em: 1, + ed: 1, + }, + ], + expected: [ + [ + { + id: '1', + data: null, + start: new EndolphinDate(2023, 1, 1, 4, 0), + end: new EndolphinDate(2023, 1, 1, 23, 59), + }, + { + id: '3', + data: null, + start: new EndolphinDate(2023, 1, 1, 10, 0), + end: new EndolphinDate(2023, 1, 1, 11, 0), + }, + ], + [ + { + id: '1', + data: null, + start: new EndolphinDate(2023, 1, 2, 0, 0), + end: new EndolphinDate(2023, 1, 2, 1, 0), + }, + { + id: '2', + data: null, + start: new EndolphinDate(2023, 1, 2, 23, 0), + end: new EndolphinDate(2023, 1, 2, 23, 59), + }, + ], + [ + { + id: '2', + data: null, + start: new EndolphinDate(2023, 1, 3, 0, 0), + end: new EndolphinDate(2023, 1, 3, 1, 0), + }, + ], + ], +}; + +export const SORT_CASE: { + input: DateRange[]; + expected: DateRange[]; +} = { + input: [ + { start: new EndolphinDate('2023-01-02'), end: new EndolphinDate('2023-01-03') }, + { start: new EndolphinDate('2023-01-01'), end: new EndolphinDate('2023-01-02') }, + { start: new EndolphinDate('2023-01-03'), end: new EndolphinDate('2023-01-04') }, + ], + expected: [ + { start: new EndolphinDate('2023-01-01'), end: new EndolphinDate('2023-01-02') }, + { start: new EndolphinDate('2023-01-02'), end: new EndolphinDate('2023-01-03') }, + { start: new EndolphinDate('2023-01-03'), end: new EndolphinDate('2023-01-04') }, + ], +}; \ No newline at end of file diff --git a/frontend/packages/date-time/__tests__/sort.test.ts b/frontend/packages/date-time/__tests__/sort.test.ts new file mode 100644 index 00000000..c2de6026 --- /dev/null +++ b/frontend/packages/date-time/__tests__/sort.test.ts @@ -0,0 +1,31 @@ +import EndolphinDate from '@/date'; +import { sortDates } from '@/sort'; +import type { DateRange } from '@/type'; + +import { SORT_CASE } from './mocks'; +import { deepCompareDateRanges } from './utils'; + +describe('sortDates', () => { + it('날짜 배열 오름차순 정렬', () => { + // given + const dates = SORT_CASE.input; + + // when + const sorted = dates.sort(sortDates); + + // then + expect(deepCompareDateRanges(SORT_CASE.expected, sorted)).toBe(true); + }); + + it('단일 날짜 처리', () => { + // given + const dates: DateRange[] + = [{ start: new EndolphinDate('2023-01-02'), end: new EndolphinDate('2023-01-03') }]; + + // when + const sorted = dates.sort(sortDates); + + // then + expect(deepCompareDateRanges(dates, sorted)).toBe(true); + }); +}); \ No newline at end of file diff --git a/frontend/packages/date-time/__tests__/utils/index.ts b/frontend/packages/date-time/__tests__/utils/index.ts new file mode 100644 index 00000000..49e648ad --- /dev/null +++ b/frontend/packages/date-time/__tests__/utils/index.ts @@ -0,0 +1,50 @@ +import type { OverlapDate, ReturnItem } from '@/group'; +import type { DateRange } from '@/type'; + +export const deepCompareDateRanges = ( + a: DateRange[], + b: DateRange[], +): boolean => { + if (a.length !== b.length) return false; + + return a.every(({ start: as, end: ae }, index) => { + const { start: bs, end: be } = b[index]; + return as.formatDateToBarString() === bs.formatDateToBarString() + && ae.formatDateToBarString() === be.formatDateToBarString(); + }); +}; + +// TODO: diff 체크를 쉽게 하기 위해 커스텀 설정 추가하기 +// 또는 중첩된 객체 비교 쉽게 하는법..? 순서 상관 없이. +export const deepCompareGroups = ( + a: ReturnItem[][], + b: ReturnItem[][], +): boolean => { + if (a.length !== b.length) return false; + + return a.every((groupA, index) => { + const groupB = b[index]; + if (groupA.length !== groupB.length) return false; + + return groupA.every((itemA, itemIndex) => { + const itemB = groupB[itemIndex]; + return itemA.id === itemB.id + && itemA.start.formatDateToBarString() === itemB.start.formatDateToBarString() + && itemA.end.formatDateToBarString() === itemB.end.formatDateToBarString(); + }); + }); +}; + +export const deepCompareOverlappedDates = ( + a: OverlapDate[], + b: OverlapDate[], +): boolean => { + if (a.length !== b.length) return false; + + return a.every(({ start: as, end: ae, idx: aidx }, index) => { + const { start: bs, end: be, idx: bidx } = b[index]; + return aidx === bidx + && as.formatDateToBarString() === bs.formatDateToBarString() + && ae.formatDateToBarString() === be.formatDateToBarString(); + }); +}; \ No newline at end of file diff --git a/frontend/packages/date-time/src/constants/regex.ts b/frontend/packages/date-time/src/constants/regex.ts index d73bd224..173887d2 100644 --- a/frontend/packages/date-time/src/constants/regex.ts +++ b/frontend/packages/date-time/src/constants/regex.ts @@ -1,4 +1,4 @@ export const DATE_BAR = /^\d{4}-\d{2}-\d{2}$/; -export const DATETIME = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/; +export const DATETIME = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+Z)?$/; export const TIME = /^\d{2}:\d{2}$/; export const PASSWORD = /^[0-9]{4,6}$/; \ No newline at end of file diff --git a/frontend/packages/date-time/src/date.ts b/frontend/packages/date-time/src/date.ts index f9843c20..69baed09 100644 --- a/frontend/packages/date-time/src/date.ts +++ b/frontend/packages/date-time/src/date.ts @@ -1,18 +1,28 @@ import { DATE_BAR, DATETIME } from '@constants/regex'; +import * as date from '@utils/date'; import * as format from '@utils/format'; import type { InputDate } from './type'; export default class EndolphinDate { #date; - - constructor (input: InputDate) { - this.#date = this.#formateToDate(input); + + constructor (input: InputDate); + constructor (year: number, month: number, day: number, hour?: number, minute?: number); + + constructor (...args: [InputDate] | [number, number, number, number?, number?]) { + if (args.length === 1) { + const [input] = args; + this.#date = this.#formateToDate(input); + } else { + const [year, month, day, hour = 0, minute = 0] = args; + this.#date = new Date(year, month, day, hour, minute); + } } #formateToDate (input: InputDate): Date | null { if (!input) return null; - if (input instanceof Date) return this.#date; + if (input instanceof Date) return input; if (typeof input === 'number') { return new Date(input); } @@ -58,4 +68,24 @@ export default class EndolphinDate { getDate () { return this.#date; } + + getDateParts () { + if (!this.#date) return { year: 0, month: 0, day: 0 }; + const { year, month, day } = date.getDateParts(this.#date); + return { year, month, day }; + } + + valueOf () { + if (!this.#date) return NaN; + return this.#date.getTime(); + } + + toString () { + return format.formatDateToBarString(this.#date); + } + + [Symbol.toPrimitive] (hint: string) { + if (hint === 'number') return this.valueOf(); + return this.toString(); + } } \ No newline at end of file diff --git a/frontend/packages/date-time/src/group.ts b/frontend/packages/date-time/src/group.ts new file mode 100644 index 00000000..80cb2380 --- /dev/null +++ b/frontend/packages/date-time/src/group.ts @@ -0,0 +1,83 @@ +import EndolphinDate from './date'; +import type { DateRange } from './type'; + +export type DateRangeWithId = DateRange & { + id: string; +}; + +export type OverlapDate = T & { + idx: number; +}; + +export interface GroupInfo { + id: string; + data: T; + start: EndolphinDate; + end: EndolphinDate; + sy: number; + sm: number; + sd: number; + ey: number; + em: number; + ed: number; +} + +export type ReturnItem = DateRangeWithId & { + data: T; +}; + +/** + * + * @param dateInfos - 날짜 범위와 ID를 포함하는 객체 배열 + * @returns - 겹치는 날짜 범위를 그룹화하여 반환 + */ +export const groupByOverlap = (dateInfos: T[]): OverlapDate[] => { + const groups = [] as OverlapDate[][]; + + for (const current of dateInfos) { + const lastGroup = groups[groups.length - 1]; + const isNewGroup = + !lastGroup || lastGroup[lastGroup.length - 1].end <= current.start; + + if (isNewGroup) groups.push([{ ...current, idx: 0 }]); + else lastGroup.push({ ...current, idx: lastGroup.length }); + } + + return groups.flat(); +}; + +/** + * + * @param infos - 날짜 범위와 ID, 시작 및 종료 날짜를 포함하는 객체 배열 + * @returns - 날짜별로 그룹화된 객체 배열 + */ +export const groupByDate = (infos: GroupInfo[]): ReturnItem[][] => { + const group = {} as Record[]>; + + const add = (key: number, content: ReturnItem) => { + if (!group[key]) group[key] = []; + group[key].push(content); + return group; + }; + + const result = infos.reduce((acc, info) => { + const { id, data, start, end, sy, sm, sd, ey, em, ed } = info; + const startDate = start.getDate(); + const endDate = end.getDate(); + + if (!startDate || !endDate) return acc; + + const startDay = startDate.getDay(); + const endDay = endDate.getDay(); + + if (sd !== ed) { + add(startDay, { id, data, start, end: new EndolphinDate(sy, sm, sd, 23, 59) }); + add(endDay, { id, data, start: new EndolphinDate(ey, em, ed, 0, 0), end }); + return acc; + } + + return add(startDay, { id, data, start, end }); + }, group); + + return Object.values(result); +}; \ No newline at end of file diff --git a/frontend/packages/date-time/src/index.ts b/frontend/packages/date-time/src/index.ts index 655557ee..595e3283 100644 --- a/frontend/packages/date-time/src/index.ts +++ b/frontend/packages/date-time/src/index.ts @@ -1,2 +1,4 @@ export { default as EndolphinDate } from './date'; +export * from './group'; +export * from './sort'; export { default as EndolphinTime } from './time'; \ No newline at end of file diff --git a/frontend/packages/date-time/src/sort.ts b/frontend/packages/date-time/src/sort.ts new file mode 100644 index 00000000..111bc73c --- /dev/null +++ b/frontend/packages/date-time/src/sort.ts @@ -0,0 +1,16 @@ +import type { DateRange } from './type'; + +/** + * + * @param d1 - 첫 번째 날짜 범위 + * @param d2 - 두 번째 날짜 범위 + * @returns - 날짜 범위를 비교하여 정렬 순서를 반환합니다. + */ +export const sortDates = (d1: DateRange, d2: DateRange) => { + if (d1.start < d2.start) return -1; + if (d1.start > d2.start) return 1; + if (d1.end < d2.end) return -1; + if (d1.end > d2.end) return 1; + + return 0; +}; \ No newline at end of file diff --git a/frontend/packages/date-time/src/type.ts b/frontend/packages/date-time/src/type.ts index 8bc7d71f..fb8fe66d 100644 --- a/frontend/packages/date-time/src/type.ts +++ b/frontend/packages/date-time/src/type.ts @@ -8,4 +8,9 @@ export interface Time { hour: number; minute: number; second: number; -} \ No newline at end of file +} + +export interface DateRange { + start: EndolphinDate; + end: EndolphinDate; +}; \ No newline at end of file diff --git a/frontend/packages/date-time/src/utils/date.ts b/frontend/packages/date-time/src/utils/date.ts index 380c4aa3..d4f22d08 100644 --- a/frontend/packages/date-time/src/utils/date.ts +++ b/frontend/packages/date-time/src/utils/date.ts @@ -204,11 +204,13 @@ export const getYearMonthDay = (date: Date) => { return { year, month, day }; }; -export const isAllday = (startDate: string, endDate: string): boolean => { - const ALL_DAY = 24 * 60 * 60 * 1000; - +export const isAllday = ( + startDate: string | Date | null, + endDate: string | Date | null, +): boolean => { if (!startDate || !endDate) return false; - return new Date(endDate).getTime() - new Date(startDate).getTime() >= ALL_DAY; + + return new Date(endDate).getTime() - new Date(startDate).getTime() >= DAY_IN_MILLISECONDS; }; export const getDateRangeString = (startDate: Date, endDate: Date): string => { diff --git a/frontend/packages/date-time/tsconfig.json b/frontend/packages/date-time/tsconfig.json index 63ef14fd..6bffe564 100644 --- a/frontend/packages/date-time/tsconfig.json +++ b/frontend/packages/date-time/tsconfig.json @@ -13,7 +13,7 @@ /* Module Resolution */ // "composite": true, "outDir": "./dist", - "types": [], + "types": ["vitest/globals"], }, - "include": ["src"] + "include": ["src", "__tests__"], } diff --git a/frontend/packages/date-time/vitest.config.ts b/frontend/packages/date-time/vitest.config.ts index 89316651..9a484447 100644 --- a/frontend/packages/date-time/vitest.config.ts +++ b/frontend/packages/date-time/vitest.config.ts @@ -10,6 +10,9 @@ export default mergeConfig( nodeConfig, defineProject({ root: dirname, + test: { + include: ['__tests__/*.test.ts'], + }, resolve: { alias: createAlias(dirname), }, diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index f2b8a0dd..8f69cc47 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -19,7 +19,7 @@ importers: version: 2.29.4 '@chromatic-com/storybook': specifier: ^3.2.4 - version: 3.2.4(react@18.3.1)(storybook@8.5.2(prettier@3.4.2)) + version: 3.2.4(react@19.0.0)(storybook@8.5.2(prettier@3.4.2)) '@eslint/js': specifier: ^9.17.0 version: 9.19.0 @@ -31,13 +31,13 @@ importers: version: 8.5.2(storybook@8.5.2(prettier@3.4.2)) '@storybook/blocks': specifier: ^8.5.2 - version: 8.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.5.2(prettier@3.4.2)) + version: 8.5.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.2(prettier@3.4.2)) '@storybook/react': specifier: ^8.5.2 - version: 8.5.2(@storybook/test@8.5.2(storybook@8.5.2(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.5.2(prettier@3.4.2))(typescript@5.6.3) + version: 8.5.2(@storybook/test@8.5.2(storybook@8.5.2(prettier@3.4.2)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.2(prettier@3.4.2))(typescript@5.6.3) '@storybook/react-vite': specifier: ^8.5.2 - version: 8.5.2(@storybook/test@8.5.2(storybook@8.5.2(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.40.2)(storybook@8.5.2(prettier@3.4.2))(typescript@5.6.3)(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2)) + version: 8.5.2(@storybook/test@8.5.2(storybook@8.5.2(prettier@3.4.2)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@4.40.2)(storybook@8.5.2(prettier@3.4.2))(typescript@5.6.3)(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2)) '@storybook/test': specifier: ^8.5.2 version: 8.5.2(storybook@8.5.2(prettier@3.4.2)) @@ -49,16 +49,19 @@ importers: version: 5.66.1(eslint@9.19.0)(typescript@5.6.3) '@tanstack/router-devtools': specifier: ^1.99.0 - version: 1.99.0(@tanstack/react-router@1.109.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(csstype@3.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 1.99.0(@tanstack/react-router@1.109.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@tanstack/router-plugin': specifier: ^1.99.3 - version: 1.99.3(@tanstack/react-router@1.109.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2)) + version: 1.99.3(@tanstack/react-router@1.109.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2)) '@testing-library/dom': specifier: ^10.4.0 version: 10.4.0 + '@testing-library/jest-dom': + specifier: ^6.6.3 + version: 6.6.3 '@testing-library/react': - specifier: ^16.2.0 - version: 16.2.0(@testing-library/dom@10.4.0)(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^16.3.0 + version: 16.3.0(@testing-library/dom@10.4.0)(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@types/react': specifier: ^19.0.8 version: 19.0.8 @@ -83,6 +86,9 @@ importers: '@vitejs/plugin-react': specifier: ^4.3.4 version: 4.3.4(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2)) + '@vitest/browser': + specifier: ^3.2.3 + version: 3.2.3(playwright@1.52.0)(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2))(vitest@3.2.3) cross-env: specifier: ^7.0.3 version: 7.0.3 @@ -113,6 +119,15 @@ importers: jsdom: specifier: ^26.0.0 version: 26.0.0 + playwright: + specifier: ^1.52.0 + version: 1.52.0 + react: + specifier: ^19.0.0 + version: 19.0.0 + react-dom: + specifier: ^19.0.0 + version: 19.0.0(react@19.0.0) sharp: specifier: ^0.33.5 version: 0.33.5 @@ -135,8 +150,8 @@ importers: specifier: ^6.0.5 version: 6.0.11(@types/node@22.15.21)(tsx@4.19.2) vitest: - specifier: ^3.2.2 - version: 3.2.2(@types/node@22.15.21)(jsdom@26.0.0)(tsx@4.19.2) + specifier: ^3.2.3 + version: 3.2.3(@types/node@22.15.21)(@vitest/browser@3.2.3)(jsdom@26.0.0)(tsx@4.19.2) apps/client: dependencies: @@ -164,12 +179,6 @@ importers: jotai: specifier: ^2.12.1 version: 2.12.1(@types/react@19.0.8)(react@19.0.0) - react: - specifier: ^19.0.0 - version: 19.0.0 - react-dom: - specifier: ^19.0.0 - version: 19.0.0(react@19.0.0) zod: specifier: ^3.24.1 version: 3.24.1 @@ -867,6 +876,9 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@polka/url@1.0.0-next.29': + resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + '@rollup/pluginutils@5.1.4': resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} engines: {node: '>=14.0.0'} @@ -1332,8 +1344,12 @@ packages: resolution: {integrity: sha512-xGGHpBXYSHUUr6XsKBfs85TWlYKpTc37cSBBVrXcib2MkHLboWlkClhWF37JKlDb9KEq3dHs+f2xR7XJEWGBxA==} engines: {node: '>=14', npm: '>=6', yarn: '>=1'} - '@testing-library/react@16.2.0': - resolution: {integrity: sha512-2cSskAvA1QNtKc8Y9VJQRv0tm3hLVgxRGDB+KYhIaPQJ1I+RHbhIXcM+zClKXzMes/wshsMVzf4B9vS4IZpqDQ==} + '@testing-library/jest-dom@6.6.3': + resolution: {integrity: sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==} + engines: {node: '>=14', npm: '>=6', yarn: '>=1'} + + '@testing-library/react@16.3.0': + resolution: {integrity: sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==} engines: {node: '>=18'} peerDependencies: '@testing-library/dom': ^10.0.0 @@ -1353,6 +1369,12 @@ packages: peerDependencies: '@testing-library/dom': '>=7.21.4' + '@testing-library/user-event@14.6.1': + resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==} + engines: {node: '>=12', npm: '>=6'} + peerDependencies: + '@testing-library/dom': '>=7.21.4' + '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} @@ -1495,8 +1517,11 @@ packages: '@vanilla-extract/babel-plugin-debug-ids@1.2.0': resolution: {integrity: sha512-z5nx2QBnOhvmlmBKeRX5sPVLz437wV30u+GJL+Hzj1rGiJYVNvgIIlzUpRNjVQ0MgAgiQIqIUbqPnmMc6HmDlQ==} - '@vanilla-extract/compiler@0.1.1': - resolution: {integrity: sha512-OJk31hrDZlDKP7K3Yr5y731Wrm1vf7fNyM5eXjfGyDovZLcVAFuB8tt7pXqpdCz0RnrKsMzlvJD3f6WT2MaIug==} + '@vanilla-extract/babel-plugin-debug-ids@1.2.1': + resolution: {integrity: sha512-RkXKzcKVZtcDNmcGh8Bv9MNW6oYYUzy90GYt8amMrk5P+myXsdFSU9N7V+cJAf80l+AsMVMyK0GK7Qj35Sfppg==} + + '@vanilla-extract/compiler@0.1.3': + resolution: {integrity: sha512-dSkRFwHfOccEZGlQ6hdRDGQMLko8RZnAKd06u9+gPkRyjNt96nG6ZE/wEh4+3cdY27DPdTLh+TPlTp2DYo94OA==} '@vanilla-extract/css@1.17.1': resolution: {integrity: sha512-tOHQXHm10FrJeXKFeWE09JfDGN/tvV6mbjwoNB9k03u930Vg021vTnbrCwVLkECj9Zvh/SHLBHJ4r2flGqfovw==} @@ -1504,6 +1529,9 @@ packages: '@vanilla-extract/css@1.17.2': resolution: {integrity: sha512-gowpfR1zJSplDO7NkGf2Vnw9v9eG1P3aUlQpxa1pOjcknbgWw7UPzIboB6vGJZmoUvDZRFmipss3/Q+RRfhloQ==} + '@vanilla-extract/css@1.17.3': + resolution: {integrity: sha512-jHivr1UPoJTX5Uel4AZSOwrCf4mO42LcdmnhJtUxZaRWhW4FviFbIfs0moAWWld7GOT+2XnuVZjjA/K32uUnMQ==} + '@vanilla-extract/dynamic@2.1.2': resolution: {integrity: sha512-9BGMciD8rO1hdSPIAh1ntsG4LPD3IYKhywR7VOmmz9OO4Lx1hlwkSg3E6X07ujFx7YuBfx0GDQnApG9ESHvB2A==} @@ -1515,18 +1543,21 @@ packages: esbuild: optional: true - '@vanilla-extract/integration@8.0.0': - resolution: {integrity: sha512-hsu5Cqs30RDTRgaOCtvdZttKIaMImObcZmylxPp693mr1pyRk+WEIEAzQAJkXE/JQ47xyqf+a63UxdI0Sf3PZw==} - '@vanilla-extract/integration@8.0.2': resolution: {integrity: sha512-w9OvWwsYkqyuyHf9NLnOJ8ap0FGTy2pAeWftgxAEkKE3tF1aYeyEtYRHKxfVH6JRgi8JIeQqELHGMSwz+BxwiA==} + '@vanilla-extract/integration@8.0.3': + resolution: {integrity: sha512-7sCd4kBp/u02iNq3cYBXtOzKyX5muoHylsqcEjyuJWfnxOb1iB/jDCyTsiSRXcByj/wKjgjItbAdm/uzrUlAVw==} + '@vanilla-extract/private@1.0.6': resolution: {integrity: sha512-ytsG/JLweEjw7DBuZ/0JCN4WAQgM9erfSTdS1NQY778hFQSZ6cfCDEZZ0sgVm4k54uNz6ImKB33AYvSR//fjxw==} '@vanilla-extract/private@1.0.7': resolution: {integrity: sha512-v9Yb0bZ5H5Kr8ciwPXyEToOFD7J/fKKH93BYP7NCSZg02VYsA/pNFrLeVDJM2OO/vsygduPKuiEI6ORGQ4IcBw==} + '@vanilla-extract/private@1.0.8': + resolution: {integrity: sha512-oRAbUlq1SyTWCo7dQnTVm+xgJMqNl8K1dEempQHXzQvUuyEfBabMt0wNGf+VCHzvKbx/Bzr9p/2wy8WA9+2z2g==} + '@vanilla-extract/recipes@0.5.5': resolution: {integrity: sha512-VadU7+IFUwLNLMgks29AHav/K5h7DOEfTU91RItn5vwdPfzduodNg317YbgWCcpm7FSXkuR3B3X8ZOi95UOozA==} peerDependencies: @@ -1543,14 +1574,29 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 + '@vitest/browser@3.2.3': + resolution: {integrity: sha512-5HpUb0ixGF8JWSAjb/P1x/VPuTYUkL4pL0+YO6DJiuvQgqJN3PREaUEcXwfXjU4nBc37EahfpRbAwdE9pHs9lQ==} + peerDependencies: + playwright: '*' + safaridriver: '*' + vitest: 3.2.3 + webdriverio: ^7.0.0 || ^8.0.0 || ^9.0.0 + peerDependenciesMeta: + playwright: + optional: true + safaridriver: + optional: true + webdriverio: + optional: true + '@vitest/expect@2.0.5': resolution: {integrity: sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==} - '@vitest/expect@3.2.2': - resolution: {integrity: sha512-ipHw0z669vEMjzz3xQE8nJX1s0rQIb7oEl4jjl35qWTwm/KIHERIg/p/zORrjAaZKXfsv7IybcNGHwhOOAPMwQ==} + '@vitest/expect@3.2.3': + resolution: {integrity: sha512-W2RH2TPWVHA1o7UmaFKISPvdicFJH+mjykctJFoAkUw+SPTJTGjUNdKscFBrqM7IPnCVu6zihtKYa7TkZS1dkQ==} - '@vitest/mocker@3.2.2': - resolution: {integrity: sha512-jKojcaRyIYpDEf+s7/dD3LJt53c0dPfp5zCPXz9H/kcGrSlovU/t1yEaNzM9oFME3dcd4ULwRI/x0Po1Zf+LTw==} + '@vitest/mocker@3.2.3': + resolution: {integrity: sha512-cP6fIun+Zx8he4rbWvi+Oya6goKQDZK+Yq4hhlggwQBbrlOQ4qtZ+G4nxB6ZnzI9lyIb+JnvyiJnPC2AGbKSPA==} peerDependencies: msw: ^2.4.9 vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 @@ -1566,20 +1612,20 @@ packages: '@vitest/pretty-format@2.1.8': resolution: {integrity: sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==} - '@vitest/pretty-format@3.2.2': - resolution: {integrity: sha512-FY4o4U1UDhO9KMd2Wee5vumwcaHw7Vg4V7yR4Oq6uK34nhEJOmdRYrk3ClburPRUA09lXD/oXWZ8y/Sdma0aUQ==} + '@vitest/pretty-format@3.2.3': + resolution: {integrity: sha512-yFglXGkr9hW/yEXngO+IKMhP0jxyFw2/qys/CK4fFUZnSltD+MU7dVYGrH8rvPcK/O6feXQA+EU33gjaBBbAng==} - '@vitest/runner@3.2.2': - resolution: {integrity: sha512-GYcHcaS3ejGRZYed2GAkvsjBeXIEerDKdX3orQrBJqLRiea4NSS9qvn9Nxmuy1IwIB+EjFOaxXnX79l8HFaBwg==} + '@vitest/runner@3.2.3': + resolution: {integrity: sha512-83HWYisT3IpMaU9LN+VN+/nLHVBCSIUKJzGxC5RWUOsK1h3USg7ojL+UXQR3b4o4UBIWCYdD2fxuzM7PQQ1u8w==} - '@vitest/snapshot@3.2.2': - resolution: {integrity: sha512-aMEI2XFlR1aNECbBs5C5IZopfi5Lb8QJZGGpzS8ZUHML5La5wCbrbhLOVSME68qwpT05ROEEOAZPRXFpxZV2wA==} + '@vitest/snapshot@3.2.3': + resolution: {integrity: sha512-9gIVWx2+tysDqUmmM1L0hwadyumqssOL1r8KJipwLx5JVYyxvVRfxvMq7DaWbZZsCqZnu/dZedaZQh4iYTtneA==} '@vitest/spy@2.0.5': resolution: {integrity: sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==} - '@vitest/spy@3.2.2': - resolution: {integrity: sha512-6Utxlx3o7pcTxvp0u8kUiXtRFScMrUg28KjB3R2hon7w4YqOFAEA9QwzPVVS1QNL3smo4xRNOpNZClRVfpMcYg==} + '@vitest/spy@3.2.3': + resolution: {integrity: sha512-JHu9Wl+7bf6FEejTCREy+DmgWe+rQKbK+y32C/k5f4TBIAlijhJbRBIRIOCEpVevgRsCQR2iHRUH2/qKVM/plw==} '@vitest/utils@2.0.5': resolution: {integrity: sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==} @@ -1587,8 +1633,8 @@ packages: '@vitest/utils@2.1.8': resolution: {integrity: sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==} - '@vitest/utils@3.2.2': - resolution: {integrity: sha512-qJYMllrWpF/OYfWHP32T31QCaLa3BAzT/n/8mNGhPdVcjY+JYazQFO1nsJvXU12Kp1xMpNY4AGuljPTNjQve6A==} + '@vitest/utils@3.2.3': + resolution: {integrity: sha512-4zFBCU5Pf+4Z6v+rwnZ1HU1yzOKKvDkMXZrymE2PBlbjKJRlrOxbvpfPSvJTGRIwGoahaOGvp+kbCoxifhzJ1Q==} accepts@2.0.0: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} @@ -2089,9 +2135,6 @@ packages: resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} engines: {node: '>= 0.4'} - es-module-lexer@1.6.0: - resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} - es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} @@ -2352,6 +2395,11 @@ packages: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -2684,6 +2732,9 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} hasBin: true @@ -2873,6 +2924,10 @@ packages: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -3063,6 +3118,16 @@ packages: pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + playwright-core@1.52.0: + resolution: {integrity: sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.52.0: + resolution: {integrity: sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==} + engines: {node: '>=18'} + hasBin: true + plimit-lit@1.6.1: resolution: {integrity: sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA==} engines: {node: '>=12'} @@ -3371,6 +3436,10 @@ packages: simple-swizzle@0.2.2: resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + sirv@3.0.1: + resolution: {integrity: sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==} + engines: {node: '>=18'} + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -3463,6 +3532,9 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + strip-literal@3.0.0: + resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} + sucrase@3.35.0: resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} engines: {node: '>=16 || 14 >=14.17'} @@ -3549,6 +3621,10 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + tough-cookie@5.1.0: resolution: {integrity: sha512-rvZUv+7MoBYTiDmFPBrhL7Ujx9Sk+q9wwm22x8c8T5IJaR+Wsyc7TNxbVxo84kZoRJZZMazowFLqpankBEQrGg==} engines: {node: '>=16'} @@ -3717,13 +3793,8 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - vite-node@3.0.4: - resolution: {integrity: sha512-7JZKEzcYV2Nx3u6rlvN8qdo3QV7Fxyt6hx+CCKz9fbWxdX5IvUOmTWEAxMrWxaiSf7CKGLJQ5rFu8prb/jBjOA==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - - vite-node@3.2.2: - resolution: {integrity: sha512-Xj/jovjZvDXOq2FgLXu8NsY4uHUMWtzVmMC2LkCu9HWdr9Qu1Is5sanX3Z4jOFKdohfaWDnEJWp9pRP0vVpAcA==} + vite-node@3.2.3: + resolution: {integrity: sha512-gc8aAifGuDIpZHrPjuHyP4dpQmYXqWw7D1GmDnWeNWP654UEXzVfQ5IHPSK5HaHkwB/+p1atpYpSdw/2kOv8iQ==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true @@ -3767,16 +3838,16 @@ packages: yaml: optional: true - vitest@3.2.2: - resolution: {integrity: sha512-fyNn/Rp016Bt5qvY0OQvIUCwW2vnaEBLxP42PmKbNIoasSYjML+8xyeADOPvBe+Xfl/ubIw4og7Lt9jflRsCNw==} + vitest@3.2.3: + resolution: {integrity: sha512-E6U2ZFXe3N/t4f5BwUaVCKRLHqUpk1CBWeMh78UT4VaTPH/2dyvH6ALl29JTovEPu9dVKr/K/J4PkXgrMbw4Ww==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@types/debug': ^4.1.12 '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.2.2 - '@vitest/ui': 3.2.2 + '@vitest/browser': 3.2.3 + '@vitest/ui': 3.2.3 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -3877,6 +3948,18 @@ packages: utf-8-validate: optional: true + ws@8.18.2: + resolution: {integrity: sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + xml-name-validator@5.0.0: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} engines: {node: '>=18'} @@ -4177,12 +4260,12 @@ snapshots: human-id: 4.1.1 prettier: 2.8.8 - '@chromatic-com/storybook@3.2.4(react@18.3.1)(storybook@8.5.2(prettier@3.4.2))': + '@chromatic-com/storybook@3.2.4(react@19.0.0)(storybook@8.5.2(prettier@3.4.2))': dependencies: chromatic: 11.25.2 filesize: 10.1.6 jsonfile: 6.1.0 - react-confetti: 6.2.2(react@18.3.1) + react-confetti: 6.2.2(react@19.0.0) storybook: 8.5.2(prettier@3.4.2) strip-ansi: 7.1.0 transitivePeerDependencies: @@ -4493,6 +4576,8 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@polka/url@1.0.0-next.29': {} + '@rollup/pluginutils@5.1.4(rollup@4.40.2)': dependencies: '@types/estree': 1.0.6 @@ -4717,6 +4802,16 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) + '@storybook/blocks@8.5.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.2(prettier@3.4.2))': + dependencies: + '@storybook/csf': 0.1.12 + '@storybook/icons': 1.3.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + storybook: 8.5.2(prettier@3.4.2) + ts-dedent: 2.2.0 + optionalDependencies: + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + '@storybook/builder-vite@8.5.2(storybook@8.5.2(prettier@3.4.2))(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2))': dependencies: '@storybook/csf-plugin': 8.5.2(storybook@8.5.2(prettier@3.4.2)) @@ -4769,6 +4864,11 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) + '@storybook/icons@1.3.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + '@storybook/instrumenter@8.5.2(storybook@8.5.2(prettier@3.4.2))': dependencies: '@storybook/global': 5.0.0 @@ -4789,17 +4889,23 @@ snapshots: react-dom: 18.3.1(react@18.3.1) storybook: 8.5.2(prettier@3.4.2) - '@storybook/react-vite@8.5.2(@storybook/test@8.5.2(storybook@8.5.2(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.40.2)(storybook@8.5.2(prettier@3.4.2))(typescript@5.6.3)(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2))': + '@storybook/react-dom-shim@8.5.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.2(prettier@3.4.2))': + dependencies: + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + storybook: 8.5.2(prettier@3.4.2) + + '@storybook/react-vite@8.5.2(@storybook/test@8.5.2(storybook@8.5.2(prettier@3.4.2)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@4.40.2)(storybook@8.5.2(prettier@3.4.2))(typescript@5.6.3)(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2))': dependencies: '@joshwooding/vite-plugin-react-docgen-typescript': 0.4.2(typescript@5.6.3)(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2)) '@rollup/pluginutils': 5.1.4(rollup@4.40.2) '@storybook/builder-vite': 8.5.2(storybook@8.5.2(prettier@3.4.2))(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2)) - '@storybook/react': 8.5.2(@storybook/test@8.5.2(storybook@8.5.2(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.5.2(prettier@3.4.2))(typescript@5.6.3) + '@storybook/react': 8.5.2(@storybook/test@8.5.2(storybook@8.5.2(prettier@3.4.2)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.2(prettier@3.4.2))(typescript@5.6.3) find-up: 5.0.0 magic-string: 0.30.17 - react: 18.3.1 + react: 19.0.0 react-docgen: 7.1.1 - react-dom: 18.3.1(react@18.3.1) + react-dom: 19.0.0(react@19.0.0) resolve: 1.22.10 storybook: 8.5.2(prettier@3.4.2) tsconfig-paths: 4.2.0 @@ -4811,16 +4917,16 @@ snapshots: - supports-color - typescript - '@storybook/react@8.5.2(@storybook/test@8.5.2(storybook@8.5.2(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.5.2(prettier@3.4.2))(typescript@5.6.3)': + '@storybook/react@8.5.2(@storybook/test@8.5.2(storybook@8.5.2(prettier@3.4.2)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.2(prettier@3.4.2))(typescript@5.6.3)': dependencies: '@storybook/components': 8.5.2(storybook@8.5.2(prettier@3.4.2)) '@storybook/global': 5.0.0 '@storybook/manager-api': 8.5.2(storybook@8.5.2(prettier@3.4.2)) '@storybook/preview-api': 8.5.2(storybook@8.5.2(prettier@3.4.2)) - '@storybook/react-dom-shim': 8.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.5.2(prettier@3.4.2)) + '@storybook/react-dom-shim': 8.5.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.2(prettier@3.4.2)) '@storybook/theming': 8.5.2(storybook@8.5.2(prettier@3.4.2)) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) storybook: 8.5.2(prettier@3.4.2) optionalDependencies: '@storybook/test': 8.5.2(storybook@8.5.2(prettier@3.4.2)) @@ -4871,17 +4977,6 @@ snapshots: '@tanstack/query-core': 5.66.0 react: 19.0.0 - '@tanstack/react-router@1.109.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@tanstack/history': 1.99.13 - '@tanstack/react-store': 0.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@tanstack/router-core': 1.108.0 - jsesc: 3.1.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - tiny-invariant: 1.3.3 - tiny-warning: 1.0.3 - '@tanstack/react-router@1.109.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@tanstack/history': 1.99.13 @@ -4893,13 +4988,6 @@ snapshots: tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - '@tanstack/react-store@0.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@tanstack/store': 0.7.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - use-sync-external-store: 1.4.0(react@18.3.1) - '@tanstack/react-store@0.7.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@tanstack/store': 0.7.0 @@ -4912,26 +5000,26 @@ snapshots: '@tanstack/history': 1.99.13 '@tanstack/store': 0.7.0 - '@tanstack/router-devtools@1.99.0(@tanstack/react-router@1.109.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(csstype@3.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@tanstack/router-devtools@1.99.0(@tanstack/react-router@1.109.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@tanstack/react-router': 1.109.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/react-router': 1.109.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) clsx: 2.1.1 goober: 2.1.16(csstype@3.1.3) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) transitivePeerDependencies: - csstype - '@tanstack/router-generator@1.99.0(@tanstack/react-router@1.109.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': + '@tanstack/router-generator@1.99.0(@tanstack/react-router@1.109.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))': dependencies: '@tanstack/virtual-file-routes': 1.99.0 prettier: 3.4.2 tsx: 4.19.2 zod: 3.24.1 optionalDependencies: - '@tanstack/react-router': 1.109.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/react-router': 1.109.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tanstack/router-plugin@1.99.3(@tanstack/react-router@1.109.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2))': + '@tanstack/router-plugin@1.99.3(@tanstack/react-router@1.109.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2))': dependencies: '@babel/core': 7.26.7 '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.7) @@ -4939,7 +5027,7 @@ snapshots: '@babel/template': 7.25.9 '@babel/traverse': 7.26.7 '@babel/types': 7.26.7 - '@tanstack/router-generator': 1.99.0(@tanstack/react-router@1.109.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + '@tanstack/router-generator': 1.99.0(@tanstack/react-router@1.109.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)) '@tanstack/router-utils': 1.99.3 '@tanstack/virtual-file-routes': 1.99.0 '@types/babel__core': 7.20.5 @@ -4987,12 +5075,22 @@ snapshots: lodash: 4.17.21 redent: 3.0.0 - '@testing-library/react@16.2.0(@testing-library/dom@10.4.0)(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@testing-library/jest-dom@6.6.3': + dependencies: + '@adobe/css-tools': 4.4.1 + aria-query: 5.3.2 + chalk: 3.0.0 + css.escape: 1.5.1 + dom-accessibility-api: 0.6.3 + lodash: 4.17.21 + redent: 3.0.0 + + '@testing-library/react@16.3.0(@testing-library/dom@10.4.0)(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@babel/runtime': 7.26.7 '@testing-library/dom': 10.4.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) optionalDependencies: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) @@ -5001,6 +5099,10 @@ snapshots: dependencies: '@testing-library/dom': 10.4.0 + '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.0)': + dependencies: + '@testing-library/dom': 10.4.0 + '@types/aria-query@5.0.4': {} '@types/babel__core@7.20.5': @@ -5188,12 +5290,18 @@ snapshots: transitivePeerDependencies: - supports-color - '@vanilla-extract/compiler@0.1.1(@types/node@22.15.21)(tsx@4.19.2)': + '@vanilla-extract/babel-plugin-debug-ids@1.2.1': dependencies: - '@vanilla-extract/css': 1.17.2 - '@vanilla-extract/integration': 8.0.0 + '@babel/core': 7.26.7 + transitivePeerDependencies: + - supports-color + + '@vanilla-extract/compiler@0.1.3(@types/node@22.15.21)(tsx@4.19.2)': + dependencies: + '@vanilla-extract/css': 1.17.3 + '@vanilla-extract/integration': 8.0.3 vite: 6.0.11(@types/node@22.15.21)(tsx@4.19.2) - vite-node: 3.0.4(@types/node@22.15.21)(tsx@4.19.2) + vite-node: 3.2.3(@types/node@22.15.21)(tsx@4.19.2) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -5243,6 +5351,23 @@ snapshots: transitivePeerDependencies: - babel-plugin-macros + '@vanilla-extract/css@1.17.3': + dependencies: + '@emotion/hash': 0.9.2 + '@vanilla-extract/private': 1.0.8 + css-what: 6.1.0 + cssesc: 3.0.0 + csstype: 3.1.3 + dedent: 1.5.3 + deep-object-diff: 1.1.9 + deepmerge: 4.3.1 + lru-cache: 10.4.3 + media-query-parser: 2.0.2 + modern-ahocorasick: 1.1.0 + picocolors: 1.1.1 + transitivePeerDependencies: + - babel-plugin-macros + '@vanilla-extract/dynamic@2.1.2': dependencies: '@vanilla-extract/private': 1.0.6 @@ -5256,7 +5381,7 @@ snapshots: - babel-plugin-macros - supports-color - '@vanilla-extract/integration@8.0.0': + '@vanilla-extract/integration@8.0.2': dependencies: '@babel/core': 7.26.7 '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.7) @@ -5272,12 +5397,12 @@ snapshots: - babel-plugin-macros - supports-color - '@vanilla-extract/integration@8.0.2': + '@vanilla-extract/integration@8.0.3': dependencies: '@babel/core': 7.26.7 '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.7) - '@vanilla-extract/babel-plugin-debug-ids': 1.2.0 - '@vanilla-extract/css': 1.17.2 + '@vanilla-extract/babel-plugin-debug-ids': 1.2.1 + '@vanilla-extract/css': 1.17.3 dedent: 1.5.3 esbuild: 0.24.2 eval: 0.1.8 @@ -5292,6 +5417,8 @@ snapshots: '@vanilla-extract/private@1.0.7': {} + '@vanilla-extract/private@1.0.8': {} + '@vanilla-extract/recipes@0.5.5(@vanilla-extract/css@1.17.1)': dependencies: '@vanilla-extract/css': 1.17.1 @@ -5302,8 +5429,8 @@ snapshots: '@vanilla-extract/vite-plugin@4.0.20(@types/node@22.15.21)(tsx@4.19.2)(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2))': dependencies: - '@vanilla-extract/compiler': 0.1.1(@types/node@22.15.21)(tsx@4.19.2) - '@vanilla-extract/integration': 8.0.0 + '@vanilla-extract/compiler': 0.1.3(@types/node@22.15.21)(tsx@4.19.2) + '@vanilla-extract/integration': 8.0.3 vite: 6.0.11(@types/node@22.15.21)(tsx@4.19.2) transitivePeerDependencies: - '@types/node' @@ -5331,6 +5458,25 @@ snapshots: transitivePeerDependencies: - supports-color + '@vitest/browser@3.2.3(playwright@1.52.0)(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2))(vitest@3.2.3)': + dependencies: + '@testing-library/dom': 10.4.0 + '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.0) + '@vitest/mocker': 3.2.3(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2)) + '@vitest/utils': 3.2.3 + magic-string: 0.30.17 + sirv: 3.0.1 + tinyrainbow: 2.0.0 + vitest: 3.2.3(@types/node@22.15.21)(@vitest/browser@3.2.3)(jsdom@26.0.0)(tsx@4.19.2) + ws: 8.18.2 + optionalDependencies: + playwright: 1.52.0 + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + '@vitest/expect@2.0.5': dependencies: '@vitest/spy': 2.0.5 @@ -5338,17 +5484,17 @@ snapshots: chai: 5.1.2 tinyrainbow: 1.2.0 - '@vitest/expect@3.2.2': + '@vitest/expect@3.2.3': dependencies: '@types/chai': 5.2.2 - '@vitest/spy': 3.2.2 - '@vitest/utils': 3.2.2 + '@vitest/spy': 3.2.3 + '@vitest/utils': 3.2.3 chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.2(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2))': + '@vitest/mocker@3.2.3(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2))': dependencies: - '@vitest/spy': 3.2.2 + '@vitest/spy': 3.2.3 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: @@ -5362,18 +5508,19 @@ snapshots: dependencies: tinyrainbow: 1.2.0 - '@vitest/pretty-format@3.2.2': + '@vitest/pretty-format@3.2.3': dependencies: tinyrainbow: 2.0.0 - '@vitest/runner@3.2.2': + '@vitest/runner@3.2.3': dependencies: - '@vitest/utils': 3.2.2 + '@vitest/utils': 3.2.3 pathe: 2.0.3 + strip-literal: 3.0.0 - '@vitest/snapshot@3.2.2': + '@vitest/snapshot@3.2.3': dependencies: - '@vitest/pretty-format': 3.2.2 + '@vitest/pretty-format': 3.2.3 magic-string: 0.30.17 pathe: 2.0.3 @@ -5381,7 +5528,7 @@ snapshots: dependencies: tinyspy: 3.0.2 - '@vitest/spy@3.2.2': + '@vitest/spy@3.2.3': dependencies: tinyspy: 4.0.3 @@ -5398,9 +5545,9 @@ snapshots: loupe: 3.1.3 tinyrainbow: 1.2.0 - '@vitest/utils@3.2.2': + '@vitest/utils@3.2.3': dependencies: - '@vitest/pretty-format': 3.2.2 + '@vitest/pretty-format': 3.2.3 loupe: 3.1.3 tinyrainbow: 2.0.0 @@ -5934,8 +6081,6 @@ snapshots: iterator.prototype: 1.1.5 safe-array-concat: 1.1.3 - es-module-lexer@1.6.0: {} - es-module-lexer@1.7.0: {} es-object-atoms@1.1.1: @@ -6305,6 +6450,9 @@ snapshots: jsonfile: 4.0.0 universalify: 0.1.2 + fsevents@2.3.2: + optional: true + fsevents@2.3.3: optional: true @@ -6641,6 +6789,8 @@ snapshots: js-tokens@4.0.0: {} + js-tokens@9.0.1: {} + js-yaml@3.14.1: dependencies: argparse: 1.0.10 @@ -6824,6 +6974,8 @@ snapshots: mri@1.2.0: {} + mrmime@2.0.1: {} + ms@2.1.3: {} mylas@2.1.13: {} @@ -6997,6 +7149,14 @@ snapshots: mlly: 1.7.4 pathe: 2.0.2 + playwright-core@1.52.0: {} + + playwright@1.52.0: + dependencies: + playwright-core: 1.52.0 + optionalDependencies: + fsevents: 2.3.2 + plimit-lit@1.6.1: dependencies: queue-lit: 1.5.2 @@ -7066,9 +7226,9 @@ snapshots: iconv-lite: 0.6.3 unpipe: 1.0.0 - react-confetti@6.2.2(react@18.3.1): + react-confetti@6.2.2(react@19.0.0): dependencies: - react: 18.3.1 + react: 19.0.0 tween-functions: 1.2.0 react-docgen-typescript@2.2.2(typescript@5.6.3): @@ -7404,6 +7564,12 @@ snapshots: dependencies: is-arrayish: 0.3.2 + sirv@3.0.1: + dependencies: + '@polka/url': 1.0.0-next.29 + mrmime: 2.0.1 + totalist: 3.0.1 + slash@3.0.0: {} source-map-js@1.2.1: {} @@ -7513,6 +7679,10 @@ snapshots: strip-json-comments@3.1.1: {} + strip-literal@3.0.0: + dependencies: + js-tokens: 9.0.1 + sucrase@3.35.0: dependencies: '@jridgewell/gen-mapping': 0.3.8 @@ -7585,6 +7755,8 @@ snapshots: toidentifier@1.0.1: {} + totalist@3.0.1: {} + tough-cookie@5.1.0: dependencies: tldts: 6.1.76 @@ -7764,10 +7936,6 @@ snapshots: dependencies: punycode: 2.3.1 - use-sync-external-store@1.4.0(react@18.3.1): - dependencies: - react: 18.3.1 - use-sync-external-store@1.4.0(react@19.0.0): dependencies: react: 19.0.0 @@ -7784,28 +7952,7 @@ snapshots: vary@1.1.2: {} - vite-node@3.0.4(@types/node@22.15.21)(tsx@4.19.2): - dependencies: - cac: 6.7.14 - debug: 4.4.0 - es-module-lexer: 1.6.0 - pathe: 2.0.2 - vite: 6.0.11(@types/node@22.15.21)(tsx@4.19.2) - transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - vite-node@3.2.2(@types/node@22.15.21)(tsx@4.19.2): + vite-node@3.2.3(@types/node@22.15.21)(tsx@4.19.2): dependencies: cac: 6.7.14 debug: 4.4.1 @@ -7836,16 +7983,16 @@ snapshots: fsevents: 2.3.3 tsx: 4.19.2 - vitest@3.2.2(@types/node@22.15.21)(jsdom@26.0.0)(tsx@4.19.2): + vitest@3.2.3(@types/node@22.15.21)(@vitest/browser@3.2.3)(jsdom@26.0.0)(tsx@4.19.2): dependencies: '@types/chai': 5.2.2 - '@vitest/expect': 3.2.2 - '@vitest/mocker': 3.2.2(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2)) - '@vitest/pretty-format': 3.2.2 - '@vitest/runner': 3.2.2 - '@vitest/snapshot': 3.2.2 - '@vitest/spy': 3.2.2 - '@vitest/utils': 3.2.2 + '@vitest/expect': 3.2.3 + '@vitest/mocker': 3.2.3(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2)) + '@vitest/pretty-format': 3.2.3 + '@vitest/runner': 3.2.3 + '@vitest/snapshot': 3.2.3 + '@vitest/spy': 3.2.3 + '@vitest/utils': 3.2.3 chai: 5.2.0 debug: 4.4.1 expect-type: 1.2.1 @@ -7859,10 +8006,11 @@ snapshots: tinypool: 1.1.0 tinyrainbow: 2.0.0 vite: 6.0.11(@types/node@22.15.21)(tsx@4.19.2) - vite-node: 3.2.2(@types/node@22.15.21)(tsx@4.19.2) + vite-node: 3.2.3(@types/node@22.15.21)(tsx@4.19.2) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.15.21 + '@vitest/browser': 3.2.3(playwright@1.52.0)(vite@6.0.11(@types/node@22.15.21)(tsx@4.19.2))(vitest@3.2.3) jsdom: 26.0.0 transitivePeerDependencies: - jiti @@ -7972,6 +8120,8 @@ snapshots: ws@8.18.0: {} + ws@8.18.2: {} + xml-name-validator@5.0.0: {} xmlchars@2.2.0: {}