diff --git a/CHANGELOG.md b/CHANGELOG.md index 27a586c25..11244ecf4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 4.4.2 + +- [610](https://github.com/bvaughn/react-resizable-panels/pull/610): Fix calculated cursor style when `"pointermove"` event is has low-precision/rounded `clientX` and `clientY` values + ## 4.4.1 - [600](https://github.com/bvaughn/react-resizable-panels/pull/600): Bugfix: Collapsible `Panel` should treat `defaultSize={0}` as _collapsed_ on mount diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c52133249..f4ed19819 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,12 +31,13 @@ pnpm test To run end to end tests locally: ```sh pnpm prerelease +pnpm e2e:install pnpm dev:integrations & pnpm e2e:test ``` ### Updating assets -Before subtmitting, also make sure to update generated docs/examples: +Before submitting, also make sure to update generated docs/examples: ``` pnpm compile pnpm prettier diff --git a/integrations/tests/playwright.config.ts b/integrations/tests/playwright.config.ts index f9f97fde4..3516f6cab 100644 --- a/integrations/tests/playwright.config.ts +++ b/integrations/tests/playwright.config.ts @@ -1,20 +1,24 @@ import { defineConfig, devices } from "@playwright/test"; -export default defineConfig({ - projects: [ - { - name: "chromium", - timeout: 10_000, - use: { - ...devices["Desktop Chrome"], - viewport: { width: 1000, height: 600 } +const DEVICES = [ + { + name: "chromium", + use: devices["Desktop Chrome"] + } +]; - // Uncomment to visually debug - // headless: false, - // launchOptions: { - // slowMo: 500 - // } - } +export default defineConfig({ + projects: DEVICES.map(({ name, use }) => ({ + name, + timeout: 10_000, + use: { + ...use, + viewport: { width: 1000, height: 600 } + // Uncomment to visually debug + // headless: false, + // launchOptions: { + // slowMo: 250 + // } } - ] + })) }); diff --git a/integrations/tests/src/components/Decoder.tsx b/integrations/tests/src/components/Decoder.tsx index 4fdeb2621..770d95dd6 100644 --- a/integrations/tests/src/components/Decoder.tsx +++ b/integrations/tests/src/components/Decoder.tsx @@ -36,6 +36,16 @@ export function Decoder({ ? panelRef : undefined; + const [cursorData, setCursorData] = useState<{ + cursorStyle: string; + movementX: number; + movementY: number; + }>({ + cursorStyle: "", + movementX: 0, + movementY: 0 + }); + const stableCallbacksRef = useRef<{ readGroupLayout: () => void; readPanelSize: () => void; @@ -135,6 +145,22 @@ export function Decoder({ return group; }, [encoded, groupRefProp, panelRefProp]); + useLayoutEffect(() => { + const onPointerMove = (event: PointerEvent) => { + setCursorData({ + cursorStyle: window.getComputedStyle(document.body).cursor, + movementX: event.movementX, + movementY: event.movementY + }); + }; + + window.addEventListener("pointermove", onPointerMove); + + return () => { + window.removeEventListener("pointermove", onPointerMove); + }; + }, []); + // Debugging // console.group("Decoder"); // console.log(encoded); @@ -145,6 +171,7 @@ export function Decoder({
{children}
+ {cursorData && } {groupRefProp && ( { for (const usePopUpWindow of [true, false]) { test.describe(usePopUpWindow ? "in a popup" : "in the main window", () => { @@ -25,22 +30,20 @@ test.describe("cursor", () => { await page.evaluate(() => getComputedStyle(document.body).cursor) ).toBe("auto"); - await page.mouse.move(x, y); + await page.mouse.move(x, y, moveConfig); expect( await page.evaluate(() => getComputedStyle(document.body).cursor) ).toBe("ew-resize"); await page.mouse.down(); - await page.mouse.move(50, y); - await page.mouse.move(25, y); + await page.mouse.move(25, y, moveConfig); expect( await page.evaluate(() => getComputedStyle(document.body).cursor) ).toBe("e-resize"); - await page.mouse.move(950, y); - await page.mouse.move(975, y); + await page.mouse.move(975, y, moveConfig); expect( await page.evaluate(() => getComputedStyle(document.body).cursor) @@ -65,22 +68,20 @@ test.describe("cursor", () => { await page.evaluate(() => getComputedStyle(document.body).cursor) ).toBe("auto"); - await page.mouse.move(x, y); + await page.mouse.move(x, y, moveConfig); expect( await page.evaluate(() => getComputedStyle(document.body).cursor) ).toBe("ns-resize"); await page.mouse.down(); - await page.mouse.move(x, 1); - await page.mouse.move(x, 0); + await page.mouse.move(x, 0, moveConfig); expect( await page.evaluate(() => getComputedStyle(document.body).cursor) ).toBe("s-resize"); - await page.mouse.move(x, 599); - await page.mouse.move(x, 600); + await page.mouse.move(x, 600, moveConfig); expect( await page.evaluate(() => getComputedStyle(document.body).cursor) @@ -114,70 +115,103 @@ test.describe("cursor", () => { ).toBe("auto"); // Centered - await page.mouse.move(x, y); + await page.mouse.move(x, y, moveConfig); expect( await page.evaluate(() => getComputedStyle(document.body).cursor) ).toBe("move"); // Top left await page.mouse.down(); - await page.mouse.move(2, 1); - await page.mouse.move(1, 1); + await page.mouse.move(1, 1, moveConfig); expect( await page.evaluate(() => getComputedStyle(document.body).cursor) ).toBe("se-resize"); // Top - await page.mouse.move(x, 1); - await page.mouse.move(x, 0); + await page.mouse.move(x, 0, moveConfig); expect( await page.evaluate(() => getComputedStyle(document.body).cursor) ).toBe("s-resize"); // Top right - await page.mouse.move(999, 1); - await page.mouse.move(1000, 1); + await page.mouse.move(1000, 1, moveConfig); expect( await page.evaluate(() => getComputedStyle(document.body).cursor) ).toBe("sw-resize"); // Right - await page.mouse.move(950, y); - await page.mouse.move(975, y); + await page.mouse.move(975, y, moveConfig); expect( await page.evaluate(() => getComputedStyle(document.body).cursor) ).toBe("w-resize"); // Bottom right - await page.mouse.move(1000, 599); - await page.mouse.move(1000, 600); + await page.mouse.move(1000, 600, moveConfig); expect( await page.evaluate(() => getComputedStyle(document.body).cursor) ).toBe("nw-resize"); // Bottom - await page.mouse.move(x, 599); - await page.mouse.move(x, 600); + await page.mouse.move(x, 600, moveConfig); expect( await page.evaluate(() => getComputedStyle(document.body).cursor) ).toBe("n-resize"); // Bottom left - await page.mouse.move(1, 599); - await page.mouse.move(1, 600); + await page.mouse.move(1, 600, moveConfig); expect( await page.evaluate(() => getComputedStyle(document.body).cursor) ).toBe("ne-resize"); // Left - await page.mouse.move(50, y); - await page.mouse.move(25, y); + await page.mouse.move(25, y, moveConfig); expect( await page.evaluate(() => getComputedStyle(document.body).cursor) ).toBe("e-resize"); // Centered - await page.mouse.move(x, y); + await page.mouse.move(x, y, moveConfig); + expect( + await page.evaluate(() => getComputedStyle(document.body).cursor) + ).toBe("move"); + }); + + test("edge case", async ({ page: mainPage }) => { + const page = await goToUrl( + mainPage, + + + + + + + + + + + , + { usePopUpWindow } + ); + + const separator = page.getByTestId("vertical-separator"); + const boundingBox = (await separator.boundingBox())!; + const x = boundingBox.x + boundingBox.width / 2; + const y = boundingBox.y; + + expect( + await page.evaluate(() => getComputedStyle(document.body).cursor) + ).toBe("auto"); + + // Centered + await page.mouse.move(x, y, moveConfig); + expect( + await page.evaluate(() => getComputedStyle(document.body).cursor) + ).toBe("move"); + + await page.mouse.down(); + + // Moving only in one dimension should not affect the cursor + await page.mouse.move(x, y - 25, moveConfig); expect( await page.evaluate(() => getComputedStyle(document.body).cursor) ).toBe("move"); @@ -201,7 +235,7 @@ test.describe("cursor", () => { await page.evaluate(() => getComputedStyle(document.body).cursor) ).toBe("auto"); - await page.mouse.move(x, y); + await page.mouse.move(x, y, moveConfig); expect( await page.evaluate(() => getComputedStyle(document.body).cursor) diff --git a/lib/constants.ts b/lib/constants.ts index 7a7d1e045..daa105868 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -22,6 +22,8 @@ export const CURSOR_FLAG_HORIZONTAL_MIN = 0b0001; export const CURSOR_FLAG_HORIZONTAL_MAX = 0b0010; export const CURSOR_FLAG_VERTICAL_MIN = 0b0100; export const CURSOR_FLAG_VERTICAL_MAX = 0b1000; +export const CURSOR_FLAGS_HORIZONTAL = 0b0011; +export const CURSOR_FLAGS_VERTICAL = 0b1100; // Misc. shared values export const DEFAULT_POINTER_PRECISION = { diff --git a/lib/global/event-handlers/onDocumentPointerLeave.ts b/lib/global/event-handlers/onDocumentPointerLeave.ts index 4b7a77b2c..8b5fd7c6d 100644 --- a/lib/global/event-handlers/onDocumentPointerLeave.ts +++ b/lib/global/event-handlers/onDocumentPointerLeave.ts @@ -2,7 +2,7 @@ import { read } from "../mutableState"; import { updateActiveHitRegions } from "../utils/updateActiveHitRegion"; export function onDocumentPointerLeave(event: PointerEvent) { - const { interactionState, mountedGroups } = read(); + const { cursorFlags, interactionState, mountedGroups } = read(); switch (interactionState.state) { case "active": { @@ -11,7 +11,8 @@ export function onDocumentPointerLeave(event: PointerEvent) { event, hitRegions: interactionState.hitRegions, initialLayoutMap: interactionState.initialLayoutMap, - mountedGroups + mountedGroups, + prevCursorFlags: cursorFlags }); } } diff --git a/lib/global/event-handlers/onDocumentPointerMove.ts b/lib/global/event-handlers/onDocumentPointerMove.ts index 0d7c60a96..3fccefa4d 100644 --- a/lib/global/event-handlers/onDocumentPointerMove.ts +++ b/lib/global/event-handlers/onDocumentPointerMove.ts @@ -8,7 +8,7 @@ export function onDocumentPointerMove(event: PointerEvent) { return; } - const { interactionState, mountedGroups } = read(); + const { cursorFlags, interactionState, mountedGroups } = read(); switch (interactionState.state) { case "active": { @@ -42,7 +42,8 @@ export function onDocumentPointerMove(event: PointerEvent) { hitRegions: interactionState.hitRegions, initialLayoutMap: interactionState.initialLayoutMap, mountedGroups, - pointerDownAtPoint: interactionState.pointerDownAtPoint + pointerDownAtPoint: interactionState.pointerDownAtPoint, + prevCursorFlags: cursorFlags }); break; } diff --git a/lib/global/utils/updateActiveHitRegion.ts b/lib/global/utils/updateActiveHitRegion.ts index 4fc1f5dbd..d077a071f 100644 --- a/lib/global/utils/updateActiveHitRegion.ts +++ b/lib/global/utils/updateActiveHitRegion.ts @@ -3,7 +3,9 @@ import { CURSOR_FLAG_HORIZONTAL_MAX, CURSOR_FLAG_HORIZONTAL_MIN, CURSOR_FLAG_VERTICAL_MAX, - CURSOR_FLAG_VERTICAL_MIN + CURSOR_FLAG_VERTICAL_MIN, + CURSOR_FLAGS_HORIZONTAL, + CURSOR_FLAGS_VERTICAL } from "../../constants"; import type { Point } from "../../types"; import { updateCursorStyle } from "../cursor/updateCursorStyle"; @@ -18,19 +20,24 @@ export function updateActiveHitRegions({ hitRegions, initialLayoutMap, mountedGroups, - pointerDownAtPoint + pointerDownAtPoint, + prevCursorFlags }: { document: Document; event: { clientX: number; clientY: number; + movementX: number; + movementY: number; }; hitRegions: HitRegion[]; initialLayoutMap: Map; mountedGroups: MountedGroupMap; pointerDownAtPoint?: Point; + prevCursorFlags: number; }) { - let cursorFlags = 0; + let nextCursorFlags = 0; + const nextMountedGroups = new Map(mountedGroups); // Note that HitRegions are frozen once a drag has started @@ -84,14 +91,14 @@ export function updateActiveHitRegions({ // An unchanged means the cursor has exceeded the allowed bounds switch (orientation) { case "horizontal": { - cursorFlags |= + nextCursorFlags |= deltaAsPercentage < 0 ? CURSOR_FLAG_HORIZONTAL_MIN : CURSOR_FLAG_HORIZONTAL_MAX; break; } case "vertical": { - cursorFlags |= + nextCursorFlags |= deltaAsPercentage < 0 ? CURSOR_FLAG_VERTICAL_MIN : CURSOR_FLAG_VERTICAL_MAX; @@ -115,6 +122,21 @@ export function updateActiveHitRegions({ } }); + // Edge case + // Re-use previous horizontal/vertical cursor flags if there's been no movement since the last event + // This accounts for edge cases in browsers like Firefox that sometimes round clientX/clientY values + let cursorFlags = 0; + if (event.movementX === 0) { + cursorFlags |= prevCursorFlags & CURSOR_FLAGS_HORIZONTAL; + } else { + cursorFlags |= nextCursorFlags & CURSOR_FLAGS_HORIZONTAL; + } + if (event.movementY === 0) { + cursorFlags |= prevCursorFlags & CURSOR_FLAGS_VERTICAL; + } else { + cursorFlags |= nextCursorFlags & CURSOR_FLAGS_VERTICAL; + } + update({ cursorFlags, mountedGroups: nextMountedGroups diff --git a/package.json b/package.json index 4406c7788..4af327781 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-resizable-panels", - "version": "4.4.1", + "version": "4.4.2", "type": "module", "author": "Brian Vaughn (https://github.com/bvaughn/)", "contributors": [ @@ -20,13 +20,13 @@ ], "scripts": { "dev": "vite", - "dev:integrations": "pnpm run dev:integrations:next & pnpm run dev:integrations:vike & pnpm run dev:integrations:vite", + "dev:integrations": "concurrently -k \"pnpm run dev:integrations:next\" \"pnpm run dev:integrations:vike\" \"pnpm run dev:integrations:vite\"", "dev:integrations:next": "pnpm -C integrations/next/ run dev", "dev:integrations:vike": "pnpm -C integrations/vike/ run dev", "dev:integrations:vite": "pnpm -C integrations/vite/ run dev", "build": "pnpm run build:lib && pnpm run build:docs", - "build:docs": "TARGET=docs vite build", - "build:lib": "TARGET=lib vite build", + "build:docs": "cross-env TARGET=docs vite build", + "build:lib": "cross-env TARGET=lib vite build", "compile": "pnpm run compile:docs && pnpm run compile:examples", "compile:docs": "tsx ./scripts/compile-docs", "compile:examples": "tsx ./scripts/compile-examples", @@ -34,7 +34,7 @@ "e2e:install": "pnpm -C integrations/tests exec playwright install --with-deps", "e2e:test": "pnpm -C integrations/tests run test", "lint": "eslint .", - "prerelease": "rm -rf dist && pnpm run build:lib", + "prerelease": "rimraf dist && pnpm run build:lib", "prettier": "prettier --write \"**/*.{css,html,js,json,jsx,ts,tsx}\"", "prettier:ci": "prettier --check \"**/*.{css,html,js,json,jsx,ts,tsx}\"", "preview": "vite preview", @@ -73,6 +73,8 @@ "bytes": "^3.1.2", "clsx": "^2.1.1", "compression": "^1.8.1", + "concurrently": "^9.2.1", + "cross-env": "^10.1.0", "csstype": "^3.1.3", "eslint": "^9.30.1", "eslint-plugin-react-hooks": "^5.2.0", @@ -93,6 +95,7 @@ "react-error-boundary": "^6.0.0", "react-lib-tools": "^0.0.31", "react-router-dom": "^7.6.3", + "rimraf": "^6.1.2", "rollup-plugin-terser": "^7.0.2", "rollup-plugin-visualizer": "^6.0.3", "rollup-preserve-directives": "^1.1.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bc062618b..e0e1f3167 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -74,6 +74,12 @@ importers: compression: specifier: ^1.8.1 version: 1.8.1 + concurrently: + specifier: ^9.2.1 + version: 9.2.1 + cross-env: + specifier: ^10.1.0 + version: 10.1.0 csstype: specifier: ^3.1.3 version: 3.2.3 @@ -134,6 +140,9 @@ importers: react-router-dom: specifier: ^7.6.3 version: 7.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + rimraf: + specifier: ^6.1.2 + version: 6.1.2 rollup-plugin-terser: specifier: ^7.0.2 version: 7.0.2(rollup@4.44.2) @@ -594,6 +603,9 @@ packages: '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + '@epic-web/invariant@1.0.0': + resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} + '@esbuild/aix-ppc64@0.25.5': resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==} engines: {node: '>=18'} @@ -2376,6 +2388,11 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + concurrently@9.2.1: + resolution: {integrity: sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==} + engines: {node: '>=18'} + hasBin: true + confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} @@ -2420,6 +2437,11 @@ packages: crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + cross-env@10.1.0: + resolution: {integrity: sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==} + engines: {node: '>=20'} + hasBin: true + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -2911,6 +2933,10 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + glob@13.0.0: + resolution: {integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==} + engines: {node: 20 || >=22} + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported @@ -3392,6 +3418,10 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.2.4: + resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -3467,6 +3497,10 @@ packages: resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} engines: {node: 20 || >=22} + minimatch@10.1.1: + resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} + engines: {node: 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -3477,6 +3511,10 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + mlly@1.8.0: resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} @@ -3615,6 +3653,9 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -3651,6 +3692,10 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@2.0.1: + resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==} + engines: {node: 20 || >=22} + path-to-regexp@8.2.0: resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} engines: {node: '>=16'} @@ -3930,6 +3975,11 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + rimraf@6.1.2: + resolution: {integrity: sha512-cFCkPslJv7BAXJsYlK1dZsbP8/ZNLkCAQ0bi1hf5EKX2QHegmDFEFA6QhuYJlk7UDdc+02JjO80YSOrWPpw06g==} + engines: {node: 20 || >=22} + hasBin: true + rollup-plugin-terser@7.0.2: resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==} deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser @@ -3969,6 +4019,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + safe-array-concat@1.1.3: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} @@ -4058,6 +4111,10 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + shell-quote@1.8.3: + resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} + engines: {node: '>= 0.4'} + side-channel-list@1.0.0: resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} engines: {node: '>= 0.4'} @@ -4302,6 +4359,10 @@ packages: resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} engines: {node: '>=18'} + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + ts-api-utils@2.1.0: resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} engines: {node: '>=18.12'} @@ -5029,6 +5090,8 @@ snapshots: tslib: 2.8.1 optional: true + '@epic-web/invariant@1.0.0': {} + '@esbuild/aix-ppc64@0.25.5': optional: true @@ -6752,6 +6815,15 @@ snapshots: concat-map@0.0.1: {} + concurrently@9.2.1: + dependencies: + chalk: 4.1.2 + rxjs: 7.8.2 + shell-quote: 1.8.3 + supports-color: 8.1.1 + tree-kill: 1.2.2 + yargs: 17.7.2 + confbox@0.1.8: {} confbox@0.2.2: {} @@ -6783,6 +6855,11 @@ snapshots: crelt@1.0.6: {} + cross-env@10.1.0: + dependencies: + '@epic-web/invariant': 1.0.0 + cross-spawn: 7.0.6 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -7083,7 +7160,7 @@ snapshots: eslint: 9.30.1(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.6.1)))(eslint@9.30.1(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.6.1)))(eslint@9.30.1(jiti@2.6.1)))(eslint@9.30.1(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.30.1(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.30.1(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.30.1(jiti@2.6.1)) eslint-plugin-react-hooks: 7.0.1(eslint@9.30.1(jiti@2.6.1)) @@ -7116,7 +7193,7 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.6.1)))(eslint@9.30.1(jiti@2.6.1)))(eslint@9.30.1(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.30.1(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -7131,7 +7208,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.6.1)))(eslint@9.30.1(jiti@2.6.1)))(eslint@9.30.1(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.30.1(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -7475,6 +7552,12 @@ snapshots: dependencies: is-glob: 4.0.3 + glob@13.0.0: + dependencies: + minimatch: 10.1.1 + minipass: 7.1.2 + path-scurry: 2.0.1 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -7955,6 +8038,8 @@ snapshots: lru-cache@10.4.3: {} + lru-cache@11.2.4: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -8017,6 +8102,10 @@ snapshots: dependencies: '@isaacs/brace-expansion': 5.0.0 + minimatch@10.1.1: + dependencies: + '@isaacs/brace-expansion': 5.0.0 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -8027,6 +8116,8 @@ snapshots: minimist@1.2.8: {} + minipass@7.1.2: {} + mlly@1.8.0: dependencies: acorn: 8.15.0 @@ -8172,6 +8263,8 @@ snapshots: dependencies: p-limit: 3.1.0 + package-json-from-dist@1.0.1: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -8201,6 +8294,11 @@ snapshots: path-parse@1.0.7: {} + path-scurry@2.0.1: + dependencies: + lru-cache: 11.2.4 + minipass: 7.1.2 + path-to-regexp@8.2.0: {} path-type@4.0.0: {} @@ -8422,6 +8520,11 @@ snapshots: rfdc@1.4.1: {} + rimraf@6.1.2: + dependencies: + glob: 13.0.0 + package-json-from-dist: 1.0.1 + rollup-plugin-terser@7.0.2(rollup@4.44.2): dependencies: '@babel/code-frame': 7.27.1 @@ -8486,6 +8589,10 @@ snapshots: dependencies: queue-microtask: 1.2.3 + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + safe-array-concat@1.1.3: dependencies: call-bind: 1.0.8 @@ -8619,6 +8726,8 @@ snapshots: shebang-regex@3.0.0: {} + shell-quote@1.8.3: {} + side-channel-list@1.0.0: dependencies: es-errors: 1.3.0 @@ -8866,6 +8975,8 @@ snapshots: dependencies: punycode: 2.3.1 + tree-kill@1.2.2: {} + ts-api-utils@2.1.0(typescript@5.8.3): dependencies: typescript: 5.8.3