Skip to content

Commit 97dc667

Browse files
LFDanLureidbarber
andauthored
fix: Assorted new docs fixes from testing (#8875)
* fix modal so it always appears over mobile header and fix dropzone width * add title font size resizing behavior to s2 docs * dont use useResizeObserver because we want to catch fonts changing * fix mobile header icon and library label * fix cross page anchor navigation scrolling and mobile cross page navigation scroll positioning * properly close mobile header menu when clicking on component card * making image coordinator example wrap to new row instead of squishing the images at small screen sizes * set a minwidth large enough so disallowEmptySelection have its label wrap * properly reobserve the new page post-navigation so the page nav picker updates during scroll on mobile this is because the page doesnt actually remount, we reuse the existing component tree * remove broken title resizer code and fix rebase * restore styles * fix internationalized logo * add 404 page * forgot to remove test code * hide error page from search * update S2 popover example * update icon in example --------- Co-authored-by: Reid Barber <reid@reidbarber.com>
1 parent 23bb07a commit 97dc667

File tree

14 files changed

+139
-85
lines changed

14 files changed

+139
-85
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import Error from '../src/Error';
2+
import {Layout} from '../src/Layout';
3+
export default Layout;
4+
5+
import docs from 'docs:@react-spectrum/s2';
6+
7+
export const hideFromSearch = true;
8+
9+
<Error />

packages/dev/s2-docs/pages/s2/DropZone.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ function Example(props) {
2121
return (
2222
<DropZone
2323
{...props}
24-
styles={style({width: 320})}
24+
styles={style({width: 320, maxWidth: '90%'})}
2525
/* PROPS */
2626
isFilled={!!content}
2727
// Determine whether dragged content should be accepted.
2828
getDropOperation={types => (
2929
['text/plain', 'image/jpeg', 'image/png', 'image/gif'].some(t => types.has(t))
30-
? 'copy'
30+
? 'copy'
3131
: 'cancel'
3232
)}
3333
onDrop={async (event) => {

packages/dev/s2-docs/pages/s2/Image.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
5656
<div
5757
className={style({
5858
display: 'grid',
59-
gridTemplateColumns: '1fr 1fr 1fr 1fr',
59+
gridTemplateColumns: 'repeat(auto-fit, minmax(140px, 1fr))',
6060
gridTemplateRows: [180],
6161
gap: 8
6262
})}>

packages/dev/s2-docs/pages/s2/Popover.mdx

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,34 +11,27 @@ export const tags = ['popup', 'overlay'];
1111

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

1818
function Example(props) {
1919
return (
2020
<DialogTrigger>
21-
<ActionButton aria-label="Filters">
22-
<Filter />
21+
<ActionButton aria-label="Feedback">
22+
<Feedback />
2323
</ActionButton>
2424
{/*- begin focus -*/}
2525
<Popover {...props}/* PROPS */>
26-
<Form>
27-
<CheckboxGroup label="Stops">
28-
<Checkbox value={0}>Non-stop</Checkbox>
29-
<Checkbox value={1}>1 stop</Checkbox>
30-
<Checkbox value={2}>2+ stops</Checkbox>
31-
</CheckboxGroup>
32-
<CheckboxGroup label="Bags">
33-
<Checkbox value={0}>Carry on</Checkbox>
34-
<Checkbox value={1}>Checked bag</Checkbox>
35-
</CheckboxGroup>
36-
<CheckboxGroup label="Times">
37-
<Checkbox value={0}>Morning</Checkbox>
38-
<Checkbox value={1}>Afternoon</Checkbox>
39-
<Checkbox value={2}>Evening</Checkbox>
40-
</CheckboxGroup>
41-
</Form>
26+
<div className={style({padding: 12})}>
27+
<p className={style({font: 'body', marginTop: 0})}>How are we doing? Share your feedback here.</p>
28+
<Form>
29+
<TextField label="Subject" placeholder="Enter a summary" />
30+
<TextField label="Description" isRequired placeholder="Enter your feedback" />
31+
<Switch>Adobe can contact me for further questions concerning this feedback</Switch>
32+
<Button styles={style({marginStart: 'auto'})}>Submit</Button>
33+
</Form>
34+
</div>
4235
</Popover>
4336
{/*- end focus -*/}
4437
</DialogTrigger>
@@ -65,17 +58,17 @@ function Example() {
6558
<Button onPress={() => setOpen(!isOpen)}>
6659
Open popover
6760
</Button>
68-
<div
61+
<div
6962
ref={triggerRef}
7063
className={style({
71-
padding: 8,
72-
backgroundColor: 'gray-100',
64+
padding: 8,
65+
backgroundColor: 'gray-100',
7366
borderRadius: 'default',
7467
font: 'ui'
7568
})}>
7669
Popover appears here
7770
</div>
78-
<Popover
71+
<Popover
7972
/*- begin highlight -*/
8073
triggerRef={triggerRef}
8174
isOpen={isOpen}

packages/dev/s2-docs/src/Error.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use client';
2+
3+
// eslint-disable-next-line monorepo/no-internal-import
4+
import BrowserError from '@react-spectrum/s2/illustrations/linear/BrowserError';
5+
import {Content, Heading, IllustratedMessage} from '@react-spectrum/s2';
6+
7+
export default function Error() {
8+
return (
9+
<div style={{display: 'flex', alignItems: 'center', height: '50vh', justifyContent: 'center', flexDirection: 'row'}}>
10+
<IllustratedMessage>
11+
<BrowserError />
12+
<Heading>Error 404: Page not found</Heading>
13+
<Content>This page isn't available. Try checking the URL or visit a different page.</Content>
14+
</IllustratedMessage>
15+
</div>
16+
);
17+
}

packages/dev/s2-docs/src/Layout.tsx

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,19 @@ const getDescription = (currentPage: Page): string => {
7474
return library ? `Documentation for ${pageTitle} in ${library}.` : `Documentation for ${pageTitle}.`;
7575
};
7676

77+
let articleStyles = style({
78+
maxWidth: {
79+
default: 'none',
80+
isWithToC: 768
81+
},
82+
width: 'full',
83+
height: 'fit'
84+
});
85+
86+
7787
export function Layout(props: PageProps & {children: ReactElement<any>}) {
7888
let {pages, currentPage, children} = props;
89+
let hasToC = currentPage.tableOfContents?.[0]?.children && currentPage.tableOfContents[0].children.length > 0;
7990
return (
8091
<Provider elementType="html" locale="en" background="layer-1" styles={style({scrollPaddingTop: {default: 64, lg: 0}})}>
8192
<head>
@@ -120,12 +131,12 @@ export function Layout(props: PageProps & {children: ReactElement<any>}) {
120131
})}>
121132
<Header pages={pages} currentPage={currentPage} />
122133
<MobileHeader
123-
toc={(currentPage.tableOfContents?.[0]?.children?.length ?? 0) > 0 ? <MobileToc key="toc" toc={currentPage.tableOfContents ?? []} /> : null}
134+
toc={(currentPage.tableOfContents?.[0]?.children?.length ?? 0) > 0 ? <MobileToc key="toc" toc={currentPage.tableOfContents ?? []} currentPage={currentPage} /> : null}
124135
pages={pages}
125136
currentPage={currentPage} />
126137
<div className={style({display: 'flex', width: 'full'})}>
127138
<Nav pages={pages} currentPage={currentPage} />
128-
<main
139+
<main
129140
key={currentPage.url}
130141
style={{borderBottomLeftRadius: 0, borderBottomRightRadius: 0}}
131142
className={style({
@@ -156,11 +167,7 @@ export function Layout(props: PageProps & {children: ReactElement<any>}) {
156167
}
157168
})}>
158169
<article
159-
className={style({
160-
maxWidth: 768,
161-
width: 'full',
162-
height: 'fit'
163-
})}>
170+
className={articleStyles({isWithToC: hasToC})}>
164171
{React.cloneElement(children, {components})}
165172
</article>
166173
<aside
@@ -177,10 +184,10 @@ export function Layout(props: PageProps & {children: ReactElement<any>}) {
177184
lg: 'block'
178185
}
179186
})}>
180-
{currentPage.tableOfContents?.[0]?.children && currentPage.tableOfContents[0].children.length > 0 && (
187+
{hasToC && (
181188
<div className={style({font: 'title', minHeight: 32, paddingX: 12, display: 'flex', alignItems: 'center'})}>Contents</div>
182189
)}
183-
<Toc toc={currentPage.tableOfContents?.[0]?.children ?? []} />
190+
<Toc toc={currentPage.tableOfContents?.[0]?.children ?? []} />
184191
</aside>
185192
</main>
186193
</div>
@@ -205,9 +212,9 @@ function Toc({toc}) {
205212
);
206213
}
207214

208-
function MobileToc({toc}) {
215+
function MobileToc({toc, currentPage}) {
209216
return (
210-
<MobileOnPageNav>
217+
<MobileOnPageNav currentPage={currentPage}>
211218
{renderMobileToc(toc)}
212219
</MobileOnPageNav>
213220
);

packages/dev/s2-docs/src/MobileHeader.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
'use client';
22

33
import {ActionButton, DialogTrigger} from '@react-spectrum/s2';
4-
import {AdobeLogo} from './icons/AdobeLogo';
4+
import {getLibraryFromPage} from './library';
55
import {keyframes} from '../../../@react-spectrum/s2/style/style-macro' with {type: 'macro'};
66
import MenuHamburger from '@react-spectrum/s2/icons/MenuHamburger';
77
import {Modal} from '../../../@react-spectrum/s2/src/Modal';
88
import React, {CSSProperties, lazy, useEffect, useRef} from 'react';
99
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
10+
import {TAB_DEFS} from './constants';
1011

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

@@ -80,6 +81,9 @@ export function MobileHeader({toc, pages, currentPage}) {
8081
}
8182
}, []);
8283

84+
let currentLibrary = getLibraryFromPage(currentPage);
85+
let icon = TAB_DEFS[currentLibrary].icon;
86+
8387
return (
8488
<div
8589
ref={ref}
@@ -123,8 +127,8 @@ export function MobileHeader({toc, pages, currentPage}) {
123127
alignItems: 'center',
124128
flexGrow: 1
125129
})}>
126-
<AdobeLogo />
127-
<h2
130+
{icon}
131+
<h2
128132
className={style({
129133
font: 'heading-sm',
130134
marginY: 0,
@@ -135,7 +139,7 @@ export function MobileHeader({toc, pages, currentPage}) {
135139
animationTimeline: 'scroll()',
136140
animationRange
137141
} as CSSProperties : undefined}>
138-
React Aria
142+
{TAB_DEFS[currentLibrary].label}
139143
</h2>
140144
</div>
141145
{toc && (

packages/dev/s2-docs/src/MobileSearchMenu.tsx

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ import {type Library, TAB_DEFS} from './constants';
99
import NoSearchResults from '@react-spectrum/s2/illustrations/linear/NoSearchResults';
1010
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';
1111
import type {PageProps} from '@parcel/rsc';
12-
import React, {ReactNode, useCallback, useEffect, useMemo, useRef, useState} from 'react';
12+
import React, {ReactNode, useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';
1313
import {useId} from '@react-aria/utils';
1414

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

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

219220
let getSectionsForLibrary = useCallback((libraryId: string) => {
220221
let sectionsMap = new Map();
221-
let filteredPages = pages.filter(page => getLibraryFromPage(page) === libraryId);
222+
let filteredPages = pages.filter(page => getLibraryFromPage(page) === libraryId && !page.exports?.hideFromSearch);
222223
for (let page of filteredPages) {
223224
let section = page.exports?.section ?? 'Components';
224225
let sectionPages = sectionsMap.get(section) ?? [];
@@ -243,7 +244,7 @@ function MobileNav({pages, currentPage}: PageProps) {
243244
});
244245
return sectionArray;
245246
}, [getSectionsForLibrary, selectedLibrary]);
246-
247+
247248

248249
useEffect(() => {
249250
// Auto-select first section initially or when library changes
@@ -296,9 +297,9 @@ function MobileNav({pages, currentPage}: PageProps) {
296297
if (!searchValue.trim()) {
297298
return pages;
298299
}
299-
300+
300301
let searchLower = searchValue.toLowerCase();
301-
302+
302303
// Filter items where name or tags start with search value
303304
let matchedPages = pages.filter(page => {
304305
let pageTitle = title(page).toLowerCase();
@@ -307,19 +308,19 @@ function MobileNav({pages, currentPage}: PageProps) {
307308
let tagMatch = tags.some(tag => tag.toLowerCase().startsWith(searchLower));
308309
return nameMatch || tagMatch;
309310
});
310-
311+
311312
// Sort to prioritize name matches over tag matches
312313
return matchedPages.sort((a, b) => {
313314
let aNameMatch = title(a).toLowerCase().startsWith(searchLower);
314315
let bNameMatch = title(b).toLowerCase().startsWith(searchLower);
315-
316+
316317
if (aNameMatch && !bNameMatch) {
317318
return -1;
318319
}
319320
if (!aNameMatch && bNameMatch) {
320321
return 1;
321322
}
322-
323+
323324
// If both match by name or both match by tag, maintain original order
324325
return 0;
325326
});
@@ -328,9 +329,9 @@ function MobileNav({pages, currentPage}: PageProps) {
328329
let getSectionContent = (sectionName: string, libraryId: string, searchValue: string = ''): ComponentCardItem[] => {
329330
let librarySections = getSectionsForLibrary(libraryId);
330331
let pages = librarySections.get(sectionName) ?? [];
331-
332+
332333
let filteredPages = filterPages(pages, searchValue);
333-
334+
334335
return filteredPages
335336
.sort((a, b) => title(a).localeCompare(title(b)))
336337
.map(page => ({id: page.url.replace(/^\//, ''), name: title(page), href: page.url}));
@@ -355,13 +356,13 @@ function MobileNav({pages, currentPage}: PageProps) {
355356
} else {
356357
items = getSectionContent(section, libraryId, searchValue);
357358
}
358-
359+
359360
// Sort to show "Introduction" first when search is empty
360361
if (searchValue.trim().length === 0) {
361362
items = [...items].sort((a, b) => {
362363
const aIsIntro = a.name === 'Introduction';
363364
const bIsIntro = b.name === 'Introduction';
364-
365+
365366
if (aIsIntro && !bIsIntro) {
366367
return -1;
367368
}
@@ -371,14 +372,14 @@ function MobileNav({pages, currentPage}: PageProps) {
371372
return 0;
372373
});
373374
}
374-
375+
375376
return items;
376377
};
377378

378379
let getSectionNamesForLibrary = (libraryId: string) => {
379380
let librarySections = getSectionsForLibrary(libraryId);
380381
let sectionArray = [...librarySections.keys()];
381-
382+
382383
// Show 'Components' first
383384
sectionArray.sort((a, b) => {
384385
if (a === 'Components') {
@@ -389,7 +390,7 @@ function MobileNav({pages, currentPage}: PageProps) {
389390
}
390391
return a.localeCompare(b);
391392
});
392-
393+
393394
return sectionArray;
394395
};
395396

@@ -464,17 +465,17 @@ function MobileNav({pages, currentPage}: PageProps) {
464465
{libraries.map(library => (
465466
<MobileTabPanel key={library.id} id={library.id}>
466467
<div className={stickySearchContainer}>
467-
<SearchField
468-
aria-label="Search"
468+
<SearchField
469+
aria-label="Search"
469470
value={searchValue}
470471
onChange={handleSearchChange}
471472
onFocus={handleSearchFocus}
472473
onBlur={handleSearchBlur}
473474
styles={style({marginX: 16})} />
474475
<div className={style({overflow: 'auto', paddingX: 8, paddingBottom: 8})}>
475476
<TagGroup
476-
aria-label="Navigation sections"
477-
selectionMode="single"
477+
aria-label="Navigation sections"
478+
selectionMode="single"
478479
selectedKeys={selectedSection ? [selectedSection] : []}
479480
onSelectionChange={handleTagSelection}
480481
UNSAFE_style={{whiteSpace: 'nowrap'}}

0 commit comments

Comments
 (0)