diff --git a/docs/framework/react/reference/useTimer.md b/docs/framework/react/reference/useTimer.md new file mode 100644 index 00000000..d78becbb --- /dev/null +++ b/docs/framework/react/reference/useTimer.md @@ -0,0 +1,76 @@ +--- +title: Use Timer +id: useTimer +--- + +### useTimer + +```ts +export function useTimer({ + initialTime: number, + onFinished?: () => void, + timeZone?: Temporal.TimeZoneLike, + onStart?: () => void, + onStop?: () => void, + onReset?: () => void, +}): TimerApi; +``` + +`useTimer` is a hook that provides a comprehensive set of functionalities for managing a countdown timer, including starting, stopping, and resetting the timer. It also includes the ability to trigger a callback when the timer finishes, starts, stops, or resets. + + +#### Parameters + +- `initialTime: number` +The initial time for the timer, specified in seconds. +- `timeZone?: Temporal.TimeZoneLike` +Optional time zone specification for the timer. Defaults to the system's time zone. +- `onFinished?: () => void` +An optional callback function that is called when the timer finishes. +- `onStart?: () => void` +Optional callback function that is called when the timer starts. +- `onStop?: () => void` +Optional callback function that is called when the timer stops. +- `onReset?: () => void` +Optional callback function that is called when the timer resets. + + +#### Returns + +- `remainingTime: number` +This value represents the remaining time of the timer in seconds. +- `isRunning: boolean` +This value represents whether the timer is currently running. +- `start: () => void` +This function starts the timer. +- `stop: () => void` +This function stops the timer. +- `reset: () => void` +This function resets the timer to the initial time. + + +#### Example Usage + +```ts +import { useTimer } from '@tanstack/react-time'; + +const TimerComponent = () => { + const { remainingTime, isRunning, start, stop, reset } = useTimer({ + initialTime: 60, + onFinished: () => { + console.log('Timer finished!'); + }, + timeZone: 'America/New_York', + }); + + return ( +
+
Remaining Time: {remainingTime}
+
Is Running: {isRunning ? 'Yes' : 'No'}
+ + + +
+ ); +}; +``` diff --git a/docs/reference/timer.md b/docs/reference/timer.md new file mode 100644 index 00000000..3002222b --- /dev/null +++ b/docs/reference/timer.md @@ -0,0 +1,58 @@ +--- +title: Timer +id: timer +--- + +# Timer + +```ts +export class Timer extends TimeCore implements TimerActions { + constructor(options: TimerOptions); +} +``` + +The Timer class provides functionality for managing a countdown timer, including starting, stopping, and resetting the timer. It also includes the ability to trigger a callback when the timer finishes. + + +## Parameters + +- `initialTime: number` +The initial time for the timer, specified in seconds. +- `onFinished?: () => void` +An optional callback function that is called when the timer finishes. +- `timeZone?: Temporal.TimeZoneLike` +Optional time zone specification for the timer. Defaults to the system's time zone. +- `onStart?: () => void` +Optional callback function that is called when the timer starts. +- `onStop?: () => void` +Optional callback function that is called when the timer stops. +- `onReset?: () => void` +Optional callback function that is called when the timer resets. + + +## Methods + +- `start(): void` +Starts the timer. +- `stop(): void` +Stops the timer. +- `reset(): void` +Resets the timer to the initial time. + + +## Example Usage + +```ts +import { Timer } from '@tanstack/time'; + +const timer = new Timer({ + initialTime: 60, // 60 seconds + onFinished: () => { + console.log('Timer finished!'); + }, + timeZone: 'America/New_York', +}); + +// Start the timer +timer.start(); +``` \ No newline at end of file diff --git a/packages/react-time/package.json b/packages/react-time/package.json index c3f9d136..32a3f06b 100644 --- a/packages/react-time/package.json +++ b/packages/react-time/package.json @@ -62,6 +62,7 @@ "react-dom": "^17.0.0 || ^18.0.0" }, "dependencies": { + "@tanstack/react-store": "^0.5.2", "@tanstack/time": "workspace:*", "use-sync-external-store": "^1.2.0" }, diff --git a/packages/react-time/src/tests/useTimer.test.ts b/packages/react-time/src/tests/useTimer.test.ts new file mode 100644 index 00000000..e8649f90 --- /dev/null +++ b/packages/react-time/src/tests/useTimer.test.ts @@ -0,0 +1,99 @@ +import { beforeEach, describe, expect, test, vi } from 'vitest' +import { act, renderHook } from '@testing-library/react' +import { useTimer } from '../useTimer' + +describe('useTimer', () => { + beforeEach(() => { + vi.useFakeTimers() + }) + + test('should start the timer', () => { + const { result } = renderHook(() => useTimer({ initialTime: 5 })) + act(() => { + result.current.start() + }) + expect(result.current.isRunning).toBe(true) + }) + + test('should stop the timer', () => { + const { result } = renderHook(() => useTimer({ initialTime: 5 })) + act(() => { + result.current.start() + }) + act(() => { + result.current.stop() + }) + expect(result.current.isRunning).toBe(false) + }) + + test('should reset the timer', () => { + const { result } = renderHook(() => useTimer({ initialTime: 5 })) + act(() => { + result.current.start() + }) + act(() => { + result.current.stop() + }) + expect(result.current.isRunning).toBe(false) + expect(result.current.remainingTime).toBe(5) + }) + + test('should update the remaining time', () => { + const { result } = renderHook(() => useTimer({ initialTime: 5 })) + act(() => { + result.current.start() + }) + act(() => { + vi.advanceTimersByTime(1000) + }) + expect(result.current.remainingTime).toBe(4) + }) + + test('should call onStart callback', () => { + const onStart = vi.fn() + const { result } = renderHook(() => useTimer({ initialTime: 5, onStart })) + act(() => { + result.current.start() + }) + expect(onStart).toHaveBeenCalledTimes(1) + }) + + test('should call onStop callback', () => { + const onStop = vi.fn() + const { result } = renderHook(() => useTimer({ initialTime: 5, onStop })) + act(() => { + result.current.start() + }) + act(() => { + result.current.stop() + }) + expect(onStop).toHaveBeenCalledTimes(1) + }) + + test('should call onReset callback', () => { + const onReset = vi.fn() + const { result } = renderHook(() => useTimer({ initialTime: 5, onReset })) + act(() => { + result.current.start() + }) + act(() => { + result.current.stop() + }) + act(() => { + result.current.reset() + }) + expect(onReset).toHaveBeenCalledTimes(1) + }) + + test('should call onFinish callback', () => { + const onFinish = vi.fn() + const { result } = renderHook(() => useTimer({ initialTime: 5, onFinish })) + act(() => { + result.current.start() + }) + act(() => { + vi.advanceTimersByTime(5000) + }) + expect(onFinish).toHaveBeenCalledTimes(1) + }) +}) diff --git a/packages/react-time/src/useTimer.ts b/packages/react-time/src/useTimer.ts new file mode 100644 index 00000000..71ba97c8 --- /dev/null +++ b/packages/react-time/src/useTimer.ts @@ -0,0 +1,22 @@ +import { useStore } from '@tanstack/react-store' +import { Timer, type TimerApi, type TimerOptions } from '@tanstack/time' +import { useCallback, useState } from 'react' + +export const useTimer = (options: TimerOptions): TimerApi => { + const [timer] = useState(() => new Timer(options)) + const state = useStore(timer.store) + + const start = useCallback(() => { + timer.start() + }, [timer]) + + const stop = useCallback(() => { + timer.stop() + }, [timer]) + + const reset = useCallback(() => { + timer.reset() + }, [timer]) + + return { ...state, start, stop, reset } +} diff --git a/packages/time/package.json b/packages/time/package.json index 081903be..44f58127 100644 --- a/packages/time/package.json +++ b/packages/time/package.json @@ -55,5 +55,12 @@ "files": [ "dist", "src" - ] + ], + "dependencies": { + "@js-temporal/polyfill": "^0.4.4", + "@tanstack/store": "^0.4.1" + }, + "devDependencies": { + "csstype": "^3.1.3" + } } diff --git a/packages/time/src/core/index.ts b/packages/time/src/core/index.ts new file mode 100644 index 00000000..46213912 --- /dev/null +++ b/packages/time/src/core/index.ts @@ -0,0 +1 @@ +export * from './timer' diff --git a/packages/time/src/core/time.ts b/packages/time/src/core/time.ts new file mode 100644 index 00000000..75ee64bb --- /dev/null +++ b/packages/time/src/core/time.ts @@ -0,0 +1,60 @@ +import { Temporal } from '@js-temporal/polyfill' +import { Store } from '@tanstack/store' +import { getDefaultTimeZone } from '../utils/dateDefaults' + +export interface TimeCoreOptions { + /** + * The time zone to use for the current time. + * @default Intl.DateTimeFormat().resolvedOptions().timeZone + */ + timeZone?: Temporal.TimeZoneLike +} + +export interface TimeState { + /** + * The current time. + * @default Temporal.Now.zonedDateTimeISO() + * @readonly + * @type Temporal.ZonedDateTime + */ + currentTime: Temporal.ZonedDateTime +} + +export abstract class TimeCore { + store: Store + interval: NodeJS.Timeout | null = null + timeZone: Temporal.TimeZoneLike + + constructor(options: TimeCoreOptions = {}) { + const defaultTimeZone = getDefaultTimeZone() + this.timeZone = options.timeZone || defaultTimeZone + this.store = new Store({ + currentTime: Temporal.Now.zonedDateTimeISO(this.timeZone), + } as TState) + this.updateCurrentTime() + } + + protected updateCurrentTime() { + this.store.setState((prev) => ({ + ...prev, + currentTime: Temporal.Now.zonedDateTimeISO(this.timeZone), + })) + } + + startUpdatingTime(intervalMs: number = 1000) { + if (!this.interval) { + this.interval = setInterval(() => this.updateCurrentTime(), intervalMs) + } + } + + stopUpdatingTime() { + if (this.interval) { + clearInterval(this.interval) + this.interval = null + } + } + + getCurrentTime(): Temporal.ZonedDateTime { + return this.store.state.currentTime + } +} diff --git a/packages/time/src/core/timer.ts b/packages/time/src/core/timer.ts new file mode 100644 index 00000000..b1f72af7 --- /dev/null +++ b/packages/time/src/core/timer.ts @@ -0,0 +1,119 @@ +import { Store } from '@tanstack/store' +import { TimeCore } from './time' +import type { TimeCoreOptions, TimeState } from './time' + +export interface TimerOptions extends TimeCoreOptions { + /** + * The initial time for the timer. + */ + initialTime: number + /** + * A callback that is called when the timer finishes. + */ + onFinish?: () => void + /** + * A callback that is called when the timer finishes. + */ + onStart?: () => void + /** + * A callback that is called when the timer stops. + */ + onStop?: () => void + /** + * A callback that is called when the timer resets. + */ + onReset?: () => void +} + +interface TimerState extends TimeState { + /** + * The remaining time for the timer. + * @default 0 + * @readonly + * @type number + */ + remainingTime: number + /** + * Whether the timer is running. + * @default false + * @readonly + * @type boolean + */ + isRunning: boolean +} + +export interface TimerActions { + /** + * Start the timer. + */ + start: () => void + /** + * Stop the timer. + */ + stop: () => void + /** + * Reset the timer. + */ + reset: () => void +} + +export interface TimerApi extends TimerActions, TimerState {} + +export class Timer extends TimeCore implements TimerActions { + private options: TimerOptions + + constructor(options: TimerOptions) { + super(options) + this.options = options + this.store = new Store({ + remainingTime: options.initialTime, + isRunning: false, + currentTime: this.store.state.currentTime, + }) + } + + start() { + if (!this.store.state.isRunning) { + this.store.setState((prev) => ({ + ...prev, + isRunning: true, + })) + this.startUpdatingTime(1000) + this.options.onStart?.() + } + } + + stop() { + if (this.store.state.isRunning) { + this.store.setState((prev) => ({ + ...prev, + isRunning: false, + })) + this.stopUpdatingTime() + this.options.onStop?.() + } + } + + reset() { + this.stop() + this.store.setState((prev) => ({ + ...prev, + remainingTime: this.options.initialTime, + })) + this.options.onReset?.() + } + + protected updateCurrentTime() { + super.updateCurrentTime() + if (this.store.state.isRunning && this.store.state.remainingTime > 0) { + this.store.setState((prev) => ({ + ...prev, + remainingTime: prev.remainingTime - 1, + })) + if (this.store.state.remainingTime <= 0) { + this.stop() + this.options.onFinish?.() + } + } + } +} diff --git a/packages/time/src/index.ts b/packages/time/src/index.ts index 12981a25..3e0cfa01 100644 --- a/packages/time/src/index.ts +++ b/packages/time/src/index.ts @@ -1,4 +1,5 @@ /** * TanStack Time */ -export * from './utils/parse'; \ No newline at end of file +export * from './utils/parse' +export * from './core' diff --git a/packages/time/src/tests/isValidDate.test.ts b/packages/time/src/tests/isValidDate.test.ts index 57a35567..01afdc69 100644 --- a/packages/time/src/tests/isValidDate.test.ts +++ b/packages/time/src/tests/isValidDate.test.ts @@ -4,7 +4,7 @@ import {isValidDate} from '../utils/isValidDate'; describe('isValidDate', () => { test('should return true for a valid date', () => { expect(isValidDate(new Date())).toBe(true); - }); + }) test('should return false for an invalid date', () => { expect(isValidDate(new Date("invalid"))).toBe(false); @@ -13,4 +13,4 @@ describe('isValidDate', () => { test("should return false for null", () => { expect(isValidDate(null)).toBe(false); }); -}); \ No newline at end of file +}); diff --git a/packages/time/src/tests/time.test.ts b/packages/time/src/tests/time.test.ts new file mode 100644 index 00000000..29135d75 --- /dev/null +++ b/packages/time/src/tests/time.test.ts @@ -0,0 +1,64 @@ +import { Temporal } from '@js-temporal/polyfill' +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' +import { TimeCore } from '../core/time' + + +export class TestTimeCore extends TimeCore { + getCurrentTime(): Temporal.ZonedDateTime { + return super.getCurrentTime() + } + + startUpdatingTime(intervalMs: number = 1000) { + super.startUpdatingTime(intervalMs) + } + + stopUpdatingTime() { + super.stopUpdatingTime() + } +} + +describe('TimeCore', () => { +beforeEach(() => { + vi.useFakeTimers() + const mockNow = Temporal.PlainDateTime.from({ year: 2024, month: 1, day: 1, hour: 0, minute: 0, second: 0 }) + vi.setSystemTime(mockNow.toZonedDateTime('UTC').epochMilliseconds) + }) + + afterEach(() => { + vi.useRealTimers() + }) + + test('should initialize with the current time in the default time zone', () => { + const timeCore = new TestTimeCore() + const currentTime = Temporal.Now.zonedDateTimeISO() + expect(timeCore.getCurrentTime().toString()).toBe(currentTime.toString()) + }) + + test('should initialize with the current time in the specified time zone', () => { + const timeZone = 'America/New_York' + const timeCore = new TestTimeCore({ timeZone }) + const currentTime = Temporal.Now.zonedDateTimeISO(timeZone) + expect(timeCore.getCurrentTime().toString()).toBe(currentTime.toString()) + }) + + test('should start updating the current time', () => { + const timeCore = new TestTimeCore() + timeCore.startUpdatingTime() + vi.advanceTimersByTime(1000) + const currentTime = Temporal.Now.zonedDateTimeISO() + expect(timeCore.getCurrentTime().epochMilliseconds).toBe(currentTime.epochMilliseconds) + }) + + test('should stop updating the current time', () => { + const timeCore = new TestTimeCore() + timeCore.startUpdatingTime() + + vi.advanceTimersByTime(1000) + timeCore.stopUpdatingTime() + const stoppedTime = timeCore.getCurrentTime() + + vi.advanceTimersByTime(1000) + const timeAfterStop = timeCore.getCurrentTime() + expect(timeAfterStop.epochMilliseconds).toBe(stoppedTime.epochMilliseconds) + }) +}) diff --git a/packages/time/src/tests/timer.test.ts b/packages/time/src/tests/timer.test.ts new file mode 100644 index 00000000..4663c4a5 --- /dev/null +++ b/packages/time/src/tests/timer.test.ts @@ -0,0 +1,67 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { Timer } from '../core/timer'; +import type { TimerOptions } from '../core/timer'; + +describe('Timer', () => { + let timer: Timer; + const onFinish = vi.fn(); + const onStart = vi.fn(); + const onStop = vi.fn(); + const onReset = vi.fn(); + const initialTime = 5; + + beforeEach(() => { + vi.useFakeTimers(); + + const options: TimerOptions = { + initialTime, + onFinish, + onStart, + onStop, + onReset, + timeZone: 'America/New_York', + }; + + timer = new Timer(options); + }); + + it('should initialize with the correct remaining time and isRunning state', () => { + expect(timer.store.state.remainingTime).toBe(initialTime); + expect(timer.store.state.isRunning).toBe(false); + }); + + it('should start the timer', () => { + timer.start(); + expect(timer.store.state.isRunning).toBe(true); + expect(onStart).toHaveBeenCalled(); + }); + + it('should stop the timer', () => { + timer.start(); + timer.stop(); + expect(timer.store.state.isRunning).toBe(false); + expect(onStop).toHaveBeenCalled(); + }); + + it('should reset the timer', () => { + timer.start(); + timer.reset(); + expect(timer.store.state.isRunning).toBe(false); + expect(timer.store.state.remainingTime).toBe(initialTime); + expect(onReset).toHaveBeenCalled(); + }); + + it('should call onFinish when the timer reaches zero', () => { + timer.start(); + vi.advanceTimersByTime(initialTime * 1000); + expect(timer.store.state.remainingTime).toBe(0); + expect(onFinish).toHaveBeenCalled(); + expect(timer.store.state.isRunning).toBe(false); + }); + + it('should decrement the remaining time every second when running', () => { + timer.start(); + vi.advanceTimersByTime(3000); + expect(timer.store.state.remainingTime).toBe(2); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 37c8fc72..b206e85c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -150,6 +150,9 @@ importers: packages/react-time: dependencies: + '@tanstack/react-store': + specifier: ^0.5.2 + version: 0.5.2(react-dom@18.2.0)(react@18.2.0) '@tanstack/time': specifier: workspace:* version: link:../time @@ -183,7 +186,18 @@ importers: specifier: ^2.10.1 version: 2.10.1(@testing-library/jest-dom@6.4.2)(solid-js@1.7.8)(vite@5.2.6) - packages/time: {} + packages/time: + dependencies: + '@js-temporal/polyfill': + specifier: ^0.4.4 + version: 0.4.4 + '@tanstack/store': + specifier: ^0.4.1 + version: 0.4.1 + devDependencies: + csstype: + specifier: ^3.1.3 + version: 3.1.3 packages/vue-time: dependencies: @@ -541,7 +555,7 @@ packages: dependencies: '@ampproject/remapping': 2.3.0 '@babel/code-frame': 7.24.2 - '@babel/generator': 7.23.6 + '@babel/generator': 7.24.1 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0) '@babel/helpers': 7.24.1 @@ -2619,6 +2633,14 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 dev: true + /@js-temporal/polyfill@0.4.4: + resolution: {integrity: sha512-2X6bvghJ/JAoZO52lbgyAPFj8uCflhTo2g7nkFzEQdXd/D8rEeD4HtmTEpmtGCva260fcd66YNXBOYdnmHqSOg==} + engines: {node: '>=12'} + dependencies: + jsbi: 4.3.0 + tslib: 2.6.2 + dev: false + /@leichtgewicht/ip-codec@2.0.5: resolution: {integrity: sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==} dev: true @@ -3288,6 +3310,26 @@ packages: - vite dev: true + /@tanstack/react-store@0.5.2(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-qzYy3ov/U/QZV8MX4zpStlp0Wwj91dmz7faVQwyLZLHiZp1VbOC5WfbUfbkKz9waL6MecZLKvosYVbgxz8Ty7Q==} + peerDependencies: + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + dependencies: + '@tanstack/store': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + use-sync-external-store: 1.2.0(react@18.2.0) + dev: false + + /@tanstack/store@0.4.1: + resolution: {integrity: sha512-NvW3MomYSTzQK61AWdtWNIhWgszXFZDRgCNlvSDw/DBaoLqJIlZ0/gKLsditA8un/BGU1NR06+j0a/UNLgXA+Q==} + dev: false + + /@tanstack/store@0.5.2: + resolution: {integrity: sha512-t3vR/nzKnixSmJcSjAULL4mlK6hApsC/pFNjwhLTgJJuWzGQaEjcaQvWfyD3LTVm4wljIL0gWW9cZ7Zrqb1bPQ==} + dev: false + /@testing-library/dom@9.3.4: resolution: {integrity: sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==} engines: {node: '>=14'} @@ -5113,7 +5155,7 @@ packages: dom-serializer: 2.0.0 domhandler: 5.0.3 htmlparser2: 8.0.2 - postcss: 8.4.35 + postcss: 8.4.38 postcss-media-query-parser: 0.2.3 dev: true @@ -5151,12 +5193,12 @@ packages: webpack: optional: true dependencies: - icss-utils: 5.1.0(postcss@8.4.35) - postcss: 8.4.35 - postcss-modules-extract-imports: 3.0.0(postcss@8.4.35) - postcss-modules-local-by-default: 4.0.4(postcss@8.4.35) - postcss-modules-scope: 3.1.1(postcss@8.4.35) - postcss-modules-values: 4.0.0(postcss@8.4.35) + icss-utils: 5.1.0(postcss@8.4.38) + postcss: 8.4.38 + postcss-modules-extract-imports: 3.0.0(postcss@8.4.38) + postcss-modules-local-by-default: 4.0.4(postcss@8.4.38) + postcss-modules-scope: 3.1.1(postcss@8.4.38) + postcss-modules-values: 4.0.0(postcss@8.4.38) postcss-value-parser: 4.2.0 semver: 7.6.0 webpack: 5.90.3(esbuild@0.20.2) @@ -7006,13 +7048,13 @@ packages: safer-buffer: 2.1.2 dev: true - /icss-utils@5.1.0(postcss@8.4.35): + /icss-utils@5.1.0(postcss@8.4.38): resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - postcss: 8.4.35 + postcss: 8.4.38 dev: true /identity-function@1.0.0: @@ -7495,7 +7537,7 @@ packages: resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} engines: {node: '>=8'} dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.3 '@babel/parser': 7.24.1 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 @@ -7641,6 +7683,10 @@ packages: argparse: 2.0.1 dev: true + /jsbi@4.3.0: + resolution: {integrity: sha512-SnZNcinB4RIcnEyZqFPdGPVgrg2AcnykiBy0sHVJQKHYeaLUvi3Exj+iaPpLnFVkDPZIV4U0yvgC9/R4uEAZ9g==} + dev: false + /jsdom@24.0.0: resolution: {integrity: sha512-UDS2NayCvmXSXVP6mpTj+73JnNQadZlr9N68189xib2tx5Mls7swlTNao26IoHv46BZJFvXygyRtyXd1feAk1A==} engines: {node: '>=18'} @@ -7891,8 +7937,6 @@ packages: peerDependenciesMeta: webpack: optional: true - webpack-sources: - optional: true dependencies: webpack: 5.90.3(esbuild@0.20.2) webpack-sources: 3.2.3 @@ -9113,45 +9157,45 @@ packages: resolution: {integrity: sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==} dev: true - /postcss-modules-extract-imports@3.0.0(postcss@8.4.35): + /postcss-modules-extract-imports@3.0.0(postcss@8.4.38): resolution: {integrity: sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - postcss: 8.4.35 + postcss: 8.4.38 dev: true - /postcss-modules-local-by-default@4.0.4(postcss@8.4.35): + /postcss-modules-local-by-default@4.0.4(postcss@8.4.38): resolution: {integrity: sha512-L4QzMnOdVwRm1Qb8m4x8jsZzKAaPAgrUF1r/hjDR2Xj7R+8Zsf97jAlSQzWtKx5YNiNGN8QxmPFIc/sh+RQl+Q==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - icss-utils: 5.1.0(postcss@8.4.35) - postcss: 8.4.35 + icss-utils: 5.1.0(postcss@8.4.38) + postcss: 8.4.38 postcss-selector-parser: 6.0.16 postcss-value-parser: 4.2.0 dev: true - /postcss-modules-scope@3.1.1(postcss@8.4.35): + /postcss-modules-scope@3.1.1(postcss@8.4.38): resolution: {integrity: sha512-uZgqzdTleelWjzJY+Fhti6F3C9iF1JR/dODLs/JDefozYcKTBCdD8BIl6nNPbTbcLnGrk56hzwZC2DaGNvYjzA==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - postcss: 8.4.35 + postcss: 8.4.38 postcss-selector-parser: 6.0.16 dev: true - /postcss-modules-values@4.0.0(postcss@8.4.35): + /postcss-modules-values@4.0.0(postcss@8.4.38): resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - icss-utils: 5.1.0(postcss@8.4.35) - postcss: 8.4.35 + icss-utils: 5.1.0(postcss@8.4.38) + postcss: 8.4.38 dev: true /postcss-selector-parser@6.0.16: @@ -9458,7 +9502,7 @@ packages: /regenerator-transform@0.15.2: resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} dependencies: - '@babel/runtime': 7.24.0 + '@babel/runtime': 7.24.1 dev: true /regex-parser@2.3.0: @@ -9545,7 +9589,7 @@ packages: adjust-sourcemap-loader: 4.0.0 convert-source-map: 1.9.0 loader-utils: 2.0.4 - postcss: 8.4.35 + postcss: 8.4.38 source-map: 0.6.1 dev: true @@ -10741,7 +10785,6 @@ packages: /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - dev: true /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}