diff --git a/.circleci/config.yml b/.circleci/config.yml index 8e55af664ea..26b0f100c9c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -816,9 +816,10 @@ jobs: - run: name: deploy command: | - azcopy copy "/tmp/dist/production/docs/*" "https://reactspectrum.blob.core.windows.net/\$web${AZURE_STORAGE_SAS_TOKEN}" --recursive --exclude-pattern "*.md;*.txt" - azcopy copy "/tmp/dist/production/docs/*" "https://reactspectrum.blob.core.windows.net/\$web${AZURE_STORAGE_SAS_TOKEN}" --recursive --include-pattern "*.md" --content-type "text/markdown; charset=utf-8" - azcopy copy "/tmp/dist/production/docs/*" "https://reactspectrum.blob.core.windows.net/\$web${AZURE_STORAGE_SAS_TOKEN}" --recursive --include-pattern "*.txt" --content-type "text/plain; charset=utf-8" + azcopy copy "/tmp/dist/production/docs/*" "https://reactspectrum.blob.core.windows.net/\$web${AZURE_STORAGE_SAS_TOKEN}" --recursive --exclude-pattern "*.md;*.txt;*.html;*.rsc" + azcopy copy "/tmp/dist/production/docs/*" "https://reactspectrum.blob.core.windows.net/\$web${AZURE_STORAGE_SAS_TOKEN}" --recursive --include-pattern "*.md" --content-type "text/markdown; charset=utf-8" --cache-control "max-age=300" + azcopy copy "/tmp/dist/production/docs/*" "https://reactspectrum.blob.core.windows.net/\$web${AZURE_STORAGE_SAS_TOKEN}" --recursive --include-pattern "*.txt" --content-type "text/plain; charset=utf-8" --cache-control "max-age=300" + azcopy copy "/tmp/dist/production/docs/*" "https://reactspectrum.blob.core.windows.net/\$web${AZURE_STORAGE_SAS_TOKEN}" --recursive --include-pattern "*.html;*.rsc" --cache-control "max-age=300" comment: executor: rsp diff --git a/Makefile b/Makefile index ff0cea55c58..e72170a0147 100644 --- a/Makefile +++ b/Makefile @@ -146,16 +146,16 @@ s2-api-diff: node scripts/api-diff.js --skip-same --skip-style-props s2-docs: - BASE_URL=https://reactspectrum.blob.core.windows.net PUBLIC_URL=/reactspectrum/$$(git rev-parse HEAD)/s2-docs DIST_DIR=dist/$$(git rev-parse HEAD)/s2-docs $(MAKE) build-s2-docs + PUBLIC_URL=https://reactspectrum.blob.core.windows.net/reactspectrum/$$(git rev-parse HEAD)/s2-docs DIST_DIR=dist/$$(git rev-parse HEAD)/s2-docs $(MAKE) build-s2-docs s2-docs-production: - BASE_URL=https://react-spectrum.adobe.com PUBLIC_URL=/beta DIST_DIR=dist/production/docs/beta $(MAKE) build-s2-docs + PUBLIC_URL=https://react-spectrum.adobe.com/beta DIST_DIR=dist/production/docs/beta $(MAKE) build-s2-docs build-s2-docs: yarn workspace @react-spectrum/s2-docs generate:md yarn workspace @react-spectrum/s2-docs generate:og - REGISTRY_URL=$(BASE_URL)$(PUBLIC_URL)/registry node scripts/buildRegistry.mjs - REGISTRY_URL=$(BASE_URL)$(PUBLIC_URL)/registry yarn build:s2-docs --public-url $(PUBLIC_URL) + REGISTRY_URL=$(PUBLIC_URL)/registry node scripts/buildRegistry.mjs + REGISTRY_URL=$(PUBLIC_URL)/registry yarn build:s2-docs --public-url $(PUBLIC_URL) mkdir -p $(DIST_DIR) mv packages/dev/s2-docs/dist/* $(DIST_DIR) mkdir -p $(DIST_DIR)/registry diff --git a/packages/dev/s2-docs/src/CodeSandbox.tsx b/packages/dev/s2-docs/src/CodeSandbox.tsx index 16cd17d0273..be0b47c3204 100644 --- a/packages/dev/s2-docs/src/CodeSandbox.tsx +++ b/packages/dev/s2-docs/src/CodeSandbox.tsx @@ -38,7 +38,8 @@ const dependencies = { 'react-aria-components': '^1.10.0', react: '^19', 'react-dom': '^19', - 'lucide-react': '^0.514.0' + 'lucide-react': '^0.514.0', + 'clsx': '^2.1.1' }, tailwind: { 'react-aria-components': '^1.10.0', diff --git a/packages/dev/s2-docs/src/Layout.tsx b/packages/dev/s2-docs/src/Layout.tsx index d408c529322..735d3232e5b 100644 --- a/packages/dev/s2-docs/src/Layout.tsx +++ b/packages/dev/s2-docs/src/Layout.tsx @@ -64,16 +64,11 @@ const getTitle = (currentPage: Page): string => { }; const getOgImageUrl = (currentPage: Page): string => { - const slug = currentPage.url.replace(/^\//, '').replace(/\.html$/, ''); - - if (slug.includes('s2-docs/')) { - // For build links, use the full URL - const ogPath = slug.replace(/s2-docs\//, 's2-docs/og/'); - return `https://reactspectrum.blob.core.windows.net/${ogPath}.png`; + let publicUrl = process.env.PUBLIC_URL || '/'; + if (!publicUrl.endsWith('/')) { + publicUrl += '/'; } - - // For production, use relative path with /og/ prefix - return `/og/${slug}.png`; + return publicUrl + 'og/' + currentPage.url.replace(publicUrl, '').replace(/\.html$/, '.png'); }; const getDescription = (currentPage: Page): string => { diff --git a/packages/dev/s2-docs/src/Nav.tsx b/packages/dev/s2-docs/src/Nav.tsx index d77b7ece220..c67beb542a5 100644 --- a/packages/dev/s2-docs/src/Nav.tsx +++ b/packages/dev/s2-docs/src/Nav.tsx @@ -11,7 +11,7 @@ export function Nav({pages, currentPage}: PageProps) { let currentLibrary = getLibraryFromPage(currentPage); let sections = new Map(); for (let page of pages) { - if (page.exports?.hideNav) { + if (page.exports?.hideNav || page.exports?.hideFromSearch) { continue; } diff --git a/packages/dev/s2-docs/src/client.tsx b/packages/dev/s2-docs/src/client.tsx index a7b923e4f01..a955a049d6f 100644 --- a/packages/dev/s2-docs/src/client.tsx +++ b/packages/dev/s2-docs/src/client.tsx @@ -49,6 +49,8 @@ async function navigate(pathname: string, push = false) { // Intercept link clicks to perform RSC navigation. document.addEventListener('click', e => { let link = (e.target as Element).closest('a'); + let publicUrl = process.env.PUBLIC_URL || '/'; + let publicUrlPathname = publicUrl.startsWith('http') ? new URL(publicUrl).pathname : publicUrl; if ( link && link instanceof HTMLAnchorElement && @@ -57,6 +59,7 @@ document.addEventListener('click', e => { link.origin === location.origin && link.pathname !== location.pathname && !link.hasAttribute('download') && + link.pathname.startsWith(publicUrlPathname) && e.button === 0 && // left clicks only !e.metaKey && // open in new tab (mac) !e.ctrlKey && // open in new tab (windows) diff --git a/packages/react-aria-components/docs/styling.mdx b/packages/react-aria-components/docs/styling.mdx index 37c86d811c6..b78753b7043 100644 --- a/packages/react-aria-components/docs/styling.mdx +++ b/packages/react-aria-components/docs/styling.mdx @@ -268,7 +268,7 @@ With this configured, all states for React Aria Components can be accessed with ## Animation -React Aria Components supports both [CSS transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_transitions/Using_CSS_transitions) and [keyframe animations](https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes), and works with JavaScript animation libraries like [Framer Motion](https://www.framer.com/motion/). +React Aria Components supports both [CSS transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_transitions/Using_CSS_transitions) and [keyframe animations](https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes), and works with JavaScript animation libraries like [Motion](https://motion.dev/). ### CSS transitions @@ -348,20 +348,20 @@ If you are using Tailwind CSS, we recommend using the [tailwindcss-animate](http ``` -### Framer Motion +### Motion -[Framer Motion](https://www.framer.com/motion/) and other JavaScript animation libraries can also be used with React Aria Components. Use the [motion](https://www.framer.com/motion/component/#custom-components) function to create a wrapper component that adds support for Framer Motion's animation props. +[Motion](https://motion.dev) and other JavaScript animation libraries can also be used with React Aria Components. Use the [motion](https://motion.dev/docs/react-motion-component#custom-components) function to create a wrapper component that adds support for Motion's animation props. ```tsx import {Modal, ModalOverlay} from 'react-aria-components'; import {motion} from 'motion/react'; -// Create Framer Motion wrappers. +// Create a Motion wrappers. const MotionModal = motion(Modal); const MotionModalOverlay = motion(ModalOverlay); ``` -This enables using props like [animate](https://www.framer.com/motion/animation/) with React Aria Components. +This enables using props like [animate](https://motion.dev/docs/react-animation) with React Aria Components. ```tsx ``` -Overlay exit animations can be implemented using the `isExiting` prop, which keeps the element in the DOM until an animation is complete. Framer Motion's [variants](https://www.framer.com/motion/animation/#variants) are a good way to setup named animation states. +Overlay exit animations can be implemented using the `isExiting` prop, which keeps the element in the DOM until an animation is complete. Motion's [variants](https://motion.dev/docs/react-animation#variants) are a good way to setup named animation states. ```tsx type AnimationState = 'unmounted' | 'hidden' | 'visible'; @@ -418,9 +418,9 @@ function Example() { } ``` -**Note**: Framer Motion's `AnimatePresence` component may not work with React Aria overlays in all cases, so the example shown above is the recommended approach for exit animations. +**Note**: Motion's `AnimatePresence` component may not work with React Aria overlays in all cases, so the example shown above is the recommended approach for exit animations. -The [AnimatePresence](https://www.framer.com/motion/animate-presence/) component allows you to animate when items are added or removed in collection components. Use `array.map` to create children, and make sure each child has a unique `key` in addition to an `id` to ensure Framer Motion can track it. +The [AnimatePresence](https://motion.dev/docs/react-animate-presence) component allows you to animate when items are added or removed in collection components. Use `array.map` to create children, and make sure each child has a unique `key` in addition to an `id` to ensure Motion can track it. ```tsx import {GridList, GridListItem} from 'react-aria-components';