Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions packages/dev/s2-docs/pages/error.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Error from '../src/Error';
import {Layout} from '../src/Layout';
export default Layout;

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

<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
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>
);
}
33 changes: 20 additions & 13 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={<MobileToc key="toc" toc={currentPage.tableOfContents ?? []} />}
pages={pages}
currentPage={currentPage} />
currentPage={currentPage}
toc={<MobileToc key="toc" toc={currentPage.tableOfContents ?? []} currentPage={currentPage} />}
Copy link
Member

Choose a reason for hiding this comment

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

This will probably conflict with #8964, but feel free to keep this version.

pages={pages} />
<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}>
React Aria
{TAB_DEFS[currentLibrary].label}
</h2>
</div>
<div
Expand Down
39 changes: 20 additions & 19 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 Down Expand Up @@ -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
8 changes: 3 additions & 5 deletions packages/dev/s2-docs/src/Nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,11 @@ export function OnPageNav({children}) {
);
}

export function MobileOnPageNav({children}) {
export function MobileOnPageNav({children, currentPage}) {
let [selected, setSelected] = useState('');

useEffect(() => {
let elements = Array.from(document.querySelectorAll('article > :is(h1,h2,h3,h4,h5)'));
elements.reverse();

let visible = new Set();
let observer = new IntersectionObserver(entries => {
for (let entry of entries) {
Expand All @@ -225,7 +223,7 @@ export function MobileOnPageNav({children}) {
visible.delete(entry.target);
}
}

let lastVisible = elements.find(e => visible.has(e));
if (lastVisible) {
setSelected('#' + lastVisible.id!);
Expand All @@ -244,7 +242,7 @@ export function MobileOnPageNav({children}) {
}

return () => observer.disconnect();
}, []);
}, [currentPage]);

return (
<Picker aria-label="Table of contents" selectedKey={selected} isQuiet size="L">
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/s2-docs/src/VisualExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const exampleStyle = style({
const controlsStyle = style({
display: 'grid',
gridTemplateColumns: {
default: 'repeat(auto-fit, minmax(130px, 1fr))',
default: 'repeat(auto-fit, minmax(200px, 1fr))',
lg: ['1fr']
},
gridAutoFlow: 'dense',
Expand Down
Loading