Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
c9aa612
fix modal so it always appears over mobile header and fix dropzone width
LFDanLu Sep 16, 2025
0ecf094
add title font size resizing behavior to s2 docs
LFDanLu Sep 16, 2025
96e5138
dont use useResizeObserver because we want to catch fonts changing
LFDanLu Sep 16, 2025
8827283
fix mobile header icon and library label
LFDanLu Sep 16, 2025
ebc6a23
fix cross page anchor navigation scrolling and mobile cross page navi…
LFDanLu Sep 4, 2025
36b0463
properly close mobile header menu when clicking on component card
LFDanLu Sep 18, 2025
52f64c5
making image coordinator example wrap to new row instead of squishing…
LFDanLu Sep 18, 2025
c7c7a30
set a minwidth large enough so disallowEmptySelection have its label …
LFDanLu Sep 18, 2025
987cff4
properly reobserve the new page post-navigation so the page nav picke…
LFDanLu Sep 18, 2025
48b0cd1
remove broken title resizer code and fix rebase
LFDanLu Sep 29, 2025
74ef767
restore styles
LFDanLu Sep 29, 2025
e3bfb1c
Merge branch 'main' of github.com:adobe/react-spectrum into docs_fixes
LFDanLu Oct 2, 2025
451ac67
fix internationalized logo
LFDanLu Oct 2, 2025
1d5918e
add 404 page
LFDanLu Oct 3, 2025
ed3fdf5
Merge branch 'main' of github.com:adobe/react-spectrum into docs_fixes
LFDanLu Oct 3, 2025
018be32
forgot to remove test code
LFDanLu Oct 3, 2025
e2aaa67
Merge remote-tracking branch 'origin/main' into docs_fixes
reidbarber Oct 6, 2025
f1ee9ed
hide error page from search
reidbarber Oct 6, 2025
4ef11a8
update S2 popover example
LFDanLu Oct 6, 2025
8c9b45f
update icon in example
LFDanLu Oct 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/dev/s2-docs/pages/error.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Error from '../src/Error';
import {Layout} from '../src/Layout';
export default Layout;

import docs from 'docs:@react-spectrum/s2';

export const hideFromSearch = true;

<Error />
4 changes: 2 additions & 2 deletions packages/dev/s2-docs/pages/s2/DropZone.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ function Example(props) {
return (
<DropZone
{...props}
styles={style({width: 320})}
styles={style({width: 320, maxWidth: '90%'})}
/* PROPS */
isFilled={!!content}
// Determine whether dragged content should be accepted.
getDropOperation={types => (
['text/plain', 'image/jpeg', 'image/png', 'image/gif'].some(t => types.has(t))
? 'copy'
? 'copy'
: 'cancel'
)}
onDrop={async (event) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/s2-docs/pages/s2/Image.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
<div
className={style({
display: 'grid',
gridTemplateColumns: '1fr 1fr 1fr 1fr',
gridTemplateColumns: 'repeat(auto-fit, minmax(140px, 1fr))',
gridTemplateRows: [180],
gap: 8
})}>
Expand Down
41 changes: 17 additions & 24 deletions packages/dev/s2-docs/pages/s2/Popover.mdx
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I poked around with this example and decided to update it entirely since the Form + CheckboxGroup looks strange when the size was increased via the controls

Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,27 @@ export const tags = ['popup', 'overlay'];

```tsx render docs={docs.exports.Popover} links={docs.links} props={['placement', 'size', 'offset', 'crossOffset', 'shouldFlip', 'hideArrow']} type="s2" initialProps={{size: 'S'}}
"use client";
import {Popover, DialogTrigger, ActionButton, CheckboxGroup, Checkbox, Form} from '@react-spectrum/s2';
import Filter from '@react-spectrum/s2/icons/Filter';
import {Popover, DialogTrigger, ActionButton, Form, TextField, Switch, Button} from '@react-spectrum/s2';
import Feedback from '@react-spectrum/s2/icons/Feedback';
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};

function Example(props) {
return (
<DialogTrigger>
<ActionButton aria-label="Filters">
<Filter />
<ActionButton aria-label="Feedback">
<Feedback />
</ActionButton>
{/*- begin focus -*/}
<Popover {...props}/* PROPS */>
<Form>
<CheckboxGroup label="Stops">
<Checkbox value={0}>Non-stop</Checkbox>
<Checkbox value={1}>1 stop</Checkbox>
<Checkbox value={2}>2+ stops</Checkbox>
</CheckboxGroup>
<CheckboxGroup label="Bags">
<Checkbox value={0}>Carry on</Checkbox>
<Checkbox value={1}>Checked bag</Checkbox>
</CheckboxGroup>
<CheckboxGroup label="Times">
<Checkbox value={0}>Morning</Checkbox>
<Checkbox value={1}>Afternoon</Checkbox>
<Checkbox value={2}>Evening</Checkbox>
</CheckboxGroup>
</Form>
<div className={style({padding: 12})}>
<p className={style({font: 'body', marginTop: 0})}>How are we doing? Share your feedback here.</p>
<Form>
<TextField label="Subject" placeholder="Enter a summary" />
<TextField label="Description" isRequired placeholder="Enter your feedback" />
<Switch>Adobe can contact me for further questions concerning this feedback</Switch>
<Button styles={style({marginStart: 'auto'})}>Submit</Button>
</Form>
</div>
</Popover>
{/*- end focus -*/}
</DialogTrigger>
Expand All @@ -65,17 +58,17 @@ function Example() {
<Button onPress={() => setOpen(!isOpen)}>
Open popover
</Button>
<div
<div
ref={triggerRef}
className={style({
padding: 8,
backgroundColor: 'gray-100',
padding: 8,
backgroundColor: 'gray-100',
borderRadius: 'default',
font: 'ui'
})}>
Popover appears here
</div>
<Popover
<Popover
/*- begin highlight -*/
triggerRef={triggerRef}
isOpen={isOpen}
Expand Down
17 changes: 17 additions & 0 deletions packages/dev/s2-docs/src/Error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use client';

// eslint-disable-next-line monorepo/no-internal-import
import BrowserError from '@react-spectrum/s2/illustrations/linear/BrowserError';
import {Content, Heading, IllustratedMessage} from '@react-spectrum/s2';

export default function Error() {
return (
<div style={{display: 'flex', alignItems: 'center', height: '50vh', justifyContent: 'center', flexDirection: 'row'}}>
<IllustratedMessage>
<BrowserError />
<Heading>Error 404: Page not found</Heading>
<Content>This page isn't available. Try checking the URL or visit a different page.</Content>
</IllustratedMessage>
</div>
);
}
29 changes: 18 additions & 11 deletions packages/dev/s2-docs/src/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,19 @@ const getDescription = (currentPage: Page): string => {
return library ? `Documentation for ${pageTitle} in ${library}.` : `Documentation for ${pageTitle}.`;
};

let articleStyles = style({
maxWidth: {
default: 'none',
isWithToC: 768
},
width: 'full',
height: 'fit'
});


export function Layout(props: PageProps & {children: ReactElement<any>}) {
let {pages, currentPage, children} = props;
let hasToC = currentPage.tableOfContents?.[0]?.children && currentPage.tableOfContents[0].children.length > 0;
return (
<Provider elementType="html" locale="en" background="layer-1" styles={style({scrollPaddingTop: {default: 64, lg: 0}})}>
<head>
Expand Down Expand Up @@ -120,12 +131,12 @@ export function Layout(props: PageProps & {children: ReactElement<any>}) {
})}>
<Header pages={pages} currentPage={currentPage} />
<MobileHeader
toc={(currentPage.tableOfContents?.[0]?.children?.length ?? 0) > 0 ? <MobileToc key="toc" toc={currentPage.tableOfContents ?? []} /> : null}
toc={(currentPage.tableOfContents?.[0]?.children?.length ?? 0) > 0 ? <MobileToc key="toc" toc={currentPage.tableOfContents ?? []} currentPage={currentPage} /> : null}
pages={pages}
currentPage={currentPage} />
<div className={style({display: 'flex', width: 'full'})}>
<Nav pages={pages} currentPage={currentPage} />
<main
<main
key={currentPage.url}
style={{borderBottomLeftRadius: 0, borderBottomRightRadius: 0}}
className={style({
Expand Down Expand Up @@ -156,11 +167,7 @@ export function Layout(props: PageProps & {children: ReactElement<any>}) {
}
})}>
<article
className={style({
maxWidth: 768,
width: 'full',
height: 'fit'
})}>
className={articleStyles({isWithToC: hasToC})}>
{React.cloneElement(children, {components})}
</article>
<aside
Expand All @@ -177,10 +184,10 @@ export function Layout(props: PageProps & {children: ReactElement<any>}) {
lg: 'block'
}
})}>
{currentPage.tableOfContents?.[0]?.children && currentPage.tableOfContents[0].children.length > 0 && (
{hasToC && (
<div className={style({font: 'title', minHeight: 32, paddingX: 12, display: 'flex', alignItems: 'center'})}>Contents</div>
)}
<Toc toc={currentPage.tableOfContents?.[0]?.children ?? []} />
<Toc toc={currentPage.tableOfContents?.[0]?.children ?? []} />
</aside>
</main>
</div>
Expand All @@ -205,9 +212,9 @@ function Toc({toc}) {
);
}

function MobileToc({toc}) {
function MobileToc({toc, currentPage}) {
return (
<MobileOnPageNav>
<MobileOnPageNav currentPage={currentPage}>
{renderMobileToc(toc)}
</MobileOnPageNav>
);
Expand Down
12 changes: 8 additions & 4 deletions packages/dev/s2-docs/src/MobileHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
'use client';

import {ActionButton, DialogTrigger} from '@react-spectrum/s2';
import {AdobeLogo} from './icons/AdobeLogo';
import {getLibraryFromPage} from './library';
import {keyframes} from '../../../@react-spectrum/s2/style/style-macro' with {type: 'macro'};
import MenuHamburger from '@react-spectrum/s2/icons/MenuHamburger';
import {Modal} from '../../../@react-spectrum/s2/src/Modal';
import React, {CSSProperties, lazy, useEffect, useRef} from 'react';
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
import {TAB_DEFS} from './constants';

const MobileSearchMenu = lazy(() => import('./SearchMenu').then(({MobileSearchMenu}) => ({default: MobileSearchMenu})));

Expand Down Expand Up @@ -80,6 +81,9 @@ export function MobileHeader({toc, pages, currentPage}) {
}
}, []);

let currentLibrary = getLibraryFromPage(currentPage);
let icon = TAB_DEFS[currentLibrary].icon;

return (
<div
ref={ref}
Expand Down Expand Up @@ -123,8 +127,8 @@ export function MobileHeader({toc, pages, currentPage}) {
alignItems: 'center',
flexGrow: 1
})}>
<AdobeLogo />
<h2
{icon}
<h2
className={style({
font: 'heading-sm',
marginY: 0,
Expand All @@ -135,7 +139,7 @@ export function MobileHeader({toc, pages, currentPage}) {
animationTimeline: 'scroll()',
animationRange
} as CSSProperties : undefined}>
React Aria
{TAB_DEFS[currentLibrary].label}
</h2>
</div>
{toc && (
Expand Down
41 changes: 21 additions & 20 deletions packages/dev/s2-docs/src/MobileSearchMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import {type Library, TAB_DEFS} from './constants';
import NoSearchResults from '@react-spectrum/s2/illustrations/linear/NoSearchResults';
import {OverlayTriggerStateContext, Provider, Dialog as RACDialog, DialogProps as RACDialogProps, Tab as RACTab, TabList as RACTabList, TabPanel as RACTabPanel, TabPanelProps as RACTabPanelProps, TabProps as RACTabProps, Tabs as RACTabs, SelectionIndicator, TabRenderProps} from 'react-aria-components';
import type {PageProps} from '@parcel/rsc';
import React, {ReactNode, useCallback, useEffect, useMemo, useRef, useState} from 'react';
import React, {ReactNode, useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';
import {useId} from '@react-aria/utils';


interface MobileDialogProps extends Omit<RACDialogProps, 'className' | 'style'> {
size?: 'S' | 'M' | 'L' | 'fullscreen' | 'fullscreenTakeover',
isDismissible?: boolean,
Expand Down Expand Up @@ -208,7 +209,7 @@ const MobileCustomDialog = function MobileCustomDialog(props: MobileDialogProps)
};

function MobileNav({pages, currentPage}: PageProps) {
let overlayTriggerState = React.useContext(OverlayTriggerStateContext);
let overlayTriggerState = useContext(OverlayTriggerStateContext);
let [searchFocused, setSearchFocused] = useState(false);
let [searchValue, setSearchValue] = useState('');
let [selectedSection, setSelectedSection] = useState<string | undefined>(undefined);
Expand All @@ -218,7 +219,7 @@ function MobileNav({pages, currentPage}: PageProps) {

let getSectionsForLibrary = useCallback((libraryId: string) => {
let sectionsMap = new Map();
let filteredPages = pages.filter(page => getLibraryFromPage(page) === libraryId);
let filteredPages = pages.filter(page => getLibraryFromPage(page) === libraryId && !page.exports?.hideFromSearch);
for (let page of filteredPages) {
let section = page.exports?.section ?? 'Components';
let sectionPages = sectionsMap.get(section) ?? [];
Expand All @@ -243,7 +244,7 @@ function MobileNav({pages, currentPage}: PageProps) {
});
return sectionArray;
}, [getSectionsForLibrary, selectedLibrary]);


useEffect(() => {
// Auto-select first section initially or when library changes
Expand Down Expand Up @@ -296,9 +297,9 @@ function MobileNav({pages, currentPage}: PageProps) {
if (!searchValue.trim()) {
return pages;
}

let searchLower = searchValue.toLowerCase();

// Filter items where name or tags start with search value
let matchedPages = pages.filter(page => {
let pageTitle = title(page).toLowerCase();
Expand All @@ -307,19 +308,19 @@ function MobileNav({pages, currentPage}: PageProps) {
let tagMatch = tags.some(tag => tag.toLowerCase().startsWith(searchLower));
return nameMatch || tagMatch;
});

// Sort to prioritize name matches over tag matches
return matchedPages.sort((a, b) => {
let aNameMatch = title(a).toLowerCase().startsWith(searchLower);
let bNameMatch = title(b).toLowerCase().startsWith(searchLower);

if (aNameMatch && !bNameMatch) {
return -1;
}
if (!aNameMatch && bNameMatch) {
return 1;
}

// If both match by name or both match by tag, maintain original order
return 0;
});
Expand All @@ -328,9 +329,9 @@ function MobileNav({pages, currentPage}: PageProps) {
let getSectionContent = (sectionName: string, libraryId: string, searchValue: string = ''): ComponentCardItem[] => {
let librarySections = getSectionsForLibrary(libraryId);
let pages = librarySections.get(sectionName) ?? [];

let filteredPages = filterPages(pages, searchValue);

return filteredPages
.sort((a, b) => title(a).localeCompare(title(b)))
.map(page => ({id: page.url.replace(/^\//, ''), name: title(page), href: page.url}));
Expand All @@ -355,13 +356,13 @@ function MobileNav({pages, currentPage}: PageProps) {
} else {
items = getSectionContent(section, libraryId, searchValue);
}

// Sort to show "Introduction" first when search is empty
if (searchValue.trim().length === 0) {
items = [...items].sort((a, b) => {
const aIsIntro = a.name === 'Introduction';
const bIsIntro = b.name === 'Introduction';

if (aIsIntro && !bIsIntro) {
return -1;
}
Expand All @@ -371,14 +372,14 @@ function MobileNav({pages, currentPage}: PageProps) {
return 0;
});
}

return items;
};

let getSectionNamesForLibrary = (libraryId: string) => {
let librarySections = getSectionsForLibrary(libraryId);
let sectionArray = [...librarySections.keys()];

// Show 'Components' first
sectionArray.sort((a, b) => {
if (a === 'Components') {
Expand All @@ -389,7 +390,7 @@ function MobileNav({pages, currentPage}: PageProps) {
}
return a.localeCompare(b);
});

return sectionArray;
};

Expand Down Expand Up @@ -464,17 +465,17 @@ function MobileNav({pages, currentPage}: PageProps) {
{libraries.map(library => (
<MobileTabPanel key={library.id} id={library.id}>
<div className={stickySearchContainer}>
<SearchField
aria-label="Search"
<SearchField
aria-label="Search"
value={searchValue}
onChange={handleSearchChange}
onFocus={handleSearchFocus}
onBlur={handleSearchBlur}
styles={style({marginX: 16})} />
<div className={style({overflow: 'auto', paddingX: 8, paddingBottom: 8})}>
<TagGroup
aria-label="Navigation sections"
selectionMode="single"
aria-label="Navigation sections"
selectionMode="single"
selectedKeys={selectedSection ? [selectedSection] : []}
onSelectionChange={handleTagSelection}
UNSAFE_style={{whiteSpace: 'nowrap'}}
Expand Down
Loading