From 846f1e870e68bec58bb88fa3ec131873fda8f7a3 Mon Sep 17 00:00:00 2001 From: Reid Barber Date: Mon, 16 Mar 2026 11:32:23 -0500 Subject: [PATCH 1/2] test: Real browser tests (#9516) * initialize S2 tests with Vitest Browser Mode * fix icons/illustrations * fix lint * fix tests * yarn.lock * revert tests * remove extra browser tests * update tests * move config to root * fail on console errors * get drag and drop working in chromium * fix types * restore unaffected tests * add icon/illustration wrappers * fix @storybook/blocks issue * remove unnecessary mocks * fix deps and config * add playwright install to script * run on desktop and mobile viewports * remove patch --- bin/imports.js | 10 +- jest.config.js | 3 +- package.json | 8 + packages/@react-spectrum/s2/package.json | 3 +- .../s2/test/DropZone.browser.test.tsx | 115 ++ .../s2/test/utils/dragAndDrop.ts | 121 ++ .../@react-spectrum/s2/test/utils/index.ts | 14 + .../@react-spectrum/s2/test/utils/render.tsx | 45 + patches/@mdx-js+react+2.0.0-rc.2.patch | 2 +- patches/@vitest+browser+4.0.17.patch | 16 + test/browser/setup.ts | 59 + vitest.browser.config.ts | 246 +++ yarn.lock | 1564 ++++++++++++++++- 13 files changed, 2180 insertions(+), 26 deletions(-) create mode 100644 packages/@react-spectrum/s2/test/DropZone.browser.test.tsx create mode 100644 packages/@react-spectrum/s2/test/utils/dragAndDrop.ts create mode 100644 packages/@react-spectrum/s2/test/utils/index.ts create mode 100644 packages/@react-spectrum/s2/test/utils/render.tsx create mode 100644 patches/@vitest+browser+4.0.17.patch create mode 100644 test/browser/setup.ts create mode 100644 vitest.browser.config.ts diff --git a/bin/imports.js b/bin/imports.js index bc792f2692a..c6896080870 100644 --- a/bin/imports.js +++ b/bin/imports.js @@ -22,7 +22,15 @@ const devDependencies = new Set([ '@parcel/macros', '@adobe/spectrum-tokens', 'playwright', - 'axe-playwright' + 'axe-playwright', + 'vitest', + '@vitejs/plugin-react', + '@vitest/browser', + '@vitest/browser-playwright', + '@vitest/ui', + 'unplugin-parcel-macros', + 'vite', + 'vite-plugin-svgr' ]); module.exports = { diff --git a/jest.config.js b/jest.config.js index a71bca685f9..140c044fbac 100644 --- a/jest.config.js +++ b/jest.config.js @@ -170,7 +170,8 @@ module.exports = { // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped testPathIgnorePatterns: [ '/node_modules/', - '\\.ssr\\.test\\.[tj]sx?$' + '\\.ssr\\.test\\.[tj]sx?$', + '\\.browser\\.test\\.[tj]sx?$' ], testTimeout: 20000, diff --git a/package.json b/package.json index a9e0a772283..af7bfd21c7e 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "start:mcp": "yarn workspace @react-spectrum/s2-docs generate:md && yarn build:mcp && node packages/dev/mcp/s2/dist/index.js && node packages/dev/mcp/react-aria/dist/index.js", "test:mcp": "yarn build:s2-docs && yarn build:mcp && node packages/dev/mcp/scripts/smoke-list-pages.mjs", "test": "cross-env STRICT_MODE=1 VIRT_ON=1 yarn jest", + "test:browser": " yarn playwright install && vitest --config=vitest.browser.config.ts", "test:lint": "node packages/**/*.test-lint.js", "test-loose": "cross-env VIRT_ON=1 yarn jest", "test-storybook": "test-storybook --url http://localhost:9003 --browsers chromium --no-cache", @@ -134,6 +135,9 @@ "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", "@typescript/native-preview": "^7.0.0-dev.20251223.1", + "@vitejs/plugin-react": "^5.1.4", + "@vitest/browser-playwright": "^4.0.17", + "@vitest/browser-preview": "^4.0.17", "@vueless/storybook-dark-mode": "^9.0.6", "@yarnpkg/types": "^4.0.0", "autoprefixer": "^9.6.0", @@ -202,7 +206,11 @@ "tempy": "^0.5.0", "typescript": "^5.8.2", "typescript-eslint": "^8.38.0", + "unplugin-parcel-macros": "^0.1.1", "verdaccio": "^6.0.0", + "vite-plugin-svgr": "^4.5.0", + "vitest": "^4.0.17", + "vitest-browser-react": "^2.0.2", "walk-object": "^4.0.0", "xml": "^1.0.1" }, diff --git a/packages/@react-spectrum/s2/package.json b/packages/@react-spectrum/s2/package.json index bcbebd73541..ace025c126f 100644 --- a/packages/@react-spectrum/s2/package.json +++ b/packages/@react-spectrum/s2/package.json @@ -145,8 +145,7 @@ "@storybook/jest": "^0.2.3", "@testing-library/dom": "^10.1.0", "@testing-library/react": "^16.0.0", - "@testing-library/user-event": "^14.0.0", - "jest": "^29.5.0" + "@testing-library/user-event": "^14.0.0" }, "dependencies": { "@internationalized/date": "^3.12.0", diff --git a/packages/@react-spectrum/s2/test/DropZone.browser.test.tsx b/packages/@react-spectrum/s2/test/DropZone.browser.test.tsx new file mode 100644 index 00000000000..5e38ca5b6f1 --- /dev/null +++ b/packages/@react-spectrum/s2/test/DropZone.browser.test.tsx @@ -0,0 +1,115 @@ +/* + * Copyright 2026 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +import {Button, ButtonGroup, Content, DropZone, FileTrigger, Heading, IllustratedMessage} from '../src'; +import CloudUpload from '@react-spectrum/s2/illustrations/gradient/generic1/CloudUpload'; +import {describe, expect, it, vi} from 'vitest'; +import {dragAndDrop} from './utils/dragAndDrop'; +import {page} from 'vitest/browser'; +import React from 'react'; +import {render} from './utils/render'; +import {style} from '../style' with {type: 'macro'}; +import {useDrag} from '@react-aria/dnd'; + +function Draggable({type}: {type: string}) { + let {dragProps} = useDrag({ + getItems() { + return [{ + [type]: 'hello world' + }]; + } + }); + + return ( +
+ Drag me +
+ ); +} + +describe('DropZone browser interactions', () => { + it('should handle drag and drop of valid drop types', async () => { + let onDrop = vi.fn(); + + await render( + <> + + (types.has('text/plain') ? 'copy' : 'cancel')} + onDrop={onDrop}> + + + + Drag and drop your file + + + Or, select a file from your computer + + + + + + + + + + ); + + let sourceEl = page.getByTestId('drag-source').element(); + let targetEl = page.getByTestId('dropzone').element(); + await dragAndDrop(sourceEl, targetEl); + + await expect.poll(() => onDrop).toHaveBeenCalledTimes(1); + let event = onDrop.mock.calls[0][0]; + expect(event.dropOperation).toBe('copy'); + expect(event.items.length).toBeGreaterThanOrEqual(1); + }); + + it('should reject unsupported drop types', async () => { + let onDrop = vi.fn(); + + await render( + <> + + (types.has('text/plain') ? 'copy' : 'cancel')} + onDrop={onDrop}> + + + + Drag and drop your file + + + Or, select a file from your computer + + + + + + + + + + ); + + let sourceEl = page.getByTestId('drag-source').element(); + let targetEl = page.getByTestId('dropzone').element(); + await dragAndDrop(sourceEl, targetEl); + + expect(onDrop).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/@react-spectrum/s2/test/utils/dragAndDrop.ts b/packages/@react-spectrum/s2/test/utils/dragAndDrop.ts new file mode 100644 index 00000000000..58cfcf51452 --- /dev/null +++ b/packages/@react-spectrum/s2/test/utils/dragAndDrop.ts @@ -0,0 +1,121 @@ +/* + * Copyright 2026 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +import {server, userEvent} from 'vitest/browser'; + +/** + * Creates a DataTransfer wrapper that works around Chromium restrictions on synthetic events. + * + * Chromium silently ignores writes to effectAllowed and dropEffect on DataTransfer objects + * attached to untrusted (dispatched) DragEvents. This proxy intercepts those writes and + * stores them in a local overlay, while forwarding everything else to the real DataTransfer. + */ +function createWritableDataTransfer(): {dataTransfer: DataTransfer, proxy: DataTransfer} { + let dataTransfer = new DataTransfer(); + let overrides: Record = {}; + + let proxy = new Proxy(dataTransfer, { + get(target, prop) { + if (prop in overrides) { + return overrides[prop as string]; + } + let value = Reflect.get(target, prop, target); + if (typeof value === 'function') { + return value.bind(target); + } + return value; + }, + set(target, prop, value) { + if (prop === 'effectAllowed' || prop === 'dropEffect') { + overrides[prop] = value; + try { (target as any)[prop] = value; } catch { /* noop - Chromium rejects this */ } + return true; + } + (target as any)[prop] = value; + return true; + } + }); + + return {dataTransfer, proxy}; +} + +interface DragAndDropOptions { + /** Clicks on the source element at this point relative to the top-left corner of the element's padding box. */ + sourcePosition?: {x: number, y: number}, + /** Drops on the target element at this point relative to the top-left corner of the element's padding box. */ + targetPosition?: {x: number, y: number} +} + +/** Returns the clientX/clientY for a position relative to an element's padding box, or the element's center if no position is given. */ +function resolveClientPosition(element: Element, position?: {x: number, y: number}): {clientX: number, clientY: number} { + let rect = element.getBoundingClientRect(); + if (position) { + return {clientX: rect.left + position.x, clientY: rect.top + position.y}; + } + return {clientX: rect.left + rect.width / 2, clientY: rect.top + rect.height / 2}; +} + +/** + * Perform a drag-and-drop from source to target. + * + * On non-Chromium browsers, delegates to `userEvent.dragAndDrop` which uses the + * browser provider's native drag support. + * + * On Chromium, Playwright's CDP-based drag bypasses the native dragstart event, + * which prevents useDrag from populating the DataTransfer. We fall back to + * dispatching the full DragEvent lifecycle with synthetic events instead. + */ +export async function dragAndDrop(source: Element, target: Element, options?: DragAndDropOptions): Promise { + if (server.browser !== 'chromium') { + await userEvent.dragAndDrop(source, target, options); + return; + } + + let {dataTransfer, proxy} = createWritableDataTransfer(); + + let sourcePos = resolveClientPosition(source, options?.sourcePosition); + let targetPos = resolveClientPosition(target, options?.targetPosition); + + // Patch DragEvent.prototype.dataTransfer to return our proxy whenever the + // event carries our real dataTransfer. This is the only reliable way to make + // effectAllowed/dropEffect writable in Chromium for synthetic events. + let origDesc = Object.getOwnPropertyDescriptor(DragEvent.prototype, 'dataTransfer')!; + Object.defineProperty(DragEvent.prototype, 'dataTransfer', { + get() { + let real = origDesc.get!.call(this); + return real === dataTransfer ? proxy : real; + }, + configurable: true + }); + + try { + // Dispatch dragstart so useDrag populates the DataTransfer with items and sets effectAllowed. + source.dispatchEvent(new DragEvent('dragstart', {dataTransfer, bubbles: true, cancelable: true, ...sourcePos})); + + // Allow React state updates from the dragstart handler to flush. + await new Promise(resolve => requestAnimationFrame(resolve)); + + target.dispatchEvent(new DragEvent('dragenter', {dataTransfer, bubbles: true, cancelable: true, ...targetPos})); + target.dispatchEvent(new DragEvent('dragover', {dataTransfer, bubbles: true, cancelable: true, ...targetPos})); + + // In a real browser drag, the drop event only fires when dropEffect is not 'none'. + // useDrop sets dropEffect during dragenter/dragover based on getDropOperation. + if (proxy.dropEffect !== 'none') { + target.dispatchEvent(new DragEvent('drop', {dataTransfer, bubbles: true, cancelable: true, ...targetPos})); + } + + source.dispatchEvent(new DragEvent('dragend', {dataTransfer, bubbles: true, cancelable: true, ...targetPos})); + } finally { + // Restore the original dataTransfer getter. + Object.defineProperty(DragEvent.prototype, 'dataTransfer', origDesc); + } +} diff --git a/packages/@react-spectrum/s2/test/utils/index.ts b/packages/@react-spectrum/s2/test/utils/index.ts new file mode 100644 index 00000000000..fadfbffe965 --- /dev/null +++ b/packages/@react-spectrum/s2/test/utils/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright 2026 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +export * from './dragAndDrop'; +export * from './render'; diff --git a/packages/@react-spectrum/s2/test/utils/render.tsx b/packages/@react-spectrum/s2/test/utils/render.tsx new file mode 100644 index 00000000000..393869dd561 --- /dev/null +++ b/packages/@react-spectrum/s2/test/utils/render.tsx @@ -0,0 +1,45 @@ +/* + * Copyright 2026 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +import '../../src/page'; +import {Provider, type ProviderProps} from '../../src'; +import React, {ReactElement} from 'react'; +import {render as vitestBrowserRender} from 'vitest-browser-react'; + +export interface S2RenderOptions { + /** + * Options to pass to the Provider. + */ + providerOptions?: Omit +} + +/** + * Custom render function that wraps components in the S2 Provider. + * Uses vitest-browser-react for browser mode testing. + */ +export async function render( + ui: ReactElement, + options: S2RenderOptions = {} +) { + const {providerOptions = {}} = options; + const {locale = 'en-US', colorScheme = 'light', ...restProviderOptions} = providerOptions; + + function Wrapper({children}: {children: React.ReactNode}) { + return ( + + {children} + + ); + } + + return await vitestBrowserRender({ui}); +} diff --git a/patches/@mdx-js+react+2.0.0-rc.2.patch b/patches/@mdx-js+react+2.0.0-rc.2.patch index b405b72598d..a69fc2a1da8 100644 --- a/patches/@mdx-js+react+2.0.0-rc.2.patch +++ b/patches/@mdx-js+react+2.0.0-rc.2.patch @@ -3,7 +3,7 @@ index be47704..c7ca78e 100644 --- a/node_modules/@mdx-js/react/lib/index.d.ts +++ b/node_modules/@mdx-js/react/lib/index.d.ts @@ -1,3 +1,4 @@ -+import {JSX} from 'react'; ++import type {JSX} from 'react'; /** * @param {import('react').ComponentType} Component * @deprecated diff --git a/patches/@vitest+browser+4.0.17.patch b/patches/@vitest+browser+4.0.17.patch new file mode 100644 index 00000000000..d6ace5cd35c --- /dev/null +++ b/patches/@vitest+browser+4.0.17.patch @@ -0,0 +1,16 @@ +diff --git a/node_modules/@vitest/browser/matchers.d.ts b/node_modules/@vitest/browser/matchers.d.ts +index 1234567..abcdefg 100644 +--- a/node_modules/@vitest/browser/matchers.d.ts ++++ b/node_modules/@vitest/browser/matchers.d.ts +@@ -1,9 +1,8 @@ + import type { Locator } from './context.js' +-import type { TestingLibraryMatchers } from './jest-dom.js' + import type { Assertion, ExpectPollOptions } from 'vitest' + + declare module 'vitest' { +- interface JestAssertion extends TestingLibraryMatchers {} +- interface AsymmetricMatchersContaining extends TestingLibraryMatchers {} ++ interface JestAssertion {} ++ interface AsymmetricMatchersContaining {} + + type Promisify = { diff --git a/test/browser/setup.ts b/test/browser/setup.ts new file mode 100644 index 00000000000..335c54b8711 --- /dev/null +++ b/test/browser/setup.ts @@ -0,0 +1,59 @@ +/* + * Copyright 2026 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +import 'vitest-browser-react'; +import {beforeEach} from 'vitest'; + +// Track console errors and warnings per test +let consoleErrors: Array<{message: unknown, args: unknown[]}> = []; +let consoleWarnings: Array<{message: unknown, args: unknown[]}> = []; + +// Reset console error/warning tracking before each test +beforeEach(() => { + consoleErrors = []; + consoleWarnings = []; +}); + +// Fail test if there were any console errors +afterEach(() => { + if (consoleErrors.length > 0) { + const errorMessages = consoleErrors.map(e => + typeof e.message === 'string' ? e.message : String(e.message) + ).join('\n'); + throw new Error( + `Test failed due to console errors:\n${errorMessages}\n\n` + ); + } +}); + +// Track console errors +const originalError = console.error; +console.error = function (message: unknown, ...args: unknown[]) { + consoleErrors.push({message, args}); + originalError.call(console, message, ...args); +}; + +// Track console warnings +const originalWarn = console.warn; +console.warn = function (message: unknown, ...args: unknown[]) { + consoleWarnings.push({message, args}); + originalWarn.call(console, message, ...args); +}; + +// Mock process for browser environment +if (typeof process === 'undefined') { + globalThis.process = { + env: {}, + versions: {node: '0.0.0'} as NodeJS.ProcessVersions, + browser: true + } as unknown as NodeJS.Process; +} diff --git a/vitest.browser.config.ts b/vitest.browser.config.ts new file mode 100644 index 00000000000..1b89e68fde5 --- /dev/null +++ b/vitest.browser.config.ts @@ -0,0 +1,246 @@ +/* + * Copyright 2026 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +import {defineConfig} from 'vitest/config'; +import fs from 'fs'; +import macros from 'unplugin-parcel-macros'; +import path from 'path'; +import {playwright} from '@vitest/browser-playwright'; +import type {Plugin} from 'vite'; +import react from '@vitejs/plugin-react'; +import svgr from 'vite-plugin-svgr'; + +const s2Dir = path.resolve(__dirname, 'packages/@react-spectrum/s2'); + +// Handles ../intl/*.json imports +function intlJsonPlugin(): Plugin { + return { + name: 'intl-json-loader', + async resolveId(source, importer) { + if (source.includes('/intl/*.json') && importer) { + const dir = path.dirname(importer); + const intlDir = path.resolve(dir, source.replace('*.json', '')); + return `virtual:intl-messages:${intlDir}`; + } + return null; + }, + async load(id) { + if (id.startsWith('virtual:intl-messages:')) { + const intlDir = id.replace('virtual:intl-messages:', ''); + try { + const files = fs.readdirSync(intlDir).filter(f => f.endsWith('.json')); + const messages: Record> = {}; + + for (const file of files) { + const locale = path.basename(file, '.json'); + const content = fs.readFileSync(path.join(intlDir, file), 'utf-8'); + messages[locale] = JSON.parse(content); + } + + return `export default ${JSON.stringify(messages)};`; + } catch { + return 'export default {};'; + } + } + return null; + } + }; +} + +// Resolve @react-spectrum/s2/illustrations/* imports +function illustrationResolverPlugin(): Plugin { + return { + name: 'illustration-resolver', + enforce: 'pre', + resolveId(source) { + if (source.startsWith('@react-spectrum/s2/illustrations/')) { + const illustrationPath = source.replace('@react-spectrum/s2/illustrations/', ''); + const tsxPath = path.resolve(s2Dir, 'spectrum-illustrations', illustrationPath + '.tsx'); + + if (fs.existsSync(tsxPath)) { + return tsxPath; + } + + return null; + } + return null; + } + }; +} + +/** + * Handle S2 illustrations + * + * Resolves the SVG and wraps it with createIllustration from Icon.tsx. + */ +function illustrationPlugin(): Plugin { + const VIRTUAL_PREFIX = '\0s2-illustration:'; + return { + name: 'illustration-loader', + enforce: 'pre', + resolveId(source, importer) { + if (source.startsWith('illustration:')) { + const svgPath = source.replace('illustration:', ''); + if (importer) { + const dir = path.dirname(importer); + const resolvedPath = path.resolve(dir, svgPath); + return VIRTUAL_PREFIX + resolvedPath; + } + } + return null; + }, + load(id) { + if (id.startsWith(VIRTUAL_PREFIX)) { + const svgPath = id.slice(VIRTUAL_PREFIX.length).replaceAll('\\', '/'); + return [ + `import {createIllustration} from '${path.resolve(s2Dir, 'src/Icon.tsx').replaceAll('\\', '/')}';`, + `import SvgComponent from '${svgPath}';`, + `export default /*#__PURE__*/ createIllustration(SvgComponent);` + ].join('\n'); + } + return null; + } + }; +} + +/** + * Handle S2 workflow icons + * + * Resolves the SVG and wraps it with createIcon from Icon.tsx. + */ +function iconWrapperPlugin(): Plugin { + const VIRTUAL_PREFIX = '\0s2-icon:'; + const iconsDir = path.resolve(s2Dir, 's2wf-icons'); + + // Build a map from icon name -> absolute SVG path + const iconMap = new Map(); + if (fs.existsSync(iconsDir)) { + for (const file of fs.readdirSync(iconsDir)) { + const match = file.match(/^S2_Icon_(.+)_20_N\.svg$/); + if (match) { + iconMap.set(match[1], path.resolve(iconsDir, file)); + } + } + } + + return { + name: 'icon-wrapper', + enforce: 'pre', + resolveId(source) { + if (source.startsWith('@react-spectrum/s2/icons/')) { + const iconName = source.replace('@react-spectrum/s2/icons/', ''); + if (iconMap.has(iconName)) { + return VIRTUAL_PREFIX + iconName; + } + } + return null; + }, + load(id) { + if (id.startsWith(VIRTUAL_PREFIX)) { + const iconName = id.slice(VIRTUAL_PREFIX.length); + const svgPath = iconMap.get(iconName); + if (svgPath) { + return [ + `import {createIcon} from '${path.resolve(s2Dir, 'src/Icon.tsx').replaceAll('\\', '/')}';`, + `import SvgComponent from '${svgPath.replaceAll('\\', '/')}';`, + `export default /*#__PURE__*/ createIcon(SvgComponent);` + ].join('\n'); + } + } + return null; + } + }; +} + +export default defineConfig({ + plugins: [ + // @ts-expect-error + macros.vite(), // Must be first! + // @ts-expect-error + iconWrapperPlugin(), // Wrap @react-spectrum/s2/icons/* SVGs with createIcon + // @ts-expect-error + illustrationResolverPlugin(), // Resolve @react-spectrum/s2/illustrations/* imports + // @ts-expect-error + illustrationPlugin(), // Handle illustration: protocol + // @ts-expect-error + svgr({ + // Process all SVG files as React components + include: [ + '**/s2wf-icons/**/*.svg', + '**/ui-icons/**/*.svg', + '**/spectrum-illustrations/**/*.svg' + ], + exclude: ['**/node_modules/**'], + svgrOptions: { + ref: true, + typescript: false, + svgoConfig: { + plugins: [ + { + name: 'preset-default', + params: { + overrides: { + removeViewBox: false + } + } + } + ] + } + } + }), + // @ts-expect-error + react(), + // @ts-expect-error + intlJsonPlugin() + ], + test: { + globals: true, + setupFiles: ['./test/browser/setup.ts'], + include: ['packages/**/test/**/*.browser.test.{ts,tsx}'], + browser: { + provider: playwright(), + enabled: true, + instances: [ + {browser: 'chromium', name: 'chromium-mobile', viewport: {width: 414, height: 896}}, + {browser: 'chromium', name: 'chromium-desktop', viewport: {width: 1280, height: 720}}, + {browser: 'firefox', name: 'firefox-mobile', viewport: {width: 414, height: 896}}, + {browser: 'firefox', name: 'firefox-desktop', viewport: {width: 1280, height: 720}}, + {browser: 'webkit', name: 'webkit-mobile', viewport: {width: 414, height: 896}}, + {browser: 'webkit', name: 'webkit-desktop', viewport: {width: 1280, height: 720}} + ] + }, + coverage: { + provider: 'v8', + reporter: ['text', 'json', 'html'], + include: ['packages/**/src/**/*.{ts,tsx}'], + exclude: ['packages/**/src/**/*.d.ts', 'packages/**/src/index.ts'] + }, + testTimeout: 20000 + }, + resolve: { + conditions: ['source', 'import', 'module', 'default'], + extensions: ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json', '.svg'], + alias: { + '@react-spectrum/s2/illustrations': path.resolve(s2Dir, 'spectrum-illustrations'), + '@react-spectrum/s2': path.resolve(s2Dir, 'src') + } + }, + optimizeDeps: { + exclude: ['@parcel/macros'] + }, + css: { + postcss: { + // @ts-expect-error + config: false + } + } +}); diff --git a/yarn.lock b/yarn.lock index eb4a90824b7..8998485ae76 100644 --- a/yarn.lock +++ b/yarn.lock @@ -454,6 +454,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-plugin-utils@npm:^7.27.1": + version: 7.28.6 + resolution: "@babel/helper-plugin-utils@npm:7.28.6" + checksum: 10c0/3f5f8acc152fdbb69a84b8624145ff4f9b9f6e776cb989f9f968f8606eb7185c5c3cfcf3ba08534e37e1e0e1c118ac67080610333f56baa4f7376c99b5f1143d + languageName: node + linkType: hard + "@babel/helper-remap-async-to-generator@npm:^7.22.20": version: 7.22.20 resolution: "@babel/helper-remap-async-to-generator@npm:7.22.20" @@ -1400,6 +1407,28 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-react-jsx-self@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-react-jsx-self@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/00a4f917b70a608f9aca2fb39aabe04a60aa33165a7e0105fd44b3a8531630eb85bf5572e9f242f51e6ad2fa38c2e7e780902176c863556c58b5ba6f6e164031 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx-source@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-react-jsx-source@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/5e67b56c39c4d03e59e03ba80692b24c5a921472079b63af711b1d250fc37c1733a17069b63537f750f3e937ec44a42b1ee6a46cd23b1a0df5163b17f741f7f2 + languageName: node + linkType: hard + "@babel/plugin-transform-react-jsx@npm:^7.22.5, @babel/plugin-transform-react-jsx@npm:^7.23.4": version: 7.23.4 resolution: "@babel/plugin-transform-react-jsx@npm:7.23.4" @@ -1897,6 +1926,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/aix-ppc64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/aix-ppc64@npm:0.27.3" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + "@esbuild/android-arm64@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/android-arm64@npm:0.25.5" @@ -1904,6 +1940,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/android-arm64@npm:0.27.3" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/android-arm@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/android-arm@npm:0.25.5" @@ -1911,6 +1954,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/android-arm@npm:0.27.3" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + "@esbuild/android-x64@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/android-x64@npm:0.25.5" @@ -1918,6 +1968,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-x64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/android-x64@npm:0.27.3" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + "@esbuild/darwin-arm64@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/darwin-arm64@npm:0.25.5" @@ -1925,6 +1982,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-arm64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/darwin-arm64@npm:0.27.3" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/darwin-x64@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/darwin-x64@npm:0.25.5" @@ -1932,6 +1996,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-x64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/darwin-x64@npm:0.27.3" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@esbuild/freebsd-arm64@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/freebsd-arm64@npm:0.25.5" @@ -1939,6 +2010,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-arm64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/freebsd-arm64@npm:0.27.3" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/freebsd-x64@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/freebsd-x64@npm:0.25.5" @@ -1946,6 +2024,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-x64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/freebsd-x64@npm:0.27.3" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/linux-arm64@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/linux-arm64@npm:0.25.5" @@ -1953,6 +2038,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/linux-arm64@npm:0.27.3" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/linux-arm@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/linux-arm@npm:0.25.5" @@ -1960,6 +2052,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/linux-arm@npm:0.27.3" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + "@esbuild/linux-ia32@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/linux-ia32@npm:0.25.5" @@ -1967,6 +2066,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ia32@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/linux-ia32@npm:0.27.3" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/linux-loong64@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/linux-loong64@npm:0.25.5" @@ -1974,6 +2080,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-loong64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/linux-loong64@npm:0.27.3" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + "@esbuild/linux-mips64el@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/linux-mips64el@npm:0.25.5" @@ -1981,6 +2094,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-mips64el@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/linux-mips64el@npm:0.27.3" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + "@esbuild/linux-ppc64@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/linux-ppc64@npm:0.25.5" @@ -1988,6 +2108,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ppc64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/linux-ppc64@npm:0.27.3" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + "@esbuild/linux-riscv64@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/linux-riscv64@npm:0.25.5" @@ -1995,6 +2122,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-riscv64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/linux-riscv64@npm:0.27.3" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + "@esbuild/linux-s390x@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/linux-s390x@npm:0.25.5" @@ -2002,6 +2136,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-s390x@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/linux-s390x@npm:0.27.3" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + "@esbuild/linux-x64@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/linux-x64@npm:0.25.5" @@ -2009,6 +2150,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-x64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/linux-x64@npm:0.27.3" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + "@esbuild/netbsd-arm64@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/netbsd-arm64@npm:0.25.5" @@ -2016,6 +2164,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/netbsd-arm64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/netbsd-arm64@npm:0.27.3" + conditions: os=netbsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/netbsd-x64@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/netbsd-x64@npm:0.25.5" @@ -2023,6 +2178,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/netbsd-x64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/netbsd-x64@npm:0.27.3" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/openbsd-arm64@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/openbsd-arm64@npm:0.25.5" @@ -2030,6 +2192,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/openbsd-arm64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/openbsd-arm64@npm:0.27.3" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/openbsd-x64@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/openbsd-x64@npm:0.25.5" @@ -2037,6 +2206,20 @@ __metadata: languageName: node linkType: hard +"@esbuild/openbsd-x64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/openbsd-x64@npm:0.27.3" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openharmony-arm64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/openharmony-arm64@npm:0.27.3" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/sunos-x64@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/sunos-x64@npm:0.25.5" @@ -2044,6 +2227,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/sunos-x64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/sunos-x64@npm:0.27.3" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + "@esbuild/win32-arm64@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/win32-arm64@npm:0.25.5" @@ -2051,6 +2241,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-arm64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/win32-arm64@npm:0.27.3" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/win32-ia32@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/win32-ia32@npm:0.25.5" @@ -2058,6 +2255,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-ia32@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/win32-ia32@npm:0.27.3" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/win32-x64@npm:0.25.5": version: 0.25.5 resolution: "@esbuild/win32-x64@npm:0.25.5" @@ -2065,6 +2269,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-x64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/win32-x64@npm:0.27.3" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": version: 4.4.0 resolution: "@eslint-community/eslint-utils@npm:4.4.0" @@ -4189,6 +4400,20 @@ __metadata: languageName: node linkType: hard +"@parcel/cache@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/cache@npm:2.16.4" + dependencies: + "@parcel/fs": "npm:2.16.4" + "@parcel/logger": "npm:2.16.4" + "@parcel/utils": "npm:2.16.4" + lmdb: "npm:2.8.5" + peerDependencies: + "@parcel/core": ^2.16.4 + checksum: 10c0/3514c5dd33fe0a7f7911b051fc312c9a8356769aad147b600ad4f15ae02096d32c44e54a9181dc08ab6af7cc9d84fe7b683a813a1451a2bf6e0467fa895dcfad + languageName: node + linkType: hard + "@parcel/codeframe@npm:2.16.3": version: 2.16.3 resolution: "@parcel/codeframe@npm:2.16.3" @@ -4198,6 +4423,15 @@ __metadata: languageName: node linkType: hard +"@parcel/codeframe@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/codeframe@npm:2.16.4" + dependencies: + chalk: "npm:^4.1.2" + checksum: 10c0/355481535a7f0a1be1273c35d3abc692bb519b0aa3076911548b5396774f9516dbdecbe0489c26313b04a9985c73b5acaaae25988adcd979e3d605af1d3da534 + languageName: node + linkType: hard + "@parcel/compressor-raw@npm:2.16.3, @parcel/compressor-raw@npm:^2.16.0, @parcel/compressor-raw@npm:^2.16.3": version: 2.16.3 resolution: "@parcel/compressor-raw@npm:2.16.3" @@ -4310,6 +4544,39 @@ __metadata: languageName: node linkType: hard +"@parcel/core@npm:^2.12.0": + version: 2.16.4 + resolution: "@parcel/core@npm:2.16.4" + dependencies: + "@mischnic/json-sourcemap": "npm:^0.1.1" + "@parcel/cache": "npm:2.16.4" + "@parcel/diagnostic": "npm:2.16.4" + "@parcel/events": "npm:2.16.4" + "@parcel/feature-flags": "npm:2.16.4" + "@parcel/fs": "npm:2.16.4" + "@parcel/graph": "npm:3.6.4" + "@parcel/logger": "npm:2.16.4" + "@parcel/package-manager": "npm:2.16.4" + "@parcel/plugin": "npm:2.16.4" + "@parcel/profiler": "npm:2.16.4" + "@parcel/rust": "npm:2.16.4" + "@parcel/source-map": "npm:^2.1.1" + "@parcel/types": "npm:2.16.4" + "@parcel/utils": "npm:2.16.4" + "@parcel/workers": "npm:2.16.4" + base-x: "npm:^3.0.11" + browserslist: "npm:^4.24.5" + clone: "npm:^2.1.2" + dotenv: "npm:^16.5.0" + dotenv-expand: "npm:^11.0.7" + json5: "npm:^2.2.3" + msgpackr: "npm:^1.11.2" + nullthrows: "npm:^1.1.1" + semver: "npm:^7.7.1" + checksum: 10c0/4a9570956a992ca35247e637b4fc838de1f88e37024a4e63305fc368b6a85c272be4d1afa399bd6fe5408faefb829c908bce81392a80fc7a88c2abbd6556fcce + languageName: node + linkType: hard + "@parcel/diagnostic@npm:2.16.3": version: 2.16.3 resolution: "@parcel/diagnostic@npm:2.16.3" @@ -4320,6 +4587,16 @@ __metadata: languageName: node linkType: hard +"@parcel/diagnostic@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/diagnostic@npm:2.16.4" + dependencies: + "@mischnic/json-sourcemap": "npm:^0.1.1" + nullthrows: "npm:^1.1.1" + checksum: 10c0/4a651f64746e58f92e3f4c826d93f10050614bd24f03bcf4c083cde8e9b5262d3ffd9a21ce51873396bafe7f630ab0750f072e37baa2b73994fedbaa842963d2 + languageName: node + linkType: hard + "@parcel/error-overlay@npm:2.16.3": version: 2.16.3 resolution: "@parcel/error-overlay@npm:2.16.3" @@ -4334,6 +4611,13 @@ __metadata: languageName: node linkType: hard +"@parcel/events@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/events@npm:2.16.4" + checksum: 10c0/0e025b0592f213f3fc12dce9cf76e7673da08127e6361849691991f7a6bcb1ba93ab1aca7e2236eebfa978e7f4afc737e3d6c89d90781178745057a49f3443fd + languageName: node + linkType: hard + "@parcel/feature-flags@npm:2.16.3": version: 2.16.3 resolution: "@parcel/feature-flags@npm:2.16.3" @@ -4341,6 +4625,13 @@ __metadata: languageName: node linkType: hard +"@parcel/feature-flags@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/feature-flags@npm:2.16.4" + checksum: 10c0/e737524d1e394d0cf63c3e6c141194e4bfaadf3827d868e18a51bd2e0dd3b178525350dc3841706e48bc775d5e43a005f9dc65bf7b483c5445ac28db72236ca3 + languageName: node + linkType: hard + "@parcel/fs@npm:2.16.3, @parcel/fs@npm:^2.16.3": version: 2.16.3 resolution: "@parcel/fs@npm:2.16.3" @@ -4357,6 +4648,22 @@ __metadata: languageName: node linkType: hard +"@parcel/fs@npm:2.16.4, @parcel/fs@npm:^2.12.0": + version: 2.16.4 + resolution: "@parcel/fs@npm:2.16.4" + dependencies: + "@parcel/feature-flags": "npm:2.16.4" + "@parcel/rust": "npm:2.16.4" + "@parcel/types-internal": "npm:2.16.4" + "@parcel/utils": "npm:2.16.4" + "@parcel/watcher": "npm:^2.0.7" + "@parcel/workers": "npm:2.16.4" + peerDependencies: + "@parcel/core": ^2.16.4 + checksum: 10c0/09b689e5a078fafca75f15a1c69b9d2582cbe675371cd85755b6c2736a912a474605f6d6a3a4f6a9b2cff6f83543852bf83f54e1d77719397bd09862c8206621 + languageName: node + linkType: hard + "@parcel/graph@npm:3.6.3": version: 3.6.3 resolution: "@parcel/graph@npm:3.6.3" @@ -4367,6 +4674,16 @@ __metadata: languageName: node linkType: hard +"@parcel/graph@npm:3.6.4": + version: 3.6.4 + resolution: "@parcel/graph@npm:3.6.4" + dependencies: + "@parcel/feature-flags": "npm:2.16.4" + nullthrows: "npm:^1.1.1" + checksum: 10c0/c7bbb3cfad35151349ab22c71a8f5a7c5dd2612523d4343bc0c5d6e53bf805bc7405b539179f8c1b99f5aed0d53ec9f36b0a75ed22fa10a77d7fb91c81425ee6 + languageName: node + linkType: hard + "@parcel/logger@npm:2.16.3": version: 2.16.3 resolution: "@parcel/logger@npm:2.16.3" @@ -4377,6 +4694,16 @@ __metadata: languageName: node linkType: hard +"@parcel/logger@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/logger@npm:2.16.4" + dependencies: + "@parcel/diagnostic": "npm:2.16.4" + "@parcel/events": "npm:2.16.4" + checksum: 10c0/b856bfa15b90c664534f311b8a152c6fd6202be8b9170f0353046f675ba60f83cd229419748ca48b9f609d34b097a432cb20426e6ceba1eeb15e69fe3ff1d066 + languageName: node + linkType: hard + "@parcel/macros@npm:^2.16.3": version: 2.16.3 resolution: "@parcel/macros@npm:2.16.3" @@ -4393,6 +4720,15 @@ __metadata: languageName: node linkType: hard +"@parcel/markdown-ansi@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/markdown-ansi@npm:2.16.4" + dependencies: + chalk: "npm:^4.1.2" + checksum: 10c0/d1d6cfd30a6cea9c6a76d6de7bab8620caa49c7343958ac39bf309c54b7d258938988c07b8eff8af2d0d6b4d2726703ce532ef317fde93eb48f15569b00281d8 + languageName: node + linkType: hard + "@parcel/namer-default@npm:2.16.3, @parcel/namer-default@npm:^2.16.0, @parcel/namer-default@npm:^2.16.3": version: 2.16.3 resolution: "@parcel/namer-default@npm:2.16.3" @@ -4419,6 +4755,21 @@ __metadata: languageName: node linkType: hard +"@parcel/node-resolver-core@npm:3.7.4": + version: 3.7.4 + resolution: "@parcel/node-resolver-core@npm:3.7.4" + dependencies: + "@mischnic/json-sourcemap": "npm:^0.1.1" + "@parcel/diagnostic": "npm:2.16.4" + "@parcel/fs": "npm:2.16.4" + "@parcel/rust": "npm:2.16.4" + "@parcel/utils": "npm:2.16.4" + nullthrows: "npm:^1.1.1" + semver: "npm:^7.7.1" + checksum: 10c0/2f5ea2fe3dda9363365f052c6fbabfe8b4f1a2d2f1e92631b15f3c3ddfcc37a1dc7d3e660bdec6a9e0d66ffb5e4c795aef8c8363a14a20698fb82b774132c314 + languageName: node + linkType: hard + "@parcel/optimizer-css@npm:2.16.3": version: 2.16.3 resolution: "@parcel/optimizer-css@npm:2.16.3" @@ -4530,6 +4881,25 @@ __metadata: languageName: node linkType: hard +"@parcel/package-manager@npm:2.16.4, @parcel/package-manager@npm:^2.12.0": + version: 2.16.4 + resolution: "@parcel/package-manager@npm:2.16.4" + dependencies: + "@parcel/diagnostic": "npm:2.16.4" + "@parcel/fs": "npm:2.16.4" + "@parcel/logger": "npm:2.16.4" + "@parcel/node-resolver-core": "npm:3.7.4" + "@parcel/types": "npm:2.16.4" + "@parcel/utils": "npm:2.16.4" + "@parcel/workers": "npm:2.16.4" + "@swc/core": "npm:^1.11.24" + semver: "npm:^7.7.1" + peerDependencies: + "@parcel/core": ^2.16.4 + checksum: 10c0/263ce3c329683ab08a8d9ecfbe0539ab49d7200a897d10ca7e2a5aecb8d662ce093cc0378a5378161b099737d9ee11104d0301a9769d0f1cc0a17295aedf59cc + languageName: node + linkType: hard + "@parcel/packager-css@npm:2.16.3": version: 2.16.3 resolution: "@parcel/packager-css@npm:2.16.3" @@ -4646,6 +5016,15 @@ __metadata: languageName: node linkType: hard +"@parcel/plugin@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/plugin@npm:2.16.4" + dependencies: + "@parcel/types": "npm:2.16.4" + checksum: 10c0/36e8aa483413c91183a1960ac2cbf8b5ad086c88b876af02f47b18c87c10998c95991ba373fc05ab1e54af26192e5620496a41568f9ff1b0604fa4c32f17385f + languageName: node + linkType: hard + "@parcel/profiler@npm:2.16.3": version: 2.16.3 resolution: "@parcel/profiler@npm:2.16.3" @@ -4658,6 +5037,18 @@ __metadata: languageName: node linkType: hard +"@parcel/profiler@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/profiler@npm:2.16.4" + dependencies: + "@parcel/diagnostic": "npm:2.16.4" + "@parcel/events": "npm:2.16.4" + "@parcel/types-internal": "npm:2.16.4" + chrome-trace-event: "npm:^1.0.2" + checksum: 10c0/6bf98ce14059bc96f1a4261dd4bdc7edd246660646db8492702d68ca78d47d502795fb39d04595fea586221a1e6431b7f18a69d7b1febe062eff077504865ba3 + languageName: node + linkType: hard + "@parcel/reporter-bundle-analyzer@npm:^2.16.3": version: 2.16.3 resolution: "@parcel/reporter-bundle-analyzer@npm:2.16.3" @@ -4816,6 +5207,13 @@ __metadata: languageName: node linkType: hard +"@parcel/rust-darwin-arm64@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/rust-darwin-arm64@npm:2.16.4" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@parcel/rust-darwin-x64@npm:2.16.3": version: 2.16.3 resolution: "@parcel/rust-darwin-x64@npm:2.16.3" @@ -4823,6 +5221,13 @@ __metadata: languageName: node linkType: hard +"@parcel/rust-darwin-x64@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/rust-darwin-x64@npm:2.16.4" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@parcel/rust-linux-arm-gnueabihf@npm:2.16.3": version: 2.16.3 resolution: "@parcel/rust-linux-arm-gnueabihf@npm:2.16.3" @@ -4830,6 +5235,13 @@ __metadata: languageName: node linkType: hard +"@parcel/rust-linux-arm-gnueabihf@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/rust-linux-arm-gnueabihf@npm:2.16.4" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + "@parcel/rust-linux-arm64-gnu@npm:2.16.3": version: 2.16.3 resolution: "@parcel/rust-linux-arm64-gnu@npm:2.16.3" @@ -4837,6 +5249,13 @@ __metadata: languageName: node linkType: hard +"@parcel/rust-linux-arm64-gnu@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/rust-linux-arm64-gnu@npm:2.16.4" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + "@parcel/rust-linux-arm64-musl@npm:2.16.3": version: 2.16.3 resolution: "@parcel/rust-linux-arm64-musl@npm:2.16.3" @@ -4844,6 +5263,13 @@ __metadata: languageName: node linkType: hard +"@parcel/rust-linux-arm64-musl@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/rust-linux-arm64-musl@npm:2.16.4" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + "@parcel/rust-linux-x64-gnu@npm:2.16.3": version: 2.16.3 resolution: "@parcel/rust-linux-x64-gnu@npm:2.16.3" @@ -4851,6 +5277,13 @@ __metadata: languageName: node linkType: hard +"@parcel/rust-linux-x64-gnu@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/rust-linux-x64-gnu@npm:2.16.4" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + "@parcel/rust-linux-x64-musl@npm:2.16.3": version: 2.16.3 resolution: "@parcel/rust-linux-x64-musl@npm:2.16.3" @@ -4858,6 +5291,13 @@ __metadata: languageName: node linkType: hard +"@parcel/rust-linux-x64-musl@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/rust-linux-x64-musl@npm:2.16.4" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + "@parcel/rust-win32-x64-msvc@npm:2.16.3": version: 2.16.3 resolution: "@parcel/rust-win32-x64-msvc@npm:2.16.3" @@ -4865,6 +5305,13 @@ __metadata: languageName: node linkType: hard +"@parcel/rust-win32-x64-msvc@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/rust-win32-x64-msvc@npm:2.16.4" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@parcel/rust@npm:2.16.3, @parcel/rust@npm:^2.16.3": version: 2.16.3 resolution: "@parcel/rust@npm:2.16.3" @@ -4903,6 +5350,44 @@ __metadata: languageName: node linkType: hard +"@parcel/rust@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/rust@npm:2.16.4" + dependencies: + "@parcel/rust-darwin-arm64": "npm:2.16.4" + "@parcel/rust-darwin-x64": "npm:2.16.4" + "@parcel/rust-linux-arm-gnueabihf": "npm:2.16.4" + "@parcel/rust-linux-arm64-gnu": "npm:2.16.4" + "@parcel/rust-linux-arm64-musl": "npm:2.16.4" + "@parcel/rust-linux-x64-gnu": "npm:2.16.4" + "@parcel/rust-linux-x64-musl": "npm:2.16.4" + "@parcel/rust-win32-x64-msvc": "npm:2.16.4" + peerDependencies: + napi-wasm: ^1.1.2 + dependenciesMeta: + "@parcel/rust-darwin-arm64": + optional: true + "@parcel/rust-darwin-x64": + optional: true + "@parcel/rust-linux-arm-gnueabihf": + optional: true + "@parcel/rust-linux-arm64-gnu": + optional: true + "@parcel/rust-linux-arm64-musl": + optional: true + "@parcel/rust-linux-x64-gnu": + optional: true + "@parcel/rust-linux-x64-musl": + optional: true + "@parcel/rust-win32-x64-msvc": + optional: true + peerDependenciesMeta: + napi-wasm: + optional: true + checksum: 10c0/d45aff86dfed0c38a626b8ec7d9bfe21db7b77fa0d414e7779f61b01dcc9370e81b55b1255b3f03e386485e1aaf24674264ea118c1375455a31cb5268c537670 + languageName: node + linkType: hard + "@parcel/source-map@npm:^2.1.1": version: 2.1.1 resolution: "@parcel/source-map@npm:2.1.1" @@ -5172,6 +5657,18 @@ __metadata: languageName: node linkType: hard +"@parcel/types-internal@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/types-internal@npm:2.16.4" + dependencies: + "@parcel/diagnostic": "npm:2.16.4" + "@parcel/feature-flags": "npm:2.16.4" + "@parcel/source-map": "npm:^2.1.1" + utility-types: "npm:^3.11.0" + checksum: 10c0/65773f7218e27d3ed0cff231e151fb744e9f884c34927e6149502572b6c169afae838501544f74f53da22e0cdf5d4ebe5f2e0c093d74befa370464c9e47af940 + languageName: node + linkType: hard + "@parcel/types@npm:2.16.3": version: 2.16.3 resolution: "@parcel/types@npm:2.16.3" @@ -5182,6 +5679,16 @@ __metadata: languageName: node linkType: hard +"@parcel/types@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/types@npm:2.16.4" + dependencies: + "@parcel/types-internal": "npm:2.16.4" + "@parcel/workers": "npm:2.16.4" + checksum: 10c0/38092b5c04e008be55f07d27addc1e739b37076ab80a3d4f7023f4abda5916f25f6ad73c1a5d16e9f49f8e4a3c217aeffc4cb67e86ecb18cd76623596845292c + languageName: node + linkType: hard + "@parcel/utils@npm:2.16.3, @parcel/utils@npm:^2.16.3": version: 2.16.3 resolution: "@parcel/utils@npm:2.16.3" @@ -5198,6 +5705,22 @@ __metadata: languageName: node linkType: hard +"@parcel/utils@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/utils@npm:2.16.4" + dependencies: + "@parcel/codeframe": "npm:2.16.4" + "@parcel/diagnostic": "npm:2.16.4" + "@parcel/logger": "npm:2.16.4" + "@parcel/markdown-ansi": "npm:2.16.4" + "@parcel/rust": "npm:2.16.4" + "@parcel/source-map": "npm:^2.1.1" + chalk: "npm:^4.1.2" + nullthrows: "npm:^1.1.1" + checksum: 10c0/bd357ec36a0a08a4a539640992c300de29c97107901e3ace0c809d4ccc324651f0b5b7a40da7637d4147fa22f4ff36ed424d7f1cd77b0796573b7d59614d0b60 + languageName: node + linkType: hard + "@parcel/watcher-android-arm64@npm:2.5.1": version: 2.5.1 resolution: "@parcel/watcher-android-arm64@npm:2.5.1" @@ -5353,8 +5876,24 @@ __metadata: "@parcel/utils": "npm:2.16.3" nullthrows: "npm:^1.1.1" peerDependencies: - "@parcel/core": ^2.16.3 - checksum: 10c0/75a051d955ca9b6e58b93d0170638097bc1a8e979f9b952f5ec95addb3a00e05d339d7ee3b124ab55ef0709aef30d587b0fd2a493007055b2db26b4a289b6f8f + "@parcel/core": ^2.16.3 + checksum: 10c0/75a051d955ca9b6e58b93d0170638097bc1a8e979f9b952f5ec95addb3a00e05d339d7ee3b124ab55ef0709aef30d587b0fd2a493007055b2db26b4a289b6f8f + languageName: node + linkType: hard + +"@parcel/workers@npm:2.16.4": + version: 2.16.4 + resolution: "@parcel/workers@npm:2.16.4" + dependencies: + "@parcel/diagnostic": "npm:2.16.4" + "@parcel/logger": "npm:2.16.4" + "@parcel/profiler": "npm:2.16.4" + "@parcel/types-internal": "npm:2.16.4" + "@parcel/utils": "npm:2.16.4" + nullthrows: "npm:^1.1.1" + peerDependencies: + "@parcel/core": ^2.16.4 + checksum: 10c0/a04f9d1ed767806be4ced7e386ace797e2a32795f8de7fc18c4164638e781473f97bd720b716b72f40a48e06192d361bba63333bf0c72940b4ca0167c7d7f2e8 languageName: node linkType: hard @@ -5372,6 +5911,13 @@ __metadata: languageName: node linkType: hard +"@polka/url@npm:^1.0.0-next.24": + version: 1.0.0-next.29 + resolution: "@polka/url@npm:1.0.0-next.29" + checksum: 10c0/0d58e081844095cb029d3c19a659bfefd09d5d51a2f791bc61eba7ea826f13d6ee204a8a448c2f5a855c17df07b37517373ff916dd05801063c0568ae9937684 + languageName: node + linkType: hard + "@react-aria/actiongroup@npm:^3.7.24, @react-aria/actiongroup@workspace:packages/@react-aria/actiongroup": version: 0.0.0-use.local resolution: "@react-aria/actiongroup@workspace:packages/@react-aria/actiongroup" @@ -7550,7 +8096,6 @@ __metadata: "@testing-library/react": "npm:^16.0.0" "@testing-library/user-event": "npm:^14.0.0" csstype: "npm:^3.0.2" - jest: "npm:^29.5.0" react-aria: "npm:^3.47.0" react-aria-components: "npm:^1.16.0" react-stately: "npm:^3.45.0" @@ -8958,6 +9503,204 @@ __metadata: languageName: unknown linkType: soft +"@rolldown/pluginutils@npm:1.0.0-rc.3": + version: 1.0.0-rc.3 + resolution: "@rolldown/pluginutils@npm:1.0.0-rc.3" + checksum: 10c0/3928b6282a30f307d1b075d2f217180ae173ea9e00638ce46ab65f089bd5f7a0b2c488ae1ce530f509387793c656a2910337c4cd68fa9d37d7e439365989e699 + languageName: node + linkType: hard + +"@rollup/pluginutils@npm:^5.2.0": + version: 5.3.0 + resolution: "@rollup/pluginutils@npm:5.3.0" + dependencies: + "@types/estree": "npm:^1.0.0" + estree-walker: "npm:^2.0.2" + picomatch: "npm:^4.0.2" + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 10c0/001834bf62d7cf5bac424d2617c113f7f7d3b2bf3c1778cbcccb72cdc957b68989f8e7747c782c2b911f1dde8257f56f8ac1e779e29e74e638e3f1e2cac2bcd0 + languageName: node + linkType: hard + +"@rollup/rollup-android-arm-eabi@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.59.0" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@rollup/rollup-android-arm64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-android-arm64@npm:4.59.0" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-arm64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-darwin-arm64@npm:4.59.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-x64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-darwin-x64@npm:4.59.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-freebsd-arm64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.59.0" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-freebsd-x64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-freebsd-x64@npm:4.59.0" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-gnueabihf@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.59.0" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-musleabihf@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.59.0" + conditions: os=linux & cpu=arm & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.59.0" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.59.0" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-loong64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-loong64-gnu@npm:4.59.0" + conditions: os=linux & cpu=loong64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-loong64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-loong64-musl@npm:4.59.0" + conditions: os=linux & cpu=loong64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-ppc64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.59.0" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-ppc64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-ppc64-musl@npm:4.59.0" + conditions: os=linux & cpu=ppc64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.59.0" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.59.0" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-s390x-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.59.0" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.59.0" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.59.0" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-openbsd-x64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-openbsd-x64@npm:4.59.0" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-openharmony-arm64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-openharmony-arm64@npm:4.59.0" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-arm64-msvc@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.59.0" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-ia32-msvc@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.59.0" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-win32-x64-gnu@npm:4.59.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-msvc@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.59.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@rtsao/scc@npm:^1.1.0": version: 1.1.0 resolution: "@rtsao/scc@npm:1.1.0" @@ -9136,6 +9879,13 @@ __metadata: languageName: unknown linkType: soft +"@standard-schema/spec@npm:^1.0.0": + version: 1.1.0 + resolution: "@standard-schema/spec@npm:1.1.0" + checksum: 10c0/d90f55acde4b2deb983529c87e8025fa693de1a5e8b49ecc6eb84d1fd96328add0e03d7d551442156c7432fd78165b2c26ff561b970a9a881f046abb78d6a526 + languageName: node + linkType: hard + "@storybook/addon-a11y@npm:^9.0.18": version: 9.1.17 resolution: "@storybook/addon-a11y@npm:9.1.17" @@ -9773,6 +10523,22 @@ __metadata: languageName: node linkType: hard +"@testing-library/dom@npm:^10.4.1": + version: 10.4.1 + resolution: "@testing-library/dom@npm:10.4.1" + dependencies: + "@babel/code-frame": "npm:^7.10.4" + "@babel/runtime": "npm:^7.12.5" + "@types/aria-query": "npm:^5.0.1" + aria-query: "npm:5.3.0" + dom-accessibility-api: "npm:^0.5.9" + lz-string: "npm:^1.5.0" + picocolors: "npm:1.1.1" + pretty-format: "npm:^27.0.2" + checksum: 10c0/19ce048012d395ad0468b0dbcc4d0911f6f9e39464d7a8464a587b29707eed5482000dad728f5acc4ed314d2f4d54f34982999a114d2404f36d048278db815b1 + languageName: node + linkType: hard + "@testing-library/jest-dom@npm:^5.16.4, @testing-library/jest-dom@npm:^5.16.5": version: 5.17.0 resolution: "@testing-library/jest-dom@npm:5.17.0" @@ -9926,7 +10692,7 @@ __metadata: languageName: node linkType: hard -"@types/babel__core@npm:^7.1.14": +"@types/babel__core@npm:^7.1.14, @types/babel__core@npm:^7.20.5": version: 7.20.5 resolution: "@types/babel__core@npm:7.20.5" dependencies: @@ -10016,6 +10782,13 @@ __metadata: languageName: node linkType: hard +"@types/estree@npm:1.0.8, @types/estree@npm:^1.0.0": + version: 1.0.8 + resolution: "@types/estree@npm:1.0.8" + checksum: 10c0/39d34d1afaa338ab9763f37ad6066e3f349444f9052b9676a7cc0252ef9485a41c6d81c9c4e0d26e9077993354edf25efc853f3224dd4b447175ef62bdcc86a5 + languageName: node + linkType: hard + "@types/estree@npm:^0.0.46": version: 0.0.46 resolution: "@types/estree@npm:0.0.46" @@ -10030,13 +10803,6 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:^1.0.0": - version: 1.0.8 - resolution: "@types/estree@npm:1.0.8" - checksum: 10c0/39d34d1afaa338ab9763f37ad6066e3f349444f9052b9676a7cc0252ef9485a41c6d81c9c4e0d26e9077993354edf25efc853f3224dd4b447175ef62bdcc86a5 - languageName: node - linkType: hard - "@types/extend@npm:^3.0.0": version: 3.0.1 resolution: "@types/extend@npm:3.0.1" @@ -10880,6 +11646,70 @@ __metadata: languageName: node linkType: hard +"@vitejs/plugin-react@npm:^5.1.4": + version: 5.1.4 + resolution: "@vitejs/plugin-react@npm:5.1.4" + dependencies: + "@babel/core": "npm:^7.29.0" + "@babel/plugin-transform-react-jsx-self": "npm:^7.27.1" + "@babel/plugin-transform-react-jsx-source": "npm:^7.27.1" + "@rolldown/pluginutils": "npm:1.0.0-rc.3" + "@types/babel__core": "npm:^7.20.5" + react-refresh: "npm:^0.18.0" + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + checksum: 10c0/dd7b8f40717ecd4a5ab18f467134ea8135f9a443359333d71e4114aeacfc8b679be9fd36dc12290d076c78883a02e708bfe1f0d93411c06c9659da0879b952e3 + languageName: node + linkType: hard + +"@vitest/browser-playwright@npm:^4.0.17": + version: 4.0.18 + resolution: "@vitest/browser-playwright@npm:4.0.18" + dependencies: + "@vitest/browser": "npm:4.0.18" + "@vitest/mocker": "npm:4.0.18" + tinyrainbow: "npm:^3.0.3" + peerDependencies: + playwright: "*" + vitest: 4.0.18 + peerDependenciesMeta: + playwright: + optional: false + checksum: 10c0/505fafe6f957d020b74914ed328de57cba0be65ff82810da85297523776a0d7389669660e58734a416fc09ce262632b4d2cf257a9e8ab1115b695d133bba7bb5 + languageName: node + linkType: hard + +"@vitest/browser-preview@npm:^4.0.17": + version: 4.0.18 + resolution: "@vitest/browser-preview@npm:4.0.18" + dependencies: + "@testing-library/dom": "npm:^10.4.1" + "@testing-library/user-event": "npm:^14.6.1" + "@vitest/browser": "npm:4.0.18" + peerDependencies: + vitest: 4.0.18 + checksum: 10c0/8ca2f4b8b81555e55d660de3b4dce6bfe9a2e98ea3e42634423720dd77b00c8fefb537da8ba2c182f1eef9b31e1a30e3f87e6a21b4c0c677cbed274ac4f488a3 + languageName: node + linkType: hard + +"@vitest/browser@npm:4.0.18": + version: 4.0.18 + resolution: "@vitest/browser@npm:4.0.18" + dependencies: + "@vitest/mocker": "npm:4.0.18" + "@vitest/utils": "npm:4.0.18" + magic-string: "npm:^0.30.21" + pixelmatch: "npm:7.1.0" + pngjs: "npm:^7.0.0" + sirv: "npm:^3.0.2" + tinyrainbow: "npm:^3.0.3" + ws: "npm:^8.18.3" + peerDependencies: + vitest: 4.0.18 + checksum: 10c0/6b7bda92fa2e8c68de3e51c97322161484c3f1dd7a7417cdeabb4f1d98eab7dba96c156ac4282ea537c58d55cc0e5959abb4b9d90d3823b3cc3071c3f7460633 + languageName: node + linkType: hard + "@vitest/expect@npm:3.2.4": version: 3.2.4 resolution: "@vitest/expect@npm:3.2.4" @@ -10893,6 +11723,20 @@ __metadata: languageName: node linkType: hard +"@vitest/expect@npm:4.0.18": + version: 4.0.18 + resolution: "@vitest/expect@npm:4.0.18" + dependencies: + "@standard-schema/spec": "npm:^1.0.0" + "@types/chai": "npm:^5.2.2" + "@vitest/spy": "npm:4.0.18" + "@vitest/utils": "npm:4.0.18" + chai: "npm:^6.2.1" + tinyrainbow: "npm:^3.0.3" + checksum: 10c0/123b0aa111682e82ec5289186df18037b1a1768700e468ee0f9879709aaa320cf790463c15c0d8ee10df92b402f4394baf5d27797e604d78e674766d87bcaadc + languageName: node + linkType: hard + "@vitest/mocker@npm:3.2.4": version: 3.2.4 resolution: "@vitest/mocker@npm:3.2.4" @@ -10912,6 +11756,25 @@ __metadata: languageName: node linkType: hard +"@vitest/mocker@npm:4.0.18": + version: 4.0.18 + resolution: "@vitest/mocker@npm:4.0.18" + dependencies: + "@vitest/spy": "npm:4.0.18" + estree-walker: "npm:^3.0.3" + magic-string: "npm:^0.30.21" + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + checksum: 10c0/fb0a257e7e167759d4ad228d53fa7bad2267586459c4a62188f2043dd7163b4b02e1e496dc3c227837f776e7d73d6c4343613e89e7da379d9d30de8260f1ee4b + languageName: node + linkType: hard + "@vitest/pretty-format@npm:3.2.4": version: 3.2.4 resolution: "@vitest/pretty-format@npm:3.2.4" @@ -10921,6 +11784,36 @@ __metadata: languageName: node linkType: hard +"@vitest/pretty-format@npm:4.0.18": + version: 4.0.18 + resolution: "@vitest/pretty-format@npm:4.0.18" + dependencies: + tinyrainbow: "npm:^3.0.3" + checksum: 10c0/0086b8c88eeca896d8e4b98fcdef452c8041a1b63eb9e85d3e0bcc96c8aa76d8e9e0b6990ebb0bb0a697c4ebab347e7735888b24f507dbff2742ddce7723fd94 + languageName: node + linkType: hard + +"@vitest/runner@npm:4.0.18": + version: 4.0.18 + resolution: "@vitest/runner@npm:4.0.18" + dependencies: + "@vitest/utils": "npm:4.0.18" + pathe: "npm:^2.0.3" + checksum: 10c0/fdb4afa411475133c05ba266c8092eaf1e56cbd5fb601f92ec6ccb9bab7ca52e06733ee8626599355cba4ee71cb3a8f28c84d3b69dc972e41047edc50229bc01 + languageName: node + linkType: hard + +"@vitest/snapshot@npm:4.0.18": + version: 4.0.18 + resolution: "@vitest/snapshot@npm:4.0.18" + dependencies: + "@vitest/pretty-format": "npm:4.0.18" + magic-string: "npm:^0.30.21" + pathe: "npm:^2.0.3" + checksum: 10c0/d3bfefa558db9a69a66886ace6575eb96903a5ba59f4d9a5d0fecb4acc2bb8dbb443ef409f5ac1475f2e1add30bd1d71280f98912da35e89c75829df9e84ea43 + languageName: node + linkType: hard + "@vitest/spy@npm:3.2.4": version: 3.2.4 resolution: "@vitest/spy@npm:3.2.4" @@ -10930,6 +11823,13 @@ __metadata: languageName: node linkType: hard +"@vitest/spy@npm:4.0.18": + version: 4.0.18 + resolution: "@vitest/spy@npm:4.0.18" + checksum: 10c0/6de537890b3994fcadb8e8d8ac05942320ae184f071ec395d978a5fba7fa928cbb0c5de85af86a1c165706c466e840de8779eaff8c93450c511c7abaeb9b8a4e + languageName: node + linkType: hard + "@vitest/utils@npm:3.2.4": version: 3.2.4 resolution: "@vitest/utils@npm:3.2.4" @@ -10941,6 +11841,16 @@ __metadata: languageName: node linkType: hard +"@vitest/utils@npm:4.0.18": + version: 4.0.18 + resolution: "@vitest/utils@npm:4.0.18" + dependencies: + "@vitest/pretty-format": "npm:4.0.18" + tinyrainbow: "npm:^3.0.3" + checksum: 10c0/4a3c43c1421eb90f38576926496f6c80056167ba111e63f77cf118983902673737a1a38880b890d7c06ec0a12475024587344ee502b3c43093781533022f2aeb + languageName: node + linkType: hard + "@vueless/storybook-dark-mode@npm:^9.0.6": version: 9.0.10 resolution: "@vueless/storybook-dark-mode@npm:9.0.10" @@ -12678,6 +13588,13 @@ __metadata: languageName: node linkType: hard +"chai@npm:^6.2.1": + version: 6.2.2 + resolution: "chai@npm:6.2.2" + checksum: 10c0/e6c69e5f0c11dffe6ea13d0290936ebb68fcc1ad688b8e952e131df6a6d5797d5e860bc55cef1aca2e950c3e1f96daf79e9d5a70fb7dbaab4e46355e2635ed53 + languageName: node + linkType: hard + "chalk@npm:^1.1.3": version: 1.1.3 resolution: "chalk@npm:1.1.3" @@ -14978,6 +15895,13 @@ __metadata: languageName: node linkType: hard +"es-module-lexer@npm:^1.7.0": + version: 1.7.0 + resolution: "es-module-lexer@npm:1.7.0" + checksum: 10c0/4c935affcbfeba7fb4533e1da10fa8568043df1e3574b869385980de9e2d475ddc36769891936dbb07036edb3c3786a8b78ccf44964cd130dedc1f2c984b6c7b + languageName: node + linkType: hard + "es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1": version: 1.1.1 resolution: "es-object-atoms@npm:1.1.1" @@ -15135,7 +16059,96 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 10c0/aba8cbc11927fa77562722ed5e95541ce2853f67ad7bdc40382b558abc2e0ec57d92ffb820f082ba2047b4ef9f3bc3da068cdebe30dfd3850cfa3827a78d604e + checksum: 10c0/aba8cbc11927fa77562722ed5e95541ce2853f67ad7bdc40382b558abc2e0ec57d92ffb820f082ba2047b4ef9f3bc3da068cdebe30dfd3850cfa3827a78d604e + languageName: node + linkType: hard + +"esbuild@npm:^0.27.0": + version: 0.27.3 + resolution: "esbuild@npm:0.27.3" + dependencies: + "@esbuild/aix-ppc64": "npm:0.27.3" + "@esbuild/android-arm": "npm:0.27.3" + "@esbuild/android-arm64": "npm:0.27.3" + "@esbuild/android-x64": "npm:0.27.3" + "@esbuild/darwin-arm64": "npm:0.27.3" + "@esbuild/darwin-x64": "npm:0.27.3" + "@esbuild/freebsd-arm64": "npm:0.27.3" + "@esbuild/freebsd-x64": "npm:0.27.3" + "@esbuild/linux-arm": "npm:0.27.3" + "@esbuild/linux-arm64": "npm:0.27.3" + "@esbuild/linux-ia32": "npm:0.27.3" + "@esbuild/linux-loong64": "npm:0.27.3" + "@esbuild/linux-mips64el": "npm:0.27.3" + "@esbuild/linux-ppc64": "npm:0.27.3" + "@esbuild/linux-riscv64": "npm:0.27.3" + "@esbuild/linux-s390x": "npm:0.27.3" + "@esbuild/linux-x64": "npm:0.27.3" + "@esbuild/netbsd-arm64": "npm:0.27.3" + "@esbuild/netbsd-x64": "npm:0.27.3" + "@esbuild/openbsd-arm64": "npm:0.27.3" + "@esbuild/openbsd-x64": "npm:0.27.3" + "@esbuild/openharmony-arm64": "npm:0.27.3" + "@esbuild/sunos-x64": "npm:0.27.3" + "@esbuild/win32-arm64": "npm:0.27.3" + "@esbuild/win32-ia32": "npm:0.27.3" + "@esbuild/win32-x64": "npm:0.27.3" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-arm64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/openharmony-arm64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10c0/fdc3f87a3f08b3ef98362f37377136c389a0d180fda4b8d073b26ba930cf245521db0a368f119cc7624bc619248fff1439f5811f062d853576f8ffa3df8ee5f1 languageName: node linkType: hard @@ -15553,6 +16566,13 @@ __metadata: languageName: node linkType: hard +"estree-walker@npm:^2.0.2": + version: 2.0.2 + resolution: "estree-walker@npm:2.0.2" + checksum: 10c0/53a6c54e2019b8c914dc395890153ffdc2322781acf4bd7d1a32d7aedc1710807bdcd866ac133903d5629ec601fbb50abe8c2e5553c7f5a0afdd9b6af6c945af + languageName: node + linkType: hard + "estree-walker@npm:^3.0.0, estree-walker@npm:^3.0.3": version: 3.0.3 resolution: "estree-walker@npm:3.0.3" @@ -15714,6 +16734,13 @@ __metadata: languageName: node linkType: hard +"expect-type@npm:^1.2.2": + version: 1.3.0 + resolution: "expect-type@npm:1.3.0" + checksum: 10c0/8412b3fe4f392c420ab41dae220b09700e4e47c639a29ba7ba2e83cc6cffd2b4926f7ac9e47d7e277e8f4f02acda76fd6931cb81fd2b382fa9477ef9ada953fd + languageName: node + linkType: hard + "expect@npm:^29.7.0": version: 29.7.0 resolution: "expect@npm:29.7.0" @@ -16021,6 +17048,18 @@ __metadata: languageName: node linkType: hard +"fdir@npm:^6.5.0": + version: 6.5.0 + resolution: "fdir@npm:6.5.0" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: 10c0/e345083c4306b3aed6cb8ec551e26c36bab5c511e99ea4576a16750ddc8d3240e63826cc624f5ae17ad4dc82e68a253213b60d556c11bfad064b7607847ed07f + languageName: node + linkType: hard + "fflate@npm:^0.7.3": version: 0.7.4 resolution: "fflate@npm:0.7.4" @@ -16565,6 +17604,16 @@ __metadata: languageName: node linkType: hard +"fsevents@npm:~2.3.3": + version: 2.3.3 + resolution: "fsevents@npm:2.3.3" + dependencies: + node-gyp: "npm:latest" + checksum: 10c0/a1f0c44595123ed717febbc478aa952e47adfc28e2092be66b8ab1635147254ca6cfe1df792a8997f22716d4cbafc73309899ff7bfac2ac3ad8cf2e4ecc3ec60 + conditions: os=darwin + languageName: node + linkType: hard + "fsevents@patch:fsevents@npm%3A2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin": version: 2.3.2 resolution: "fsevents@patch:fsevents@npm%3A2.3.2#optional!builtin::version=2.3.2&hash=df0bf1" @@ -16574,6 +17623,15 @@ __metadata: languageName: node linkType: hard +"fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": + version: 2.3.3 + resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" + dependencies: + node-gyp: "npm:latest" + conditions: os=darwin + languageName: node + linkType: hard + "function-bind@npm:^1.1.2": version: 1.1.2 resolution: "function-bind@npm:1.1.2" @@ -20680,7 +21738,7 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.30.17": +"magic-string@npm:^0.30.17, magic-string@npm:^0.30.21": version: 0.30.21 resolution: "magic-string@npm:0.30.21" dependencies: @@ -21970,6 +23028,13 @@ __metadata: languageName: node linkType: hard +"mrmime@npm:^2.0.0": + version: 2.0.1 + resolution: "mrmime@npm:2.0.1" + checksum: 10c0/af05afd95af202fdd620422f976ad67dc18e6ee29beb03dd1ce950ea6ef664de378e44197246df4c7cdd73d47f2e7143a6e26e473084b9e4aa2095c0ad1e1761 + languageName: node + linkType: hard + "ms@npm:2.0.0": version: 2.0.0 resolution: "ms@npm:2.0.0" @@ -22762,6 +23827,13 @@ __metadata: languageName: node linkType: hard +"obug@npm:^2.1.1": + version: 2.1.1 + resolution: "obug@npm:2.1.1" + checksum: 10c0/59dccd7de72a047e08f8649e94c1015ec72f94eefb6ddb57fb4812c4b425a813bc7e7cd30c9aca20db3c59abc3c85cc7a62bb656a968741d770f4e8e02bc2e78 + languageName: node + linkType: hard + "octokit-pagination-methods@npm:^1.1.0": version: 1.1.0 resolution: "octokit-pagination-methods@npm:1.1.0" @@ -23581,6 +24653,13 @@ __metadata: languageName: node linkType: hard +"pathe@npm:^2.0.3": + version: 2.0.3 + resolution: "pathe@npm:2.0.3" + checksum: 10c0/c118dc5a8b5c4166011b2b70608762e260085180bb9e33e80a50dcdb1e78c010b1624f4280c492c92b05fc276715a4c357d1f9edc570f8f1b3d90b6839ebaca1 + languageName: node + linkType: hard + "pathval@npm:^2.0.0": version: 2.0.0 resolution: "pathval@npm:2.0.0" @@ -23616,6 +24695,13 @@ __metadata: languageName: node linkType: hard +"picocolors@npm:1.1.1, picocolors@npm:^1.1.1": + version: 1.1.1 + resolution: "picocolors@npm:1.1.1" + checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 + languageName: node + linkType: hard + "picocolors@npm:^0.2.1": version: 0.2.1 resolution: "picocolors@npm:0.2.1" @@ -23630,13 +24716,6 @@ __metadata: languageName: node linkType: hard -"picocolors@npm:^1.1.1": - version: 1.1.1 - resolution: "picocolors@npm:1.1.1" - checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 - languageName: node - linkType: hard - "picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" @@ -23644,6 +24723,13 @@ __metadata: languageName: node linkType: hard +"picomatch@npm:^4.0.2, picomatch@npm:^4.0.3": + version: 4.0.3 + resolution: "picomatch@npm:4.0.3" + checksum: 10c0/9582c951e95eebee5434f59e426cddd228a7b97a0161a375aed4be244bd3fe8e3a31b846808ea14ef2c8a2527a6eeab7b3946a67d5979e81694654f939473ae2 + languageName: node + linkType: hard + "pify@npm:^2.0.0, pify@npm:^2.3.0": version: 2.3.0 resolution: "pify@npm:2.3.0" @@ -23735,6 +24821,17 @@ __metadata: languageName: node linkType: hard +"pixelmatch@npm:7.1.0": + version: 7.1.0 + resolution: "pixelmatch@npm:7.1.0" + dependencies: + pngjs: "npm:^7.0.0" + bin: + pixelmatch: bin/pixelmatch + checksum: 10c0/ff069f92edaa841ac9b58b0ab74e1afa1f3b5e770eea0218c96bac1da4e752f5f6b79a0f9c4ba6b02afb955d39b8c78bcc3cc884f8122b67a1f2efbbccbe1a73 + languageName: node + linkType: hard + "pkce-challenge@npm:^5.0.0": version: 5.0.0 resolution: "pkce-challenge@npm:5.0.0" @@ -23815,6 +24912,13 @@ __metadata: languageName: node linkType: hard +"pngjs@npm:^7.0.0": + version: 7.0.0 + resolution: "pngjs@npm:7.0.0" + checksum: 10c0/0d4c7a0fd476a9c33df7d0a2a73e1d56537628a668841f6995c2bca070cf30819f9254a64363266bc14ef2fee47659dd3b4f2b18eec7ab65143015139f497b38 + languageName: node + linkType: hard + "posix-character-classes@npm:^0.1.0": version: 0.1.1 resolution: "posix-character-classes@npm:0.1.1" @@ -24523,6 +25627,9 @@ __metadata: "@types/react": "npm:^19.0.0" "@types/react-dom": "npm:^19.0.0" "@typescript/native-preview": "npm:^7.0.0-dev.20251223.1" + "@vitejs/plugin-react": "npm:^5.1.4" + "@vitest/browser-playwright": "npm:^4.0.17" + "@vitest/browser-preview": "npm:^4.0.17" "@vueless/storybook-dark-mode": "npm:^9.0.6" "@yarnpkg/types": "npm:^4.0.0" autoprefixer: "npm:^9.6.0" @@ -24591,7 +25698,11 @@ __metadata: tempy: "npm:^0.5.0" typescript: "npm:^5.8.2" typescript-eslint: "npm:^8.38.0" + unplugin-parcel-macros: "npm:^0.1.1" verdaccio: "npm:^6.0.0" + vite-plugin-svgr: "npm:^4.5.0" + vitest: "npm:^4.0.17" + vitest-browser-react: "npm:^2.0.2" walk-object: "npm:^4.0.0" xml: "npm:^1.0.1" languageName: unknown @@ -25473,6 +26584,96 @@ __metadata: languageName: node linkType: hard +"rollup@npm:^4.43.0": + version: 4.59.0 + resolution: "rollup@npm:4.59.0" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.59.0" + "@rollup/rollup-android-arm64": "npm:4.59.0" + "@rollup/rollup-darwin-arm64": "npm:4.59.0" + "@rollup/rollup-darwin-x64": "npm:4.59.0" + "@rollup/rollup-freebsd-arm64": "npm:4.59.0" + "@rollup/rollup-freebsd-x64": "npm:4.59.0" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.59.0" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.59.0" + "@rollup/rollup-linux-arm64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-arm64-musl": "npm:4.59.0" + "@rollup/rollup-linux-loong64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-loong64-musl": "npm:4.59.0" + "@rollup/rollup-linux-ppc64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-ppc64-musl": "npm:4.59.0" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-riscv64-musl": "npm:4.59.0" + "@rollup/rollup-linux-s390x-gnu": "npm:4.59.0" + "@rollup/rollup-linux-x64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-x64-musl": "npm:4.59.0" + "@rollup/rollup-openbsd-x64": "npm:4.59.0" + "@rollup/rollup-openharmony-arm64": "npm:4.59.0" + "@rollup/rollup-win32-arm64-msvc": "npm:4.59.0" + "@rollup/rollup-win32-ia32-msvc": "npm:4.59.0" + "@rollup/rollup-win32-x64-gnu": "npm:4.59.0" + "@rollup/rollup-win32-x64-msvc": "npm:4.59.0" + "@types/estree": "npm:1.0.8" + fsevents: "npm:~2.3.2" + dependenciesMeta: + "@rollup/rollup-android-arm-eabi": + optional: true + "@rollup/rollup-android-arm64": + optional: true + "@rollup/rollup-darwin-arm64": + optional: true + "@rollup/rollup-darwin-x64": + optional: true + "@rollup/rollup-freebsd-arm64": + optional: true + "@rollup/rollup-freebsd-x64": + optional: true + "@rollup/rollup-linux-arm-gnueabihf": + optional: true + "@rollup/rollup-linux-arm-musleabihf": + optional: true + "@rollup/rollup-linux-arm64-gnu": + optional: true + "@rollup/rollup-linux-arm64-musl": + optional: true + "@rollup/rollup-linux-loong64-gnu": + optional: true + "@rollup/rollup-linux-loong64-musl": + optional: true + "@rollup/rollup-linux-ppc64-gnu": + optional: true + "@rollup/rollup-linux-ppc64-musl": + optional: true + "@rollup/rollup-linux-riscv64-gnu": + optional: true + "@rollup/rollup-linux-riscv64-musl": + optional: true + "@rollup/rollup-linux-s390x-gnu": + optional: true + "@rollup/rollup-linux-x64-gnu": + optional: true + "@rollup/rollup-linux-x64-musl": + optional: true + "@rollup/rollup-openbsd-x64": + optional: true + "@rollup/rollup-openharmony-arm64": + optional: true + "@rollup/rollup-win32-arm64-msvc": + optional: true + "@rollup/rollup-win32-ia32-msvc": + optional: true + "@rollup/rollup-win32-x64-gnu": + optional: true + "@rollup/rollup-win32-x64-msvc": + optional: true + fsevents: + optional: true + bin: + rollup: dist/bin/rollup + checksum: 10c0/f38742da34cfee5e899302615fa157aa77cb6a2a1495e5e3ce4cc9c540d3262e235bbe60caa31562bbfe492b01fdb3e7a8c43c39d842d3293bcf843123b766fc + languageName: node + linkType: hard + "route-manifest@npm:^1.0.0": version: 1.0.0 resolution: "route-manifest@npm:1.0.0" @@ -26024,6 +27225,13 @@ __metadata: languageName: node linkType: hard +"siginfo@npm:^2.0.0": + version: 2.0.0 + resolution: "siginfo@npm:2.0.0" + checksum: 10c0/3def8f8e516fbb34cb6ae415b07ccc5d9c018d85b4b8611e3dc6f8be6d1899f693a4382913c9ed51a06babb5201639d76453ab297d1c54a456544acf5c892e34 + languageName: node + linkType: hard + "signal-exit@npm:^3.0.0, signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": version: 3.0.7 resolution: "signal-exit@npm:3.0.7" @@ -26047,6 +27255,17 @@ __metadata: languageName: node linkType: hard +"sirv@npm:^3.0.2": + version: 3.0.2 + resolution: "sirv@npm:3.0.2" + dependencies: + "@polka/url": "npm:^1.0.0-next.24" + mrmime: "npm:^2.0.0" + totalist: "npm:^3.0.0" + checksum: 10c0/5930e4397afdb14fbae13751c3be983af4bda5c9aadec832607dc2af15a7162f7d518c71b30e83ae3644b9a24cea041543cc969e5fe2b80af6ce8ea3174b2d04 + languageName: node + linkType: hard + "sisteransi@npm:^1.0.5": version: 1.0.5 resolution: "sisteransi@npm:1.0.5" @@ -26497,6 +27716,13 @@ __metadata: languageName: node linkType: hard +"stackback@npm:0.0.2": + version: 0.0.2 + resolution: "stackback@npm:0.0.2" + checksum: 10c0/89a1416668f950236dd5ac9f9a6b2588e1b9b62b1b6ad8dff1bfc5d1a15dbf0aafc9b52d2226d00c28dffff212da464eaeebfc6b7578b9d180cef3e3782c5983 + languageName: node + linkType: hard + "static-extend@npm:^0.1.1": version: 0.1.2 resolution: "static-extend@npm:0.1.2" @@ -26521,6 +27747,13 @@ __metadata: languageName: node linkType: hard +"std-env@npm:^3.10.0": + version: 3.10.0 + resolution: "std-env@npm:3.10.0" + checksum: 10c0/1814927a45004d36dde6707eaf17552a546769bc79a6421be2c16ce77d238158dfe5de30910b78ec30d95135cc1c59ea73ee22d2ca170f8b9753f84da34c427f + languageName: node + linkType: hard + "steno@npm:^0.4.1": version: 0.4.4 resolution: "steno@npm:0.4.4" @@ -27390,6 +28623,30 @@ __metadata: languageName: node linkType: hard +"tinybench@npm:^2.9.0": + version: 2.9.0 + resolution: "tinybench@npm:2.9.0" + checksum: 10c0/c3500b0f60d2eb8db65250afe750b66d51623057ee88720b7f064894a6cb7eb93360ca824a60a31ab16dab30c7b1f06efe0795b352e37914a9d4bad86386a20c + languageName: node + linkType: hard + +"tinyexec@npm:^1.0.2": + version: 1.0.2 + resolution: "tinyexec@npm:1.0.2" + checksum: 10c0/1261a8e34c9b539a9aae3b7f0bb5372045ff28ee1eba035a2a059e532198fe1a182ec61ac60fa0b4a4129f0c4c4b1d2d57355b5cb9aa2d17ac9454ecace502ee + languageName: node + linkType: hard + +"tinyglobby@npm:^0.2.15": + version: 0.2.15 + resolution: "tinyglobby@npm:0.2.15" + dependencies: + fdir: "npm:^6.5.0" + picomatch: "npm:^4.0.3" + checksum: 10c0/869c31490d0d88eedb8305d178d4c75e7463e820df5a9b9d388291daf93e8b1eb5de1dad1c1e139767e4269fe75f3b10d5009b2cc14db96ff98986920a186844 + languageName: node + linkType: hard + "tinyrainbow@npm:^2.0.0": version: 2.0.0 resolution: "tinyrainbow@npm:2.0.0" @@ -27397,6 +28654,13 @@ __metadata: languageName: node linkType: hard +"tinyrainbow@npm:^3.0.3": + version: 3.0.3 + resolution: "tinyrainbow@npm:3.0.3" + checksum: 10c0/1e799d35cd23cabe02e22550985a3051dc88814a979be02dc632a159c393a998628eacfc558e4c746b3006606d54b00bcdea0c39301133956d10a27aa27e988c + languageName: node + linkType: hard + "tinyspy@npm:^4.0.3": version: 4.0.4 resolution: "tinyspy@npm:4.0.4" @@ -27515,6 +28779,13 @@ __metadata: languageName: node linkType: hard +"totalist@npm:^3.0.0": + version: 3.0.1 + resolution: "totalist@npm:3.0.1" + checksum: 10c0/4bb1fadb69c3edbef91c73ebef9d25b33bbf69afe1e37ce544d5f7d13854cda15e47132f3e0dc4cafe300ddb8578c77c50a65004d8b6e97e77934a69aa924863 + languageName: node + linkType: hard + "tough-cookie@npm:^4.1.2": version: 4.1.2 resolution: "tough-cookie@npm:4.1.2" @@ -28356,6 +29627,90 @@ __metadata: languageName: node linkType: hard +"unplugin-parcel-macros-darwin-arm64@npm:0.1.1": + version: 0.1.1 + resolution: "unplugin-parcel-macros-darwin-arm64@npm:0.1.1" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"unplugin-parcel-macros-darwin-x64@npm:0.1.1": + version: 0.1.1 + resolution: "unplugin-parcel-macros-darwin-x64@npm:0.1.1" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"unplugin-parcel-macros-linux-arm64-gnu@npm:0.1.1": + version: 0.1.1 + resolution: "unplugin-parcel-macros-linux-arm64-gnu@npm:0.1.1" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"unplugin-parcel-macros-linux-arm64-musl@npm:0.1.1": + version: 0.1.1 + resolution: "unplugin-parcel-macros-linux-arm64-musl@npm:0.1.1" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"unplugin-parcel-macros-linux-x64-gnu@npm:0.1.1": + version: 0.1.1 + resolution: "unplugin-parcel-macros-linux-x64-gnu@npm:0.1.1" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"unplugin-parcel-macros-linux-x64-musl@npm:0.1.1": + version: 0.1.1 + resolution: "unplugin-parcel-macros-linux-x64-musl@npm:0.1.1" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"unplugin-parcel-macros-win32-x64-msvc@npm:0.1.1": + version: 0.1.1 + resolution: "unplugin-parcel-macros-win32-x64-msvc@npm:0.1.1" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"unplugin-parcel-macros@npm:^0.1.1": + version: 0.1.1 + resolution: "unplugin-parcel-macros@npm:0.1.1" + dependencies: + "@parcel/core": "npm:^2.12.0" + "@parcel/fs": "npm:^2.12.0" + "@parcel/package-manager": "npm:^2.12.0" + "@parcel/source-map": "npm:^2.1.1" + unplugin: "npm:^1.9.0" + unplugin-parcel-macros-darwin-arm64: "npm:0.1.1" + unplugin-parcel-macros-darwin-x64: "npm:0.1.1" + unplugin-parcel-macros-linux-arm64-gnu: "npm:0.1.1" + unplugin-parcel-macros-linux-arm64-musl: "npm:0.1.1" + unplugin-parcel-macros-linux-x64-gnu: "npm:0.1.1" + unplugin-parcel-macros-linux-x64-musl: "npm:0.1.1" + unplugin-parcel-macros-win32-x64-msvc: "npm:0.1.1" + dependenciesMeta: + unplugin-parcel-macros-darwin-arm64: + optional: true + unplugin-parcel-macros-darwin-x64: + optional: true + unplugin-parcel-macros-linux-arm64-gnu: + optional: true + unplugin-parcel-macros-linux-arm64-musl: + optional: true + unplugin-parcel-macros-linux-x64-gnu: + optional: true + unplugin-parcel-macros-linux-x64-musl: + optional: true + unplugin-parcel-macros-win32-x64-msvc: + optional: true + checksum: 10c0/9019036e04e38bbb2401d735c9c7365dc559d596a21760778bf0eeb9c454ebf0216053767b69bd5ac0b33e480a0aafb94f8cf5d79c6324e0698564c94cfad3ad + languageName: node + linkType: hard + "unplugin@npm:^1.3.1, unplugin@npm:^1.4.0": version: 1.12.0 resolution: "unplugin@npm:1.12.0" @@ -28368,6 +29723,16 @@ __metadata: languageName: node linkType: hard +"unplugin@npm:^1.9.0": + version: 1.16.1 + resolution: "unplugin@npm:1.16.1" + dependencies: + acorn: "npm:^8.14.0" + webpack-virtual-modules: "npm:^0.6.2" + checksum: 10c0/dd5f8c5727d0135847da73cf03fb199107f1acf458167034886fda3405737dab871ad3926431b4f70e1e82cdac482ac1383cea4019d782a68515c8e3e611b6cc + languageName: node + linkType: hard + "unquote@npm:^1.1.0": version: 1.1.1 resolution: "unquote@npm:1.1.1" @@ -28840,6 +30205,151 @@ __metadata: languageName: node linkType: hard +"vite-plugin-svgr@npm:^4.5.0": + version: 4.5.0 + resolution: "vite-plugin-svgr@npm:4.5.0" + dependencies: + "@rollup/pluginutils": "npm:^5.2.0" + "@svgr/core": "npm:^8.1.0" + "@svgr/plugin-jsx": "npm:^8.1.0" + peerDependencies: + vite: ">=2.6.0" + checksum: 10c0/3e1959fec626bb4f5a8ec13ff15bc40ffbc1c0ff38149bebe3f37dc2d67ed1f276f129ff7983e06946cf712e19996affd9d6868aa7d20d8921d1fe4449109b55 + languageName: node + linkType: hard + +"vite@npm:^6.0.0 || ^7.0.0": + version: 7.3.1 + resolution: "vite@npm:7.3.1" + dependencies: + esbuild: "npm:^0.27.0" + fdir: "npm:^6.5.0" + fsevents: "npm:~2.3.3" + picomatch: "npm:^4.0.3" + postcss: "npm:^8.5.6" + rollup: "npm:^4.43.0" + tinyglobby: "npm:^0.2.15" + peerDependencies: + "@types/node": ^20.19.0 || >=22.12.0 + jiti: ">=1.21.0" + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: ">=0.54.8" + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + dependenciesMeta: + fsevents: + optional: true + peerDependenciesMeta: + "@types/node": + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + bin: + vite: bin/vite.js + checksum: 10c0/5c7548f5f43a23533e53324304db4ad85f1896b1bfd3ee32ae9b866bac2933782c77b350eb2b52a02c625c8ad1ddd4c000df077419410650c982cd97fde8d014 + languageName: node + linkType: hard + +"vitest-browser-react@npm:^2.0.2": + version: 2.0.5 + resolution: "vitest-browser-react@npm:2.0.5" + peerDependencies: + "@types/react": ^18.0.0 || ^19.0.0 + "@types/react-dom": ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + vitest: ^4.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/ae972fa20895c73622c2e724a2e2a716cc2a2e5148da19a60d1185323aeb5f5bd0653cfe3048d081bb086ee0efa68c0c360d28cdf42ddd8df6a5f2d17ffd0c9e + languageName: node + linkType: hard + +"vitest@npm:^4.0.17": + version: 4.0.18 + resolution: "vitest@npm:4.0.18" + dependencies: + "@vitest/expect": "npm:4.0.18" + "@vitest/mocker": "npm:4.0.18" + "@vitest/pretty-format": "npm:4.0.18" + "@vitest/runner": "npm:4.0.18" + "@vitest/snapshot": "npm:4.0.18" + "@vitest/spy": "npm:4.0.18" + "@vitest/utils": "npm:4.0.18" + es-module-lexer: "npm:^1.7.0" + expect-type: "npm:^1.2.2" + magic-string: "npm:^0.30.21" + obug: "npm:^2.1.1" + pathe: "npm:^2.0.3" + picomatch: "npm:^4.0.3" + std-env: "npm:^3.10.0" + tinybench: "npm:^2.9.0" + tinyexec: "npm:^1.0.2" + tinyglobby: "npm:^0.2.15" + tinyrainbow: "npm:^3.0.3" + vite: "npm:^6.0.0 || ^7.0.0" + why-is-node-running: "npm:^2.3.0" + peerDependencies: + "@edge-runtime/vm": "*" + "@opentelemetry/api": ^1.9.0 + "@types/node": ^20.0.0 || ^22.0.0 || >=24.0.0 + "@vitest/browser-playwright": 4.0.18 + "@vitest/browser-preview": 4.0.18 + "@vitest/browser-webdriverio": 4.0.18 + "@vitest/ui": 4.0.18 + happy-dom: "*" + jsdom: "*" + peerDependenciesMeta: + "@edge-runtime/vm": + optional: true + "@opentelemetry/api": + optional: true + "@types/node": + optional: true + "@vitest/browser-playwright": + optional: true + "@vitest/browser-preview": + optional: true + "@vitest/browser-webdriverio": + optional: true + "@vitest/ui": + optional: true + happy-dom: + optional: true + jsdom: + optional: true + bin: + vitest: vitest.mjs + checksum: 10c0/b913cd32032c95f29ff08c931f4b4c6fd6d2da498908d6770952c561a1b8d75c62499a1f04cadf82fb89cc0f9a33f29fb5dfdb899f6dbb27686a9d91571be5fa + languageName: node + linkType: hard + "w3c-xmlserializer@npm:^4.0.0": version: 4.0.0 resolution: "w3c-xmlserializer@npm:4.0.0" @@ -29098,6 +30608,18 @@ __metadata: languageName: node linkType: hard +"why-is-node-running@npm:^2.3.0": + version: 2.3.0 + resolution: "why-is-node-running@npm:2.3.0" + dependencies: + siginfo: "npm:^2.0.0" + stackback: "npm:0.0.2" + bin: + why-is-node-running: cli.js + checksum: 10c0/1cde0b01b827d2cf4cb11db962f3958b9175d5d9e7ac7361d1a7b0e2dc6069a263e69118bd974c4f6d0a890ef4eedfe34cf3d5167ec14203dbc9a18620537054 + languageName: node + linkType: hard + "wide-align@npm:^1.1.0": version: 1.1.5 resolution: "wide-align@npm:1.1.5" @@ -29285,7 +30807,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:^8.18.0": +"ws@npm:^8.18.0, ws@npm:^8.18.3": version: 8.19.0 resolution: "ws@npm:8.19.0" peerDependencies: From 2b09630fc192d170336b191654a2123b7c8148c6 Mon Sep 17 00:00:00 2001 From: Yihui Liao <44729383+yihuiliao@users.noreply.github.com> Date: Mon, 16 Mar 2026 10:56:50 -0700 Subject: [PATCH 2/2] feat: add highlight selection to S2 TreeView (#9769) * Merge branch 'main' into tree-section * feat: add highlight selection to TreeView * clean up * fixes * update comment * add highlight selection to docs * update hcm * update chromatic * fix forced colors error * add highlight selection to docs * export isPrevSelected from ListView * add link to jsdoc * export additional functions * update focus ring * add hcm back for focus ring * prevent focus ring from getting cut off when inside selected group --- .../s2/chromatic/TreeView.stories.tsx | 11 +- packages/@react-spectrum/s2/src/ListView.tsx | 4 +- packages/@react-spectrum/s2/src/TreeView.tsx | 246 ++++++++++++++---- packages/dev/s2-docs/pages/s2/TreeView.mdx | 4 +- 4 files changed, 206 insertions(+), 59 deletions(-) diff --git a/packages/@react-spectrum/s2/chromatic/TreeView.stories.tsx b/packages/@react-spectrum/s2/chromatic/TreeView.stories.tsx index b718f1702c0..9c152d539dd 100644 --- a/packages/@react-spectrum/s2/chromatic/TreeView.stories.tsx +++ b/packages/@react-spectrum/s2/chromatic/TreeView.stories.tsx @@ -143,7 +143,7 @@ export const TreeStatic: StoryObj = { render: (args) => }; -export const TreeSelection: StoryObj = { +export const TreeCheckboxSelection: StoryObj = { ...TreeStatic, args: { selectionMode: 'multiple', @@ -151,6 +151,15 @@ export const TreeSelection: StoryObj = { } }; +export const TreeHighlightSelection: StoryObj = { + ...TreeStatic, + args: { + selectionMode: 'multiple', + selectionStyle: 'highlight', + defaultSelectedKeys: ['projects-2', 'projects-3'] + } +}; + export const TreeDisableSelection: StoryObj = { ...TreeStatic, args: { diff --git a/packages/@react-spectrum/s2/src/ListView.tsx b/packages/@react-spectrum/s2/src/ListView.tsx index 6a201f6a84d..912dee58764 100644 --- a/packages/@react-spectrum/s2/src/ListView.tsx +++ b/packages/@react-spectrum/s2/src/ListView.tsx @@ -716,7 +716,7 @@ function isNextSelected(id: Key | undefined, state: ListState) { let keyAfter = state.collection.getKeyAfter(id); return keyAfter != null && state.selectionManager.isSelected(keyAfter); } -function isPrevSelected(id: Key | undefined, state: ListState) { +export function isPrevSelected(id: Key | undefined, state: ListState) { if (id == null || !state) { return false; } @@ -724,7 +724,7 @@ function isPrevSelected(id: Key | undefined, state: ListState) { return keyBefore != null && state.selectionManager.isSelected(keyBefore); } -function isFirstItem(id: Key | undefined, state: ListState) { +export function isFirstItem(id: Key | undefined, state: ListState) { if (id == null || !state) { return false; } diff --git a/packages/@react-spectrum/s2/src/TreeView.tsx b/packages/@react-spectrum/s2/src/TreeView.tsx index defed595152..3f0eebcb361 100644 --- a/packages/@react-spectrum/s2/src/TreeView.tsx +++ b/packages/@react-spectrum/s2/src/TreeView.tsx @@ -26,6 +26,7 @@ import { TreeItemContentProps, TreeLoadMoreItem, TreeLoadMoreItemProps, + TreeState, useContextProps, Virtualizer } from 'react-aria-components'; @@ -37,9 +38,9 @@ import {getAllowedOverrides, StylesPropWithHeight, UnsafeStyles} from './style-u import {IconContext} from './Icon'; // @ts-ignore import intlMessages from '../intl/*.json'; +import {isFirstItem, isPrevSelected} from './ListView'; import {ProgressCircle} from './ProgressCircle'; -import {raw} from '../style/style-macro' with {type: 'macro'}; -import React, {createContext, forwardRef, JSXElementConstructor, ReactElement, ReactNode, useRef} from 'react'; +import React, {createContext, forwardRef, JSXElementConstructor, ReactElement, ReactNode, useContext, useRef} from 'react'; import {Text, TextContext} from './Content'; import {useActionBarContainer} from './ActionBar'; import {useDOMRef} from '@react-spectrum/utils'; @@ -53,7 +54,15 @@ interface S2TreeProps { renderActionBar?: (selectedKeys: 'all' | Set) => ReactElement } -export interface TreeViewProps extends Omit, 'style' | 'className' | 'render' | 'onRowAction' | 'selectionBehavior' | 'onScroll' | 'onCellAction' | 'dragAndDropHooks' | keyof GlobalDOMAttributes>, UnsafeStyles, S2TreeProps { +interface TreeViewStyleProps { + /** + * How selection should be displayed. For guidance on when to use which option, refer to the [Spectrum](https://spectrum.adobe.com/page/tree-view/#Checkbox-or-highlight-selection-style) page. + * @default 'checkbox' + */ + selectionStyle?: 'highlight' | 'checkbox' +} + +export interface TreeViewProps extends Omit, 'style' | 'className' | 'render' | 'onRowAction' | 'selectionBehavior' | 'onScroll' | 'onCellAction' | 'dragAndDropHooks' | keyof GlobalDOMAttributes>, UnsafeStyles, S2TreeProps, TreeViewStyleProps { /** Spectrum-defined styles, returned by the `style()` macro. */ styles?: StylesPropWithHeight } @@ -109,11 +118,13 @@ const tree = style({ } }); +let InternalTreeViewContext = createContext<{selectionStyle?: 'highlight' | 'checkbox'}>({}); + /** * A tree view provides users with a way to navigate nested hierarchical information. */ export const TreeView = /*#__PURE__*/ (forwardRef as forwardRefType)(function TreeView(props: TreeViewProps, ref: DOMRef) { - let {children, UNSAFE_className, UNSAFE_style} = props; + let {children, selectionStyle = 'checkbox', UNSAFE_className, UNSAFE_style} = props; let scale = useScale(); let renderer; @@ -137,20 +148,22 @@ export const TreeView = /*#__PURE__*/ (forwardRef as forwardRefType)(function Tr rowHeight: scale === 'large' ? 50 : 40 }}> - 0 ? actionBarHeight + 8 : 0, - scrollPaddingBottom: actionBarHeight > 0 ? actionBarHeight + 8 : 0 - }} - className={tree} - selectionBehavior="toggle" - selectedKeys={selectedKeys} - defaultSelectedKeys={undefined} - onSelectionChange={onSelectionChange} - ref={scrollRef}> - {props.children} - + + 0 ? actionBarHeight + 8 : 0, + scrollPaddingBottom: actionBarHeight > 0 ? actionBarHeight + 8 : 0 + }} + className={tree} + selectionBehavior={selectionStyle === 'highlight' ? 'replace' : 'toggle'} + selectedKeys={selectedKeys} + defaultSelectedKeys={undefined} + onSelectionChange={onSelectionChange} + ref={scrollRef}> + {props.children} + + {actionBar} @@ -162,7 +175,7 @@ const rowBackgroundColor = { default: '--s2-container-bg', isFocusVisibleWithin: colorMix('gray-25', 'gray-900', 7), isHovered: colorMix('gray-25', 'gray-900', 7), - isPressed: colorMix('gray-25', 'gray-900', 10), + isPressed: colorMix('gray-25', 'gray-900', 7), isSelected: { default: colorMix('gray-25', 'gray-900', 7), isFocusVisibleWithin: colorMix('gray-25', 'gray-900', 10), @@ -175,6 +188,7 @@ const rowBackgroundColor = { } as const; const treeRow = style({ + outlineStyle: 'none', position: 'relative', display: 'flex', height: 40, @@ -186,7 +200,6 @@ const treeRow = style({ isSelected: baseColor('neutral'), forcedColors: 'ButtonText' }, - outlineStyle: 'none', cursor: { default: 'default', isLink: 'pointer' @@ -195,13 +208,11 @@ const treeRow = style({ type: 'backgroundColor', value: rowBackgroundColor }, - '--rowFocusIndicatorColor': { - type: 'outlineColor', - value: { - default: 'focus-ring', - forcedColors: 'Highlight' - } - } + '--borderRadiusTreeItem': { + type: 'borderTopStartRadius', + value: 'sm' + }, + borderRadius: 'sm' }); const treeCellGrid = style({ @@ -209,6 +220,7 @@ const treeCellGrid = style({ width: 'full', height: 'full', boxSizing: 'border-box', + borderRadius: 'sm', alignContent: 'center', alignItems: 'center', gridTemplateColumns: ['auto', 'auto', 'auto', 'auto', 'auto', '1fr', 'minmax(0, auto)', 'auto'], @@ -216,12 +228,19 @@ const treeCellGrid = style({ gridTemplateAreas: [ 'drag-handle checkbox level-padding expand-button icon content actions actionmenu' ], - backgroundColor: '--rowBackgroundColor', paddingEnd: 4, // account for any focus rings on the last item in the cell color: { isDisabled: { default: 'gray-400', forcedColors: 'GrayText' + }, + forcedColors: 'ButtonText', + selectionStyle: { + highlight: { + isSelected: { + forcedColors: 'HighlightText' + } + } } }, '--rowSelectedBorderColor': { @@ -238,6 +257,82 @@ const treeCellGrid = style({ default: 'focus-ring', forcedColors: 'Highlight' } + }, + '--borderColor': { + type: 'borderColor', + value: { + default: 'transparent', + selectionStyle: { + highlight: 'blue-900' + }, + forcedColors: 'ButtonBorder' + } + }, + forcedColorAdjust: 'none' +}); + +const treeRowBackground = style({ + position: 'absolute', + zIndex: -1, + inset: 0, + backgroundColor: { + default: '--rowBackgroundColor', + forcedColors: 'Background', + selectionStyle: { + highlight: { + default: '--rowBackgroundColor', + isSelected: { + default: colorMix('gray-25', 'blue-900', 10), + isHovered: colorMix('gray-25', 'blue-900', 15), + isPressed: colorMix('gray-25', 'blue-900', 15), + isFocusVisible: colorMix('gray-25', 'blue-900', 15), + forcedColors: 'Highlight' + } + } + } + }, + borderTopStartRadius: { + default: '--borderRadiusTreeItem', + isPreviousSelected: { + default: '--borderRadiusTreeItem', + isSelected: 'none' + } + }, + borderTopEndRadius: { + default: '--borderRadiusTreeItem', + isPreviousSelected: { + default: '--borderRadiusTreeItem', + isSelected: 'none' + } + }, + borderBottomStartRadius: { + default: '--borderRadiusTreeItem', + isNextSelected: { + default: '--borderRadiusTreeItem', + isSelected: 'none' + } + }, + borderBottomEndRadius: { + default: '--borderRadiusTreeItem', + isNextSelected: { + default: '--borderRadiusTreeItem', + isSelected: 'none' + } + }, + borderTopWidth: { + default: 1, + isPreviousSelected: 0 + }, + borderBottomWidth: { + default: 1, + isNextSelected: 0 + }, + borderStartWidth: 1, + borderEndWidth: 1, + borderStyle: 'solid', + borderColor: { + default: 'transparent', + isSelected: '--borderColor' } }); @@ -279,33 +374,63 @@ const treeActionMenu = style({ gridArea: 'actionmenu' }); -const treeRowFocusIndicator = raw(` - &:before { - content: ""; - display: inline-block; - position: sticky; - inset-inline-start: 0; - width: 3px; - height: 100%; - margin-inline-end: -3px; - margin-block-end: 1px; - z-index: 3; - background-color: var(--rowFocusIndicatorColor); - }` -); + +let treeRowFocusRing = style({ + ...focusRing(), + outlineOffset: -2, + outlineColor: { + default: 'focus-ring', + forcedColors: 'Highlight', + selectionStyle: { + highlight: { + default: 'focus-ring', + forcedColors: 'Highlight', + isSelected: { + default: 'focus-ring', + forcedColors: 'ButtonBorder' + } + } + } + }, + position: 'absolute', + inset: 0, + top: { + default: '[-1px]', + isFirstItem: 0 + }, + bottom: { + selectionStyle: { + checkbox: 0, + highlight: { + default: 0, + isNextSelected: '[-1px]', + isSelected: { + default: 0, + isNextSelected: 0 + } + } + } + }, + borderRadius: 'sm', + zIndex: 1, + pointerEvents: 'none' +}); export const TreeViewItem = (props: TreeViewItemProps): ReactNode => { let { href } = props; + let {selectionStyle} = useContext(InternalTreeViewContext); return ( treeRow({ ...renderProps, - isLink: !!href - }) + (renderProps.isFocusVisible ? ' ' + treeRowFocusIndicator : '')} /> + isLink: !!href, + selectionStyle, + isPreviousSelected: isPrevSelected(renderProps.id, renderProps.state) + })} /> ); }; @@ -320,19 +445,16 @@ export const TreeViewItemContent = (props: TreeViewItemContentProps): ReactNode } = props; let scale = useScale(); + let {selectionStyle} = useContext(InternalTreeViewContext); + return ( - {({isExpanded, hasChildItems, selectionMode, selectionBehavior, isDisabled, isSelected, id, state}) => { - let isNextSelected = false; - let isNextFocused = false; - let keyAfter = state.collection.getKeyAfter(id); - if (keyAfter != null) { - isNextSelected = state.selectionManager.isSelected(keyAfter); - } - let isFirst = state.collection.getFirstKey() === id; + {({isExpanded, hasChildItems, selectionMode, selectionBehavior, isDisabled, isSelected, id, state, isHovered, isFocusVisible}) => { return ( -
- {selectionMode !== 'none' && selectionBehavior === 'toggle' && ( +
+
+ {isFocusVisible &&
} + {selectionMode !== 'none' && selectionBehavior === 'toggle' && selectionStyle !== 'highlight' && ( // TODO: add transition?
@@ -459,3 +581,19 @@ function ExpandableRowChevron(props: ExpandableRowChevronProps) { ); } + +function isNextSelected(id: Key | undefined, state: TreeState) { + if (id == null || !state) { + return false; + } + let keyAfter = state.collection.getKeyAfter(id); + + // We need to skip non-item nodes because the selection manager will map non-item nodes to their parent before checking selection + let node = keyAfter ? state.collection.getItem(keyAfter) : null; + while (node && node.type !== 'item' && keyAfter) { + keyAfter = state.collection.getKeyAfter(keyAfter); + node = keyAfter ? state.collection.getItem(keyAfter) : null; + } + + return keyAfter != null && state.selectionManager.isSelected(keyAfter); +} diff --git a/packages/dev/s2-docs/pages/s2/TreeView.mdx b/packages/dev/s2-docs/pages/s2/TreeView.mdx index f8043e4e813..31cf9b89c46 100644 --- a/packages/dev/s2-docs/pages/s2/TreeView.mdx +++ b/packages/dev/s2-docs/pages/s2/TreeView.mdx @@ -14,7 +14,7 @@ export const description = 'Displays hierarchical data with selection and collap {docs.exports.TreeView.description} -```tsx render docs={docs.exports.TreeView} links={docs.links} props={['selectionMode']} initialProps={{selectionMode: 'multiple'}} type="s2" wide +```tsx render docs={docs.exports.TreeView} links={docs.links} props={['selectionMode', 'selectionStyle']} initialProps={{selectionMode: 'multiple', selectionStyle: 'checkbox'}} type="s2" wide "use client"; import {TreeView, TreeViewItem, TreeViewItemContent} from '@react-spectrum/s2'; import {style} from '@react-spectrum/s2/style' with {type: 'macro'}; @@ -305,7 +305,7 @@ import {style} from '@react-spectrum/s2/style' with {type: 'macro'}; Use the `selectionMode` prop to enable single or multiple selection. The selected items can be controlled via the `selectedKeys` prop, matching the `id` prop of the items. Return an [ActionBar](ActionBar) from `renderActionBar` to handle bulk actions, and use `onAction` for item navigation. Items can be disabled with the `isDisabled` prop. See the [selection guide](selection?component=Tree) for more details. -```tsx render docs={docs.exports.TreeView} links={docs.links} props={['selectionMode', 'disabledBehavior', 'disallowEmptySelection']} initialProps={{selectionMode: 'multiple'}} wide +```tsx render docs={docs.exports.TreeView} links={docs.links} props={['selectionMode', 'disabledBehavior', 'disallowEmptySelection', 'selectionStyle']} initialProps={{selectionMode: 'multiple', selectionStyle: 'checkbox'}} wide "use client"; import {TreeView, TreeViewItem, TreeViewItemContent, ActionBar, ActionButton, Text, type Selection} from '@react-spectrum/s2'; import Edit from '@react-spectrum/s2/icons/Edit';