diff --git a/package.json b/package.json index f8771242416..6b6bb4e9662 100644 --- a/package.json +++ b/package.json @@ -178,10 +178,10 @@ "postcss": "^8.4.24", "postcss-custom-properties": "^13.2.0", "postcss-import": "^15.1.0", - "react": "^19.1.0", - "react-dom": "^19.1.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", "react-frame-component": "^5.0.0", - "react-test-renderer": "^19.1.0", + "react-test-renderer": "^19.2.0", "recast": "^0.23", "recursive-readdir": "^2.2.2", "regenerator-runtime": "0.13.3", diff --git a/packages/@react-aria/collections/src/CollectionBuilder.tsx b/packages/@react-aria/collections/src/CollectionBuilder.tsx index e7585b8ab81..97ed76aaf1f 100644 --- a/packages/@react-aria/collections/src/CollectionBuilder.tsx +++ b/packages/@react-aria/collections/src/CollectionBuilder.tsx @@ -19,6 +19,7 @@ import {forwardRefType, Key, Node} from '@react-types/shared'; import {Hidden} from './Hidden'; import React, {createContext, ForwardedRef, forwardRef, JSX, ReactElement, ReactNode, useCallback, useContext, useMemo, useRef, useState} from 'react'; import {useIsSSR} from '@react-aria/ssr'; +import {useLayoutEffect} from '@react-aria/utils'; import {useSyncExternalStore as useSyncExternalStoreShim} from 'use-sync-external-store/shim/index.js'; const ShallowRenderContext = createContext(false); @@ -113,6 +114,23 @@ function useCollectionDocument>(cr return document.getCollection(); }, [document]); let collection = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot); + + // React 19.2 introduced activities, which when started as hidden on the dom can play funky with the collection + // To avoid this we force a one time re-render if the collection fails to populate + const [, forceStoreRerender] = useState(0); // simple state to force a re-render + useLayoutEffect(function forceRefreshCollection() { + // Do not do anything if the collection has been pre-populated successfully + if (collection.size > 0) { + return; + } + // Re-create the collection + const nextValue = getSnapshot(); + if (nextValue.size > 0) { + forceStoreRerender(c => c + 1); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [collection.size === 0]); // don't run effect once we have a populated collection + return {collection, document}; } diff --git a/packages/dev/docs/package.json b/packages/dev/docs/package.json index 70f8d3ea505..53e981002c4 100644 --- a/packages/dev/docs/package.json +++ b/packages/dev/docs/package.json @@ -29,8 +29,8 @@ "highlight.js": "9.18.1", "markdown-to-jsx": "^6.11.0", "quicklink": "^2.3.0", - "react": "^19.1.0", - "react-dom": "^19.1.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", "react-lowlight": "^2.0.0" }, "peerDependencies": { diff --git a/packages/dev/s2-docs/package.json b/packages/dev/s2-docs/package.json index 1c5b8f2d3da..dd974b856e3 100644 --- a/packages/dev/s2-docs/package.json +++ b/packages/dev/s2-docs/package.json @@ -49,10 +49,10 @@ "json5": "^2.2.3", "lz-string": "^1.5.0", "markdown-to-jsx": "^6.11.0", - "react": "^19", + "react": "^19.2.0", "react-aria": "^3.40.0", "react-aria-components": "^1.7.1", - "react-dom": "^19", + "react-dom": "^19.2.0", "react-stately": "^3.38.0", "remark-mdx": "^3.1.0", "remark-parse": "^11.0.0", diff --git a/packages/react-aria-components/test/ListBox.test.js b/packages/react-aria-components/test/ListBox.test.js index a46b9fc71aa..7649d06e188 100644 --- a/packages/react-aria-components/test/ListBox.test.js +++ b/packages/react-aria-components/test/ListBox.test.js @@ -1861,4 +1861,40 @@ describe('ListBox', () => { expect(onClick).toHaveBeenCalledTimes(1); }); }); + + if (React.version.startsWith('19')) { + it('supports Activity', async () => { + function ActivityListBox() { + let [mode, setMode] = React.useState('hidden'); + + return ( + <> + + + +

List should be visible

+ + + Item 1 + Item 2 + Item 3 + Item 4 + Item 5 + +
+ + ); + } + + let {getAllByRole, getByRole, queryAllByRole} = render(); + let button = getByRole('button'); + expect(queryAllByRole('option')).toHaveLength(0); + await user.click(button); + expect(getAllByRole('option')).toHaveLength(5); + await user.click(button); + expect(queryAllByRole('option')).toHaveLength(0); + }); + } }); diff --git a/packages/react-aria-components/test/Tabs.test.js b/packages/react-aria-components/test/Tabs.test.js index d05350f4267..f849387358d 100644 --- a/packages/react-aria-components/test/Tabs.test.js +++ b/packages/react-aria-components/test/Tabs.test.js @@ -641,4 +641,42 @@ describe('Tabs', () => { expect(onClick).toHaveBeenCalledTimes(1); }); }); + + if (React.version.startsWith('19')) { + it('supports Activity', async () => { + function ActivityTabs() { + let [mode, setMode] = React.useState('hidden'); + + return ( + <> + + + + + A + B + + C + Test + + + A + B + C + + + + ); + } + + let {getByRole, getAllByRole, queryAllByRole} = render(); + + let button = getByRole('button'); + expect(queryAllByRole('tab')).toHaveLength(0); + await user.click(button); + expect(getAllByRole('tab')).toHaveLength(3); + }); + } }); diff --git a/starters/docs/package.json b/starters/docs/package.json index 00a78daa303..ca577cdc6bd 100644 --- a/starters/docs/package.json +++ b/starters/docs/package.json @@ -27,16 +27,16 @@ "clsx": "^2.1.1", "lightningcss-loader": "^2.1.0", "lucide-react": "^0.517.0", - "react": "^19.1.0", + "react": "^19.2.0", "react-aria-components": "^1.14.0", - "react-dom": "^19.1.0", + "react-dom": "^19.2.0", "storybook": "^8.6.14", "storybook-dark-mode": "^4.0.2", "typescript": "^5.8.2" }, "resolutions": { - "react": "19.1.0", - "react-dom": "19.1.0", + "react": "19.2.0", + "react-dom": "19.2.0", "@types/mime": "3.0.4", "jackspeak": "2.1.1" } diff --git a/yarn.lock b/yarn.lock index 273906bc616..e3a09c04be5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6831,8 +6831,8 @@ __metadata: highlight.js: "npm:9.18.1" markdown-to-jsx: "npm:^6.11.0" quicklink: "npm:^2.3.0" - react: "npm:^19.1.0" - react-dom: "npm:^19.1.0" + react: "npm:^19.2.0" + react-dom: "npm:^19.2.0" react-lowlight: "npm:^2.0.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 @@ -7383,10 +7383,10 @@ __metadata: lz-string: "npm:^1.5.0" markdown-to-jsx: "npm:^6.11.0" playwright: "npm:^1.57.0" - react: "npm:^19" + react: "npm:^19.2.0" react-aria: "npm:^3.40.0" react-aria-components: "npm:^1.7.1" - react-dom: "npm:^19" + react-dom: "npm:^19.2.0" react-stately: "npm:^3.38.0" remark-mdx: "npm:^3.1.0" remark-parse: "npm:^11.0.0" @@ -24614,14 +24614,14 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0, react-dom@npm:^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0, react-dom@npm:^19, react-dom@npm:^19.1.0": - version: 19.1.0 - resolution: "react-dom@npm:19.1.0" +"react-dom@npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0, react-dom@npm:^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0, react-dom@npm:^19.2.0": + version: 19.2.1 + resolution: "react-dom@npm:19.2.1" dependencies: - scheduler: "npm:^0.26.0" + scheduler: "npm:^0.27.0" peerDependencies: - react: ^19.1.0 - checksum: 10c0/3e26e89bb6c67c9a6aa86cb888c7a7f8258f2e347a6d2a15299c17eb16e04c19194e3452bc3255bd34000a61e45e2cb51e46292392340432f133e5a5d2dfb5fc + react: ^19.2.1 + checksum: 10c0/e56b6b3d72314df580ca800b70a69a21c6372703c8f45d9b5451ca6519faefb2496d76ffa9c5adb94136d2bbf2fd303d0dfc208a2cd77ede3132877471af9470 languageName: node linkType: hard @@ -24805,10 +24805,10 @@ __metadata: postcss: "npm:^8.4.24" postcss-custom-properties: "npm:^13.2.0" postcss-import: "npm:^15.1.0" - react: "npm:^19.1.0" - react-dom: "npm:^19.1.0" + react: "npm:^19.2.0" + react-dom: "npm:^19.2.0" react-frame-component: "npm:^5.0.0" - react-test-renderer: "npm:^19.1.0" + react-test-renderer: "npm:^19.2.0" recast: "npm:^0.23" recursive-readdir: "npm:^2.2.2" regenerator-runtime: "npm:0.13.3" @@ -24894,17 +24894,10 @@ __metadata: languageName: node linkType: hard -"react@npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0, react@npm:^19, react@npm:^19.1.0": - version: 19.1.0 - resolution: "react@npm:19.1.0" - checksum: 10c0/530fb9a62237d54137a13d2cfb67a7db6a2156faed43eecc423f4713d9b20c6f2728b026b45e28fcd72e8eadb9e9ed4b089e99f5e295d2f0ad3134251bdd3698 - languageName: node - linkType: hard - -"react@npm:^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0": - version: 19.1.1 - resolution: "react@npm:19.1.1" - checksum: 10c0/8c9769a2dfd02e603af6445058325e6c8a24b47b185d0e461f66a6454765ddcaecb3f0a90184836c68bb509f3c38248359edbc42f0d07c23eb500a5c30c87b4e +"react@npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0, react@npm:^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0, react@npm:^19.2.0": + version: 19.2.1 + resolution: "react@npm:19.2.1" + checksum: 10c0/2b5eaf407abb3db84090434c20d6c5a8e447ab7abcd8fe9eaf1ddc299babcf31284ee9db7ea5671d21c85ac5298bd632fa1a7da1ed78d5b368a537f5e1cd5d62 languageName: node linkType: hard @@ -25889,6 +25882,13 @@ __metadata: languageName: node linkType: hard +"scheduler@npm:^0.27.0": + version: 0.27.0 + resolution: "scheduler@npm:0.27.0" + checksum: 10c0/4f03048cb05a3c8fddc45813052251eca00688f413a3cee236d984a161da28db28ba71bd11e7a3dd02f7af84ab28d39fb311431d3b3772fed557945beb00c452 + languageName: node + linkType: hard + "section-matter@npm:^1.0.0": version: 1.0.0 resolution: "section-matter@npm:1.0.0"