From 5de83cd87477e011969cc2faddb52c43a3965fcd Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Thu, 11 Dec 2025 11:31:25 -0800 Subject: [PATCH 1/7] docs: Use StackBlitz for S2, and remove CodeSandbox (#9321) * Add StackBlitz for S2 * Remove CodeSandbox for now * fix: stackblitz examples * Simplify --------- Co-authored-by: Robert Snow --- .../pages/react-aria/getting-started.mdx | 2 +- packages/dev/s2-docs/src/CodePlatter.tsx | 73 ++++++++++--------- packages/dev/s2-docs/src/StackBlitz.tsx | 15 ++-- 3 files changed, 49 insertions(+), 41 deletions(-) diff --git a/packages/dev/s2-docs/pages/react-aria/getting-started.mdx b/packages/dev/s2-docs/pages/react-aria/getting-started.mdx index df2fe12d6ab..a86caad5719 100644 --- a/packages/dev/s2-docs/pages/react-aria/getting-started.mdx +++ b/packages/dev/s2-docs/pages/react-aria/getting-started.mdx @@ -28,7 +28,7 @@ Install React Aria with your preferred package manager. ## Quick start -The documentation for each component includes vanilla CSS and [Tailwind](https://tailwindcss.com) examples. Copy and paste these into your project and make them your own. You can also download each example as a ZIP or open in CodeSandbox or StackBlitz. +The documentation for each component includes vanilla CSS and [Tailwind](https://tailwindcss.com) examples. Copy and paste these into your project and make them your own. You can also download each example as a ZIP or open in StackBlitz. ```tsx render docs={docs.exports.Select} links={docs.links} props={[]} type="vanilla" files={["starters/docs/src/Select.tsx", "starters/docs/src/Select.css"]} showCoachMark diff --git a/packages/dev/s2-docs/src/CodePlatter.tsx b/packages/dev/s2-docs/src/CodePlatter.tsx index 715a4432c80..654dd7a6398 100644 --- a/packages/dev/s2-docs/src/CodePlatter.tsx +++ b/packages/dev/s2-docs/src/CodePlatter.tsx @@ -2,15 +2,15 @@ import {ActionButton, ActionButtonGroup, Button, ButtonGroup, Content, createIcon, Dialog, DialogContainer, Heading, Link, Menu, MenuItem, MenuTrigger, Text, ToastQueue, Tooltip, TooltipTrigger} from '@react-spectrum/s2'; import {CopyButton} from './CopyButton'; -import {createCodeSandbox, getCodeSandboxFiles} from './CodeSandbox'; import {createStackBlitz} from './StackBlitz'; import Download from '@react-spectrum/s2/icons/Download'; import type {DownloadFiles} from './CodeBlock'; +import {getCodeSandboxFiles} from './CodeSandbox'; import {keyframes} from '../../../@react-spectrum/s2/style/style-macro' with {type: 'macro'}; import {Library} from './library'; import LinkIcon from '@react-spectrum/s2/icons/Link'; import OpenIn from '@react-spectrum/s2/icons/OpenIn'; -import Polygon4 from '@react-spectrum/s2/icons/Polygon4'; +// import Polygon4 from '@react-spectrum/s2/icons/Polygon4'; import Prompt from '@react-spectrum/s2/icons/Prompt'; import React, {createContext, ProviderProps, ReactNode, RefObject, useContext, useRef, useState} from 'react'; import {ShadcnCommand} from './ShadcnCommand'; @@ -72,7 +72,7 @@ export function ShareUrlProvider(props: ProviderProps) { export function CodePlatter({children, type, showCoachMark}: CodePlatterProps) { let codeRef = useRef(null); let [showShadcn, setShowShadcn] = useState(false); - let [showCodeSandbox, setShowCodeSandbox] = useState(false); + // let [showCodeSandbox, setShowCodeSandbox] = useState(false); let getText = () => codeRef.current!.querySelector('pre')!.textContent!; let {library} = useContext(CodePlatterContext); if (!type) { @@ -158,7 +158,7 @@ export function CodePlatter({children, type, showCoachMark}: CodePlatterProps) { Install with shadcn } - {files && + {/* {files && { setShowCodeSandbox(true); @@ -166,8 +166,8 @@ export function CodePlatter({children, type, showCoachMark}: CodePlatterProps) { Open in CodeSandbox - } - {files && type !== 's2' && + } */} + {files && { createStackBlitz(getExampleFiles(codeRef, files, urls, entry), deps, type, entry); @@ -192,11 +192,11 @@ export function CodePlatter({children, type, showCoachMark}: CodePlatterProps) {
{children}
- setShowCodeSandbox(false)}> + {/* setShowCodeSandbox(false)}> {showCodeSandbox && } - + */} setShowShadcn(false)}> {showShadcn && @@ -250,9 +250,12 @@ function getExampleCode(codeRef: RefObject, urls: {[name: } } - return code + if (!code.includes('export default function')) { // Export the last function - .replace(/\nfunction ([^(]+)((.|\n)+\n\}\n?)$/, '\nexport default function Example$2') + code = code.replace(/\nfunction ([^(]+)((.|\n)+\n\}\n?)$/, '\nexport default function Example$2'); + } + + return code // Add function wrapper around raw JSX in examples. .replace(/\n<((?:.|\n)+)/, (_, code) => { let res = '\nexport default function Example() {\n return (\n <'; @@ -319,31 +322,31 @@ function ShadcnDialog({registryUrl}) { ); } -function CodeSandboxDialog({getExampleFiles, codeRef, files, urls, entry, deps, type}) { - return ( - - {({close}) => (<> - Create a CodeSandbox - -

This will create an editable sandbox with this example in a new tab.

-

Troubleshooting: If the sandbox fails to open or isn't created, try logging in to CodeSandbox first. If you're already logged in, try signing out and back in.

-
- - - - - - )} -
- ); -} +// function CodeSandboxDialog({getExampleFiles, codeRef, files, urls, entry, deps, type}) { +// return ( +// +// {({close}) => (<> +// Create a CodeSandbox +// +//

This will create an editable sandbox with this example in a new tab.

+//

Troubleshooting: If the sandbox fails to open or isn't created, try logging in to CodeSandbox first. If you're already logged in, try signing out and back in.

+//
+ +// +// +// +// +// )} +//
+// ); +// } const pulseAnimation = keyframes(` 0% { diff --git a/packages/dev/s2-docs/src/StackBlitz.tsx b/packages/dev/s2-docs/src/StackBlitz.tsx index 7d4edaac323..eef2ecc5fdc 100644 --- a/packages/dev/s2-docs/src/StackBlitz.tsx +++ b/packages/dev/s2-docs/src/StackBlitz.tsx @@ -65,6 +65,7 @@ function getFiles( dependencies: { react: '^19', 'react-dom': '^19', + ...(type === 's2' ? {'@react-spectrum/s2': 'latest'} : {}), ...deps }, devDependencies: { @@ -77,17 +78,21 @@ function getFiles( '@tailwindcss/vite': '^4', 'tailwindcss-react-aria-components': '^2', 'tailwindcss-animate': '^1' + } : {}), + ...(type === 's2' ? { + 'unplugin-parcel-macros': '^0.1.2-alpha.1' } : {}) } }, null, 2) + '\n', 'vite.config.ts': `import {defineConfig} from 'vite'; -import react from '@vitejs/plugin-react';${type === 'tailwind' ? "\nimport tailwindcss from '@tailwindcss/vite';" : ''} +import react from '@vitejs/plugin-react';${type === 'tailwind' ? "\nimport tailwindcss from '@tailwindcss/vite';" : ''}${type === 's2' ? "\nimport macros from 'unplugin-parcel-macros';" : ''} export default defineConfig({ - plugins: [react()${type === 'tailwind' ? ', tailwindcss()' : ''}], + plugins: [${type === 's2' ? 'macros.vite(), ' : ''}react()${type === 'tailwind' ? ', tailwindcss()' : ''}], }); `, - 'index.html': ` + 'index.html': ` + Test @@ -99,10 +104,10 @@ export default defineConfig({ `, - 'src/index.tsx': `import {createRoot} from 'react-dom/client'; + 'src/index.tsx': `import {createRoot} from 'react-dom/client';${type === 's2' ? "\nimport '@react-spectrum/s2/page.css';\nimport {Provider} from '@react-spectrum/s2';" : ''} import ${entryName} from './${entryName}'; -createRoot(document.getElementById('root')!).render(<${entryName} />); +createRoot(document.getElementById('root')!).render(${type === 's2' ? `\n \n <${entryName} />\n \n` : `<${entryName} />`}); `, 'tsconfig.json': JSON.stringify({ compilerOptions: { From 950141c8193a874da3d0ddb872635d7a465ffc9f Mon Sep 17 00:00:00 2001 From: Reid Barber Date: Thu, 11 Dec 2025 13:49:27 -0600 Subject: [PATCH 2/7] fix RAC ExampleSwitcher rendering in markdown docs (#9333) --- .../s2-docs/scripts/generateMarkdownDocs.mjs | 292 +++++++++++++++--- 1 file changed, 250 insertions(+), 42 deletions(-) diff --git a/packages/dev/s2-docs/scripts/generateMarkdownDocs.mjs b/packages/dev/s2-docs/scripts/generateMarkdownDocs.mjs index d04e6c34772..6a52f9908d7 100644 --- a/packages/dev/s2-docs/scripts/generateMarkdownDocs.mjs +++ b/packages/dev/s2-docs/scripts/generateMarkdownDocs.mjs @@ -3,7 +3,6 @@ import * as babel from '@babel/parser'; import {fileURLToPath} from 'url'; import fs from 'fs'; -import {getBaseUrl} from '../src/pageUtils.ts'; import glob from 'fast-glob'; import path from 'path'; import {Project} from 'ts-morph'; @@ -13,6 +12,33 @@ import remarkStringify from 'remark-stringify'; import {unified} from 'unified'; import {visit} from 'unist-util-visit'; +const BASE_URL = { + dev: { + 'react-aria': 'http://localhost:1234', + 's2': 'http://localhost:4321' + }, + stage: { + 'react-aria': 'https://d5iwopk28bdhl.cloudfront.net', + 's2': 'https://d1pzu54gtk2aed.cloudfront.net' + }, + prod: { + 'react-aria': 'https://react-aria.adobe.com', + 's2': 'https://react-spectrum.adobe.com' + } +}; + +function getBaseUrl(library) { + let env = process.env.DOCS_ENV; + let base = env + ? BASE_URL[env][library] + : `http://localhost:1234/${library}`; + let publicUrl = process.env.PUBLIC_URL; + if (publicUrl) { + base += publicUrl.replace(/\/$/, ''); + } + return base; +} + const __dirname = path.dirname(fileURLToPath(import.meta.url)); const REPO_ROOT = path.resolve(__dirname, '../../../../'); const S2_SRC_ROOT = path.join(REPO_ROOT, 'packages/@react-spectrum/s2/src'); @@ -938,61 +964,243 @@ function remarkDocsComponentsToMarkdown() { exampleTitles = Array.isArray(parsed) ? parsed : []; } - // Fallback default titles when none were provided. - if (exampleTitles.length === 0) { - exampleTitles = ['Vanilla CSS', 'Tailwind']; - } - - // Children may include whitespace/text nodes – filter to VisualExample elements. const visualChildren = (node.children || []).filter(c => c.type === 'mdxJsxFlowElement' && c.name === 'VisualExample'); + const codeChildren = (node.children || []).filter(c => c.type === 'code'); // Build replacement markdown nodes. const newNodes = []; - visualChildren.forEach((vChild, i) => { - const title = exampleTitles[i] || `Example ${i + 1}`; - - // ## {title} example - newNodes.push({ - type: 'heading', - depth: 2, - children: [{type: 'text', value: `${title} example`}] - }); - - // Extract files attribute from VisualExample - const filesAttr = vChild.attributes?.find(a => a.name === 'files'); - let fileList = []; - if (filesAttr) { - if (filesAttr.value?.type === 'mdxJsxAttributeValueExpression') { - const parsed = parseExpression(filesAttr.value.value, file); - fileList = Array.isArray(parsed) ? parsed : []; - } else if (Array.isArray(filesAttr.value)) { - fileList = filesAttr.value; - } + if (visualChildren.length > 0) { + if (exampleTitles.length === 0) { + exampleTitles = ['Vanilla CSS', 'Tailwind']; } - fileList.forEach(fp => { - const absPath = path.join(REPO_ROOT, fp); - if (!fs.existsSync(absPath)) {return;} - const contents = fs.readFileSync(absPath, 'utf8'); - const ext = path.extname(fp).slice(1); + visualChildren.forEach((vChild, i) => { + const title = exampleTitles[i] || `Example ${i + 1}`; - // ### {filename} + // ## {title} example newNodes.push({ type: 'heading', - depth: 3, - children: [{type: 'text', value: path.basename(fp)}] + depth: 2, + children: [{type: 'text', value: `${title} example`}] }); - // ```{lang}\n{contents}\n``` - newNodes.push({ - type: 'code', - lang: ext || undefined, - meta: '', - value: contents + // Extract files attribute from VisualExample + const filesAttr = vChild.attributes?.find(a => a.name === 'files'); + let fileList = []; + if (filesAttr) { + if (filesAttr.value?.type === 'mdxJsxAttributeValueExpression') { + const parsed = parseExpression(filesAttr.value.value, file); + fileList = Array.isArray(parsed) ? parsed : []; + } else if (Array.isArray(filesAttr.value)) { + fileList = filesAttr.value; + } + } + + fileList.forEach(fp => { + const absPath = path.join(REPO_ROOT, fp); + if (!fs.existsSync(absPath)) {return;} + const contents = fs.readFileSync(absPath, 'utf8'); + const ext = path.extname(fp).slice(1); + + // ### {filename} + newNodes.push({ + type: 'heading', + depth: 3, + children: [{type: 'text', value: path.basename(fp)}] + }); + + // ```{lang}\n{contents}\n``` + newNodes.push({ + type: 'code', + lang: ext || undefined, + meta: '', + value: contents + }); }); }); - }); + } + + // Handle code block children (type="vanilla"|"tailwind" and files=[...]) + if (codeChildren.length > 0) { + // Parse metadata from code blocks to extract type and files + const parseCodeMeta = (meta) => { + if (!meta) {return {};} + const result = {}; + + // Extract type + const typeMatch = meta.match(/type=["']([^"']+)["']/); + if (typeMatch) { + result.type = typeMatch[1]; + } + + // Extract files={[...]} + const filesMatch = meta.match(/files=\{(\[[^\]]+\])\}/); + if (filesMatch) { + try { + result.files = JSON.parse(filesMatch[1]); + } catch { + const parsed = parseExpression(filesMatch[1], file); + if (Array.isArray(parsed)) { + result.files = parsed; + } + } + } + + return result; + }; + + const typeToTitle = { + 'vanilla': 'Vanilla CSS', + 'tailwind': 'Tailwind' + }; + + // Check if this is a "component" type ExampleSwitcher (each code block gets its own example title) + const typeAttr = node.attributes?.find(a => a.name === 'type'); + let switcherType = null; + if (typeAttr) { + if (typeAttr.value?.type === 'mdxJsxAttributeValueExpression') { + switcherType = typeAttr.value.value.replace(/['"`]/g, '').trim(); + } else if (typeof typeAttr.value === 'string') { + switcherType = typeAttr.value.trim(); + } + } + + if (switcherType === 'component' && exampleTitles.length > 0) { + // Each code block gets its own heading from the examples array + codeChildren.forEach((codeChild, i) => { + const title = exampleTitles[i] || `Example ${i + 1}`; + const meta = parseCodeMeta(codeChild.meta); + + // ## {title} example + newNodes.push({ + type: 'heading', + depth: 2, + children: [{type: 'text', value: `${title} example`}] + }); + + // Clean up the code value + let codeValue = codeChild.value; + if (codeValue.startsWith('"use client";\n')) { + codeValue = codeValue.slice(14); + } + // Remove docs rendering-specific comments + codeValue = codeValue + .split('\n') + .filter(l => !/^\s*\/\/\/-\s*(begin|end)/i.test(l)) + .map(l => l.replace(/\/\*\s*PROPS\s*\*\//gi, '')) + .join('\n'); + + newNodes.push({ + type: 'code', + lang: codeChild.lang || 'tsx', + meta: '', + value: codeValue + }); + + // Add referenced files for this specific example + if (meta.files && Array.isArray(meta.files)) { + meta.files.forEach(fp => { + const absPath = path.join(REPO_ROOT, fp); + if (!fs.existsSync(absPath)) {return;} + const contents = fs.readFileSync(absPath, 'utf8'); + const ext = path.extname(fp).slice(1); + + // ### {filename} + newNodes.push({ + type: 'heading', + depth: 3, + children: [{type: 'text', value: path.basename(fp)}] + }); + + // ```{lang}\n{contents}\n``` + newNodes.push({ + type: 'code', + lang: ext || undefined, + meta: '', + value: contents + }); + }); + } + }); + } else { + // Group code blocks by type (vanilla, tailwind, etc.) + const codeBlocksByType = new Map(); + codeChildren.forEach((codeChild) => { + const meta = parseCodeMeta(codeChild.meta); + const type = meta.type || 'vanilla'; + if (!codeBlocksByType.has(type)) { + codeBlocksByType.set(type, []); + } + codeBlocksByType.get(type).push({code: codeChild, meta}); + }); + + // Process each type group + for (const [type, codeBlocks] of codeBlocksByType) { + const title = typeToTitle[type] || type.charAt(0).toUpperCase() + type.slice(1); + + // ## {title} example + newNodes.push({ + type: 'heading', + depth: 2, + children: [{type: 'text', value: `${title} example`}] + }); + + // Collect all unique files from all code blocks of this type + const allFiles = new Set(); + codeBlocks.forEach(({meta}) => { + if (meta.files && Array.isArray(meta.files)) { + meta.files.forEach(f => allFiles.add(f)); + } + }); + + // Add the inline example code first + codeBlocks.forEach(({code}) => { + // Clean up the code value + let codeValue = code.value; + if (codeValue.startsWith('"use client";\n')) { + codeValue = codeValue.slice(14); + } + // Remove docs rendering-specific comments + codeValue = codeValue + .split('\n') + .filter(l => !/^\s*\/\/\/-\s*(begin|end)/i.test(l)) + .map(l => l.replace(/\/\*\s*PROPS\s*\*\//gi, '')) + .join('\n'); + + newNodes.push({ + type: 'code', + lang: code.lang || 'tsx', + meta: '', + value: codeValue + }); + }); + + // Add referenced files + allFiles.forEach(fp => { + const absPath = path.join(REPO_ROOT, fp); + if (!fs.existsSync(absPath)) {return;} + const contents = fs.readFileSync(absPath, 'utf8'); + const ext = path.extname(fp).slice(1); + + // ### {filename} + newNodes.push({ + type: 'heading', + depth: 3, + children: [{type: 'text', value: path.basename(fp)}] + }); + + // ```{lang}\n{contents}\n``` + newNodes.push({ + type: 'code', + lang: ext || undefined, + meta: '', + value: contents + }); + }); + } + } + } // Replace ExampleSwitcher node with generated markdown. parent.children.splice(index, 1, ...newNodes); From 299e2416a44b9dbcc52101a51aefc769eb1e300f Mon Sep 17 00:00:00 2001 From: Reid Barber Date: Thu, 11 Dec 2025 15:45:04 -0600 Subject: [PATCH 3/7] docs: fix scroll position restoration when navigating back/forward (#9242) * fix scroll position restoration when navigating back/forward * save scroll position to history * set history.scrollRestoration = 'manual' --- packages/dev/s2-docs/src/client.tsx | 81 +++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 9 deletions(-) diff --git a/packages/dev/s2-docs/src/client.tsx b/packages/dev/s2-docs/src/client.tsx index dfd951d002e..1f821c3b3a9 100644 --- a/packages/dev/s2-docs/src/client.tsx +++ b/packages/dev/s2-docs/src/client.tsx @@ -7,6 +7,11 @@ import {type ReactElement} from 'react'; import {setNavigationPromise} from './Router'; import {ToastQueue} from '@react-spectrum/s2'; +if ('scrollRestoration' in history) { + // Disable browser's automatic scroll restoration since we handle it manually + history.scrollRestoration = 'manual'; +} + // Hydrate initial RSC payload embedded in the HTML. let updateRoot = hydrate({ // Intercept HMR window reloads, and do it with RSC instead. @@ -19,16 +24,56 @@ let updateRoot = hydrate({ let currentNavigationId = 0; let currentAbortController: AbortController | null = null; +interface HistoryState { + scrollTop?: number, + windowScrollTop?: number +} + +function getScrollContainer(): HTMLElement | null { + return document.querySelector('main'); +} + +function saveScrollPosition() { + let scrollContainer = getScrollContainer(); + let scrollTop = scrollContainer?.scrollTop ?? 0; + let windowScrollTop = window.scrollY; + let state: HistoryState = { + ...(history.state as HistoryState | null), + scrollTop, + windowScrollTop + }; + history.replaceState(state, '', location.href); +} + +function restoreScrollPosition(state: HistoryState | null) { + if (state?.scrollTop != null || state?.windowScrollTop != null) { + requestAnimationFrame(() => { + let scrollContainer = getScrollContainer(); + if (scrollContainer && state.scrollTop != null) { + scrollContainer.scrollTop = state.scrollTop; + } + if (state.windowScrollTop != null) { + window.scrollTo(0, state.windowScrollTop); + } + }); + } +} + // A very simple router. When we navigate, we'll fetch a new RSC payload from the server, // and in a React transition, stream in the new page. Once complete, we'll pushState to // update the URL in the browser. -async function navigate(pathname: string, push = false) { +async function navigate(pathname: string, push = false, popstateState: HistoryState | null = null) { let url = new URL(pathname, location.href); let basePath = url.pathname; let pathAnchor = url.hash.slice(1); let currentPath = location.pathname; let isSamePageAnchor = (!basePath || basePath === currentPath) && pathAnchor; + // Save scroll position to current history entry before navigating away + if (push) { + saveScrollPosition(); + } + if (isSamePageAnchor) { if (push) { history.pushState(null, '', pathname); @@ -86,10 +131,19 @@ async function navigate(pathname: string, push = false) { push = false; } - // Reset scroll if navigating to a different page without an anchor - if (currentPath !== newBasePath && !newPathAnchor) { + // Handle scroll position + if (popstateState) { + // Restore scroll position from history state (back/forward navigation) + restoreScrollPosition(popstateState); + } else if (currentPath !== newBasePath && !newPathAnchor) { + // Reset scroll for forward navigation to a different page without an anchor + let scrollContainer = getScrollContainer(); + if (scrollContainer) { + scrollContainer.scrollTop = 0; + } window.scrollTo(0, 0); } else if (newPathAnchor) { + // Scroll to anchor let element = document.getElementById(newPathAnchor); if (element) { element.scrollIntoView(); @@ -244,11 +298,22 @@ document.addEventListener('click', e => { } }); -// When the user clicks the back button, navigate with RSC. -window.addEventListener('popstate', () => { - navigate(location.pathname + location.search + location.hash); +// When the user clicks the back/forward button, navigate with RSC. +window.addEventListener('popstate', (e) => { + navigate(location.pathname + location.search + location.hash, false, e.state as HistoryState | null); }); +// Save scroll position to history state when scrolling stops. +let scrollSaveTimeout: ReturnType | null = null; +function onScroll() { + if (scrollSaveTimeout) { + clearTimeout(scrollSaveTimeout); + } + scrollSaveTimeout = setTimeout(saveScrollPosition, 150); +} + +window.addEventListener('scroll', onScroll, {passive: true, capture: true}); + function scrollToCurrentHash() { if (!location.hash || location.hash === '#') { return; @@ -276,7 +341,5 @@ function scrollToCurrentHash() { if (document.readyState === 'complete' || document.readyState === 'interactive') { scrollToCurrentHash(); } else { - window.addEventListener('DOMContentLoaded', () => { - scrollToCurrentHash(); - }, {once: true}); + window.addEventListener('DOMContentLoaded', scrollToCurrentHash, {once: true}); } From 6bc588b5facf0b52431767df289697084e3de3f4 Mon Sep 17 00:00:00 2001 From: Reid Barber Date: Thu, 11 Dec 2025 16:19:37 -0600 Subject: [PATCH 4/7] docs: new Internationzlied logo (#9326) * test new Internationalized logo * update all Internationalized logos --- .../InternationalizedDefault.svg | 11 +--- .../dev/s2-docs/assets/internationalized.ico | Bin 195234 -> 15086 bytes .../src/icons/InternationalizedLogo.tsx | 51 +++++------------- 3 files changed, 16 insertions(+), 46 deletions(-) diff --git a/packages/dev/docs/pages/assets/component-illustrations/InternationalizedDefault.svg b/packages/dev/docs/pages/assets/component-illustrations/InternationalizedDefault.svg index 7be422befdf..3968013e2c1 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/InternationalizedDefault.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/InternationalizedDefault.svg @@ -1,10 +1,3 @@ - - - - - - - - - + + diff --git a/packages/dev/s2-docs/assets/internationalized.ico b/packages/dev/s2-docs/assets/internationalized.ico index d0dee54937d6a07f652285eb64fa8fcddb99e9fc..8aec276c9386d8bc5b8db774036d17813b8a04d9 100644 GIT binary patch literal 15086 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 { - const clipPathId = `internationalized-logo-clip-${useId()}`; return ( - - - - - - - - - - - - - - - + viewBox="20 20 120 120" + style={{display: 'block', width: size, height: size}} + className={style({ + '--internationalized-logo-color': { + type: 'backgroundColor', + value: 'blue-900' + } + })}> + ); }; From 3d374c5697cb2c8548b8f7f0ac5d46289210562d Mon Sep 17 00:00:00 2001 From: XiaoYan Li Date: Fri, 12 Dec 2025 06:43:50 +0800 Subject: [PATCH 5/7] fix: refactor useControlledState to address state-outdated issues (#9331) * fix: refactor useControlledState to address state-outdated issues * Reduce fix to only required changes --------- Co-authored-by: Devon Govett --- .../@react-stately/utils/src/useControlledState.ts | 7 +++++-- .../utils/test/useControlledState.test.tsx | 10 ++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/@react-stately/utils/src/useControlledState.ts b/packages/@react-stately/utils/src/useControlledState.ts index 0e52b499b6b..76d735b09a9 100644 --- a/packages/@react-stately/utils/src/useControlledState.ts +++ b/packages/@react-stately/utils/src/useControlledState.ts @@ -10,7 +10,7 @@ * governing permissions and limitations under the License. */ -import React, {SetStateAction, useCallback, useEffect, useRef, useState} from 'react'; +import React, {SetStateAction, useCallback, useEffect, useReducer, useRef, useState} from 'react'; // Use the earliest effect possible to reset the ref below. const useEarlyEffect: typeof React.useLayoutEffect = typeof document !== 'undefined' @@ -43,6 +43,7 @@ export function useControlledState(value: T, defaultValue: T, onChange valueRef.current = currentValue; }); + let [, forceUpdate] = useReducer(() => ({}), {}); let setValue = useCallback((value: SetStateAction, ...args: any[]) => { // @ts-ignore - TS doesn't know that T cannot be a function. let newValue = typeof value === 'function' ? value(valueRef.current) : value; @@ -50,9 +51,11 @@ export function useControlledState(value: T, defaultValue: T, onChange // Update the ref so that the next setState callback has the most recent value. valueRef.current = newValue; - // Always trigger a setState, even when controlled, so that the layout effect above runs to reset the value. setStateValue(newValue); + // Always trigger a re-render, even when controlled, so that the layout effect above runs to reset the value. + forceUpdate(); + // Trigger onChange. Note that if setState is called multiple times in a single event, // onChange will be called for each one instead of only once. onChange?.(newValue, ...args); diff --git a/packages/@react-stately/utils/test/useControlledState.test.tsx b/packages/@react-stately/utils/test/useControlledState.test.tsx index 18c9307afe5..a2f3760d313 100644 --- a/packages/@react-stately/utils/test/useControlledState.test.tsx +++ b/packages/@react-stately/utils/test/useControlledState.test.tsx @@ -212,6 +212,16 @@ describe('useControlledState tests', function () { onChangeSpy.mockClear(); + act(() => setValue((prevValue) => { + expect(prevValue).toBe('updated'); + return 'newValue'; + })); + [value, setValue] = result.current; + expect(value).toBe('updated'); + expect(onChangeSpy).toHaveBeenLastCalledWith('newValue'); + + onChangeSpy.mockClear(); + act(() => setValue((prevValue) => { expect(prevValue).toBe('updated'); return 'updated'; From 810a385959e117182a3689cc7f2a5cdefbdfbeb7 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Thu, 11 Dec 2025 15:18:43 -0800 Subject: [PATCH 6/7] feat: Conditional image sources (#9335) * feat: Conditional image sources * Fix --- packages/@react-spectrum/s2/src/Image.tsx | 106 ++++++++++++++---- packages/@react-spectrum/s2/src/Skeleton.tsx | 2 +- .../@react-spectrum/s2/test/Image.test.tsx | 65 +++++++++++ packages/dev/s2-docs/pages/s2/Image.mdx | 23 ++++ packages/dev/s2-docs/src/ComponentCard.tsx | 27 ++--- .../dev/s2-docs/src/ComponentCardClient.tsx | 3 +- packages/dev/s2-docs/src/ExampleList.tsx | 10 +- .../dev/s2-docs/src/VisualExampleClient.tsx | 3 + 8 files changed, 193 insertions(+), 46 deletions(-) create mode 100644 packages/@react-spectrum/s2/test/Image.test.tsx diff --git a/packages/@react-spectrum/s2/src/Image.tsx b/packages/@react-spectrum/s2/src/Image.tsx index 0cf45380aaf..9fc66e4a032 100644 --- a/packages/@react-spectrum/s2/src/Image.tsx +++ b/packages/@react-spectrum/s2/src/Image.tsx @@ -1,3 +1,4 @@ +import {ColorSchemeContext} from './Provider'; import {ContextValue, SlotProps} from 'react-aria-components'; import {createContext, ForwardedRef, forwardRef, HTMLAttributeReferrerPolicy, JSX, ReactNode, useCallback, useContext, useMemo, useReducer, useRef, version} from 'react'; import {DefaultImageGroup, ImageGroup} from './ImageCoordinator'; @@ -9,9 +10,46 @@ import {UnsafeStyles} from './style-utils'; import {useLayoutEffect} from '@react-aria/utils'; import {useSpectrumContextProps} from './useSpectrumContextProps'; +export interface ImageSource { + /** + * A comma-separated list of image URLs and descriptors. + * [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/source#srcset). + */ + srcSet?: string | undefined, + /** + * The color scheme for this image source. Unlike `media`, this respects the `Provider` color scheme setting. + */ + colorScheme?: 'light' | 'dark', + /** + * A media query describing when the source should render. + * [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/source#media). + */ + media?: string | undefined, + /** + * A list of source sizes that describe the final rendered width of the image. + * [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/source#sizes). + */ + sizes?: string | undefined, + /** + * The mime type of the image. + * [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/source#type). + */ + type?: string | undefined, + /** + * The intrinsic width of the image. + * [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/source#width). + */ + width?: number, + /** + * The intrinsic height of the image. + * [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/source#height). + */ + height?: number +} + export interface ImageProps extends UnsafeStyles, SlotProps { - /** The URL of the image. */ - src?: string, + /** The URL of the image or a list of conditional sources. */ + src?: string | ImageSource[], // TODO // srcSet?: string, // sizes?: string, @@ -61,10 +99,6 @@ export interface ImageProps extends UnsafeStyles, SlotProps { * If not provided, the default image group is used. */ group?: ImageGroup, - /** - * Child `` elements defining alternate versions of an image for different display/device scenarios. - */ - children?: ReactNode, /** * Associates the image with a microdata object. * See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/itemprop). @@ -159,7 +193,7 @@ export const Image = forwardRef(function Image(props: ImageProps, domRef: Forwar [props, domRef] = useSpectrumContextProps(props, domRef, ImageContext); let { - src = '', + src: srcProp = '', styles, UNSAFE_className = '', UNSAFE_style, @@ -177,16 +211,17 @@ export const Image = forwardRef(function Image(props: ImageProps, domRef: Forwar slot, width, height, - children, itemProp } = props; let hidden = (props as ImageContextValue).hidden; + let colorScheme = useContext(ColorSchemeContext); + let cacheKey = useMemo(() => typeof srcProp === 'object' ? JSON.stringify(srcProp) : srcProp, [srcProp]); let {revealAll, register, unregister, load} = useContext(group); - let [{state, src: lastSrc, loadTime}, dispatch] = useReducer(reducer, src, createState); + let [{state, src: lastCacheKey, loadTime}, dispatch] = useReducer(reducer, cacheKey, createState); - if (src !== lastSrc && !hidden) { - dispatch({type: 'update', src}); + if (cacheKey !== lastCacheKey && !hidden) { + dispatch({type: 'update', src: cacheKey}); } if (state === 'loaded' && revealAll && !hidden) { @@ -199,21 +234,21 @@ export const Image = forwardRef(function Image(props: ImageProps, domRef: Forwar return; } - register(src); + register(cacheKey); return () => { - unregister(src); + unregister(cacheKey); }; - }, [hidden, register, unregister, src]); + }, [hidden, register, unregister, cacheKey]); let onLoad = useCallback(() => { - load(src); + load(cacheKey); dispatch({type: 'loaded'}); - }, [load, src]); + }, [load, cacheKey]); let onError = useCallback(() => { dispatch({type: 'error'}); - unregister(src); - }, [unregister, src]); + unregister(cacheKey); + }, [unregister, cacheKey]); let isSkeleton = useIsSkeleton(); let isAnimating = isSkeleton || state === 'loading' || state === 'loaded'; @@ -223,15 +258,20 @@ export const Image = forwardRef(function Image(props: ImageProps, domRef: Forwar return; } + // In React act environments, run immediately. + // @ts-ignore + let isTestEnv = typeof IS_REACT_ACT_ENVIRONMENT === 'boolean' ? IS_REACT_ACT_ENVIRONMENT : typeof jest !== 'undefined'; + let runTask = isTestEnv ? fn => fn() : queueMicrotask; + // If the image is already loaded, update state immediately instead of waiting for onLoad. let img = imgRef.current; if (state === 'loading' && img?.complete) { if (img.naturalWidth === 0 && img.naturalHeight === 0) { // Queue a microtask so we don't hit React's update limit. // TODO: is this necessary? - queueMicrotask(onError); + runTask(onError); } else { - queueMicrotask(onLoad); + runTask(onLoad); } } @@ -253,7 +293,7 @@ export const Image = forwardRef(function Image(props: ImageProps, domRef: Forwar let img = ( {alt} ); - if (children) { + if (Array.isArray(srcProp)) { img = ( - {children} + {srcProp.map((source, i) => { + let {colorScheme: sourceColorScheme, ...sourceProps} = source; + if (sourceColorScheme) { + if (!colorScheme || colorScheme === 'light dark') { + return ( + + ); + } + + return sourceColorScheme === colorScheme + ? + : null; + } else { + return ; + } + })} {img} ); @@ -287,7 +345,7 @@ export const Image = forwardRef(function Image(props: ImageProps, domRef: Forwar {!errorState && img} ); - }, [slot, hidden, domRef, UNSAFE_style, UNSAFE_className, styles, isAnimating, errorState, src, alt, crossOrigin, decoding, fetchPriority, loading, referrerPolicy, width, height, onLoad, onError, isRevealed, isTransitioning, children, itemProp]); + }, [slot, hidden, domRef, UNSAFE_style, UNSAFE_className, styles, isAnimating, errorState, alt, crossOrigin, decoding, fetchPriority, loading, referrerPolicy, width, height, onLoad, onError, isRevealed, isTransitioning, srcProp, itemProp, colorScheme]); }); function getFetchPriorityProp(fetchPriority?: 'high' | 'low' | 'auto'): Record { diff --git a/packages/@react-spectrum/s2/src/Skeleton.tsx b/packages/@react-spectrum/s2/src/Skeleton.tsx index b8ebd13cba4..1cc218bb3d6 100644 --- a/packages/@react-spectrum/s2/src/Skeleton.tsx +++ b/packages/@react-spectrum/s2/src/Skeleton.tsx @@ -22,7 +22,7 @@ export function useLoadingAnimation(isAnimating: boolean): (element: HTMLElement let animationRef = useRef(null); let reduceMotion = useMediaQuery('(prefers-reduced-motion: reduce)'); return useCallback((element: HTMLElement | null) => { - if (isAnimating && !animationRef.current && element && !reduceMotion) { + if (isAnimating && !animationRef.current && element && !reduceMotion && typeof element.animate === 'function') { // Use web animation API instead of CSS animations so that we can // synchronize it between all loading elements on the page (via startTime). animationRef.current = element.animate( diff --git a/packages/@react-spectrum/s2/test/Image.test.tsx b/packages/@react-spectrum/s2/test/Image.test.tsx new file mode 100644 index 00000000000..014a0f01cbf --- /dev/null +++ b/packages/@react-spectrum/s2/test/Image.test.tsx @@ -0,0 +1,65 @@ +/* + * Copyright 2025 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 {Image, Provider} from '../src'; +import {render} from '@react-spectrum/test-utils-internal'; + +describe('Image', () => { + it('should support conditional sources', async () => { + let {getByRole} = render( + test= 500px)'}, + {srcSet: 'default.png'} + ]} /> + ); + + let img = getByRole('img'); + let picture = img.parentElement!; + expect(picture.tagName).toBe('PICTURE'); + let sources = picture.querySelectorAll('source'); + + expect(sources).toHaveLength(3); + expect(sources[0]).toHaveAttribute('srcset', 'foo.png'); + expect(sources[0]).toHaveAttribute('type', 'image/png'); + expect(sources[0]).toHaveAttribute('media', '(prefers-color-scheme: light)'); + expect(sources[1]).toHaveAttribute('srcset', 'bar.png'); + expect(sources[1]).toHaveAttribute('media', '(width >= 500px) and (prefers-color-scheme: dark)'); + expect(sources[2]).toHaveAttribute('srcset', 'default.png'); + }); + + it('should support conditional sources with Provider colorScheme override', async () => { + let {getByRole} = render( + + test= 500px)'}, + {srcSet: 'default.png'} + ]} /> + + ); + + let img = getByRole('img'); + let picture = img.parentElement!; + expect(picture.tagName).toBe('PICTURE'); + let sources = picture.querySelectorAll('source'); + + expect(sources).toHaveLength(2); + expect(sources[0]).toHaveAttribute('srcset', 'bar.png'); + expect(sources[0]).toHaveAttribute('media', '(width >= 500px)'); + expect(sources[1]).toHaveAttribute('srcset', 'default.png'); + }); +}); diff --git a/packages/dev/s2-docs/pages/s2/Image.mdx b/packages/dev/s2-docs/pages/s2/Image.mdx index 59b4629fe90..d1487fdd169 100644 --- a/packages/dev/s2-docs/pages/s2/Image.mdx +++ b/packages/dev/s2-docs/pages/s2/Image.mdx @@ -21,6 +21,29 @@ import {style} from '@react-spectrum/s2/style' with {type: 'macro'}; styles={style({width: 400, maxWidth: 'full', borderRadius: 'default'})} /> ``` +## Conditional sources + +Set the `src` prop to an array of objects describing conditional images, e.g. media queries or image formats. These accept the same props as the <[source](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/source)> HTML element, as well as `colorScheme` to conditionally render images based on the [Provider](Provider) color scheme. + +```tsx render type="s2" wide docs={docs.exports.Provider} links={docs.links} props={['colorScheme']} +"use client"; +import {Image, Provider} from '@react-spectrum/s2'; +import {style} from '@react-spectrum/s2/style' with {type: 'macro'}; + + + Conditional image + +``` + + ## Error state Use `renderError` to display a custom error UI when an image fails to load. diff --git a/packages/dev/s2-docs/src/ComponentCard.tsx b/packages/dev/s2-docs/src/ComponentCard.tsx index d67b99a36c5..bc5f38db9fa 100644 --- a/packages/dev/s2-docs/src/ComponentCard.tsx +++ b/packages/dev/s2-docs/src/ComponentCard.tsx @@ -408,15 +408,15 @@ function ComponentIllustration({name, href}: IllustrationProps) { return ( - - - + styles={illustrationStyles} /> ); } @@ -443,16 +443,13 @@ export function ComponentCard({id, name, href, description, size, ...otherProps} preview = (
{/* Background gradient */} - - - - - + {releaseVersion}
); diff --git a/packages/dev/s2-docs/src/ComponentCardClient.tsx b/packages/dev/s2-docs/src/ComponentCardClient.tsx index 05665f2f76a..ba08de3f9fc 100644 --- a/packages/dev/s2-docs/src/ComponentCardClient.tsx +++ b/packages/dev/s2-docs/src/ComponentCardClient.tsx @@ -2,6 +2,7 @@ import {Card, CardPreview, CardProps, Content, Text} from '@react-spectrum/s2'; import {ReactNode, useEffect, useRef} from 'react'; import {registerSpectrumLink} from './prefetch'; +import {style} from '@react-spectrum/s2/style' with {type: 'macro'}; interface ComponentCardProps extends Omit { preview: ReactNode, @@ -30,7 +31,7 @@ export function ComponentCardClient(props: ComponentCardProps) { {preview} - + {name} {description && {description}} diff --git a/packages/dev/s2-docs/src/ExampleList.tsx b/packages/dev/s2-docs/src/ExampleList.tsx index 3498db4d9b1..821fe699d2a 100644 --- a/packages/dev/s2-docs/src/ExampleList.tsx +++ b/packages/dev/s2-docs/src/ExampleList.tsx @@ -99,12 +99,12 @@ export function ExampleImage({name, itemProp}: {name: string, itemProp?: string} let [light, dark] = img; return ( - - - + styles={image} /> ); } diff --git a/packages/dev/s2-docs/src/VisualExampleClient.tsx b/packages/dev/s2-docs/src/VisualExampleClient.tsx index 8338e39a527..0d12be6d428 100644 --- a/packages/dev/s2-docs/src/VisualExampleClient.tsx +++ b/packages/dev/s2-docs/src/VisualExampleClient.tsx @@ -444,6 +444,9 @@ export function Control({name}: {name: string}) { if (name === 'placement' && control.value.elements.length === 22) { return ; } + if (name === 'src') { + return ; + } return ; case 'number': return ; From 94932452e9978728bc1ff38bbcf9b468c97a5a45 Mon Sep 17 00:00:00 2001 From: Yihui Liao <44729383+yihuiliao@users.noreply.github.com> Date: Thu, 11 Dec 2025 15:28:51 -0800 Subject: [PATCH 7/7] chore: rename closeOnPress to shouldCloseOnPress (#9337) * chore: rename closeOnPress to shouldCloseOnPress * fix test * update doc example --------- Co-authored-by: Daniel Lu --- packages/@react-aria/tooltip/src/useTooltipTrigger.ts | 6 +++--- packages/@react-spectrum/tooltip/src/TooltipTrigger.tsx | 6 +++--- .../tooltip/stories/TooltipTrigger.stories.tsx | 4 ++-- .../@react-spectrum/tooltip/test/TooltipTrigger.test.js | 8 ++++---- packages/@react-types/tooltip/src/index.d.ts | 2 +- packages/dev/s2-docs/pages/s2/Tooltip.mdx | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/@react-aria/tooltip/src/useTooltipTrigger.ts b/packages/@react-aria/tooltip/src/useTooltipTrigger.ts index d31c8ae9024..cacef8ec890 100644 --- a/packages/@react-aria/tooltip/src/useTooltipTrigger.ts +++ b/packages/@react-aria/tooltip/src/useTooltipTrigger.ts @@ -37,7 +37,7 @@ export function useTooltipTrigger(props: TooltipTriggerProps, state: TooltipTrig let { isDisabled, trigger, - closeOnPress = true + shouldCloseOnPress = true } = props; let tooltipId = useId(); @@ -103,8 +103,8 @@ export function useTooltipTrigger(props: TooltipTriggerProps, state: TooltipTrig }; let onPressStart = () => { - // if closeOnPress is false, we should not close the tooltip - if (!closeOnPress) { + // if shouldCloseOnPress is false, we should not close the tooltip + if (!shouldCloseOnPress) { return; } // no matter how the trigger is pressed, we should close the tooltip diff --git a/packages/@react-spectrum/tooltip/src/TooltipTrigger.tsx b/packages/@react-spectrum/tooltip/src/TooltipTrigger.tsx index 0cb42d22ab7..9530a2404b0 100644 --- a/packages/@react-spectrum/tooltip/src/TooltipTrigger.tsx +++ b/packages/@react-spectrum/tooltip/src/TooltipTrigger.tsx @@ -22,7 +22,7 @@ import {useTooltipTriggerState} from '@react-stately/tooltip'; const DEFAULT_OFFSET = -1; // Offset needed to reach 4px/5px (med/large) distance between tooltip and trigger button const DEFAULT_CROSS_OFFSET = 0; -const DEFAULT_CLOSE_ON_PRESS = true; // Whether the tooltip should close when the trigger is pressed +const DEFAULT_SHOULD_CLOSE_ON_PRESS = true; // Whether the tooltip should close when the trigger is pressed function TooltipTrigger(props: SpectrumTooltipTriggerProps) { let { @@ -31,7 +31,7 @@ function TooltipTrigger(props: SpectrumTooltipTriggerProps) { isDisabled, offset = DEFAULT_OFFSET, trigger: triggerAction, - closeOnPress = DEFAULT_CLOSE_ON_PRESS + shouldCloseOnPress = DEFAULT_SHOULD_CLOSE_ON_PRESS } = props; let [trigger, tooltip] = React.Children.toArray(children) as [ReactElement, ReactElement]; @@ -43,7 +43,7 @@ function TooltipTrigger(props: SpectrumTooltipTriggerProps) { let {triggerProps, tooltipProps} = useTooltipTrigger({ isDisabled, trigger: triggerAction, - closeOnPress + shouldCloseOnPress }, state, tooltipTriggerRef); let [borderRadius, setBorderRadius] = useState(0); diff --git a/packages/@react-spectrum/tooltip/stories/TooltipTrigger.stories.tsx b/packages/@react-spectrum/tooltip/stories/TooltipTrigger.stories.tsx index 48becc8c2bf..bcbdebd4b56 100644 --- a/packages/@react-spectrum/tooltip/stories/TooltipTrigger.stories.tsx +++ b/packages/@react-spectrum/tooltip/stories/TooltipTrigger.stories.tsx @@ -73,7 +73,7 @@ const argTypes = { children: { control: {disable: true} }, - closeOnPress: { + shouldCloseOnPress: { control: 'boolean' } }; @@ -117,7 +117,7 @@ export default { Change Name ], onOpenChange: action('openChange'), - closeOnPress: true + shouldCloseOnPress: true }, argTypes: argTypes } as Meta; diff --git a/packages/@react-spectrum/tooltip/test/TooltipTrigger.test.js b/packages/@react-spectrum/tooltip/test/TooltipTrigger.test.js index 5a898b7450e..9a6576f521a 100644 --- a/packages/@react-spectrum/tooltip/test/TooltipTrigger.test.js +++ b/packages/@react-spectrum/tooltip/test/TooltipTrigger.test.js @@ -330,10 +330,10 @@ describe('TooltipTrigger', function () { expect(queryByRole('tooltip')).toBeNull(); }); - it('does not close if the trigger is clicked when closeOnPress is false', async () => { + it('does not close if the trigger is clicked when shouldCloseOnPress is false', async () => { let {getByRole, getByLabelText} = render( - + Helpful information. @@ -351,10 +351,10 @@ describe('TooltipTrigger', function () { expect(tooltip).toBeVisible(); }); - it('does not close if the trigger is clicked with the keyboard when closeOnPress is false', async () => { + it('does not close if the trigger is clicked with the keyboard when shouldCloseOnPress is false', async () => { let {getByRole, getByLabelText} = render( - + Helpful information. diff --git a/packages/@react-types/tooltip/src/index.d.ts b/packages/@react-types/tooltip/src/index.d.ts index 73730df859f..5bac687bbb5 100644 --- a/packages/@react-types/tooltip/src/index.d.ts +++ b/packages/@react-types/tooltip/src/index.d.ts @@ -42,7 +42,7 @@ export interface TooltipTriggerProps extends OverlayTriggerProps { * Whether the tooltip should close when the trigger is pressed. * @default true */ - closeOnPress?: boolean + shouldCloseOnPress?: boolean } export interface SpectrumTooltipTriggerProps extends Omit, PositionProps { diff --git a/packages/dev/s2-docs/pages/s2/Tooltip.mdx b/packages/dev/s2-docs/pages/s2/Tooltip.mdx index 70b153d3a40..0d0e836aff0 100644 --- a/packages/dev/s2-docs/pages/s2/Tooltip.mdx +++ b/packages/dev/s2-docs/pages/s2/Tooltip.mdx @@ -11,7 +11,7 @@ export const description = 'Displays a description of an element on hover or foc {docs.exports.Tooltip.description} -```tsx render docs={docs.exports.TooltipTrigger} links={docs.links} props={['placement', 'crossOffset', 'shouldFlip']} type="s2" +```tsx render docs={docs.exports.TooltipTrigger} links={docs.links} props={['placement', 'crossOffset', 'shouldFlip', 'shouldCloseOnPress']} type="s2" "use client"; import {Tooltip, TooltipTrigger, ActionButton} from '@react-spectrum/s2'; import Edit from '@react-spectrum/s2/icons/Edit';