Skip to content

Commit 8e7a57d

Browse files
authored
docs: UI improvements (#9098)
* Adjust heading to fit viewport * Allow horizontal scrolling in code examples instead of wrapping * Automatically set library so sandbox links work everywhere * Add additional aria groupings/labels * lint
1 parent 5c62b4d commit 8e7a57d

File tree

12 files changed

+217
-41
lines changed

12 files changed

+217
-41
lines changed

packages/@react-spectrum/s2/style/spectrum-theme.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -760,10 +760,14 @@ export const style = createTheme({
760760
code: 'source-code-pro, "Source Code Pro", Monaco, monospace'
761761
},
762762
fontSize: new ExpandedProperty<keyof typeof fontSize>(['fontSize', 'lineHeight'], (value) => {
763-
return {
764-
'--fs': `pow(1.125, ${value})`,
765-
fontSize: `round(${fontSizeCalc} / 16 * 1rem, 1px)`
766-
};
763+
if (typeof value === 'number') {
764+
return {
765+
'--fs': `pow(1.125, ${value})`,
766+
fontSize: `round(${fontSizeCalc} / 16 * 1rem, 1px)`
767+
} as CSSProperties;
768+
}
769+
770+
return {fontSize: value};
767771
}, fontSize),
768772
fontWeight: new ExpandedProperty<keyof typeof fontWeight>(['fontWeight', 'fontVariationSettings', 'fontSynthesisWeight'], (value) => {
769773
return {

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ export default Layout;
55
import docs from 'docs:@react-spectrum/s2';
66

77
export const tags = ['box'];
8+
export const version = 'alpha';
89

9-
# SelectBoxGroup <VersionBadge version="alpha" />
10+
# SelectBoxGroup
1011

1112
<PageDescription>{docs.exports.SelectBoxGroup.description}</PageDescription>
1213

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import {InterfaceType} from '../../src/types';
77
import {VersionBadge} from '../../src/VersionBadge';
88

99
export const tags = ['snackbar', 'notification', 'alert'];
10+
export const version = 'alpha';
1011

11-
# Toast <VersionBadge version="alpha" />
12+
# Toast
1213

1314
<PageDescription>{docs.exports.UNSTABLE_ToastContainer.description}</PageDescription>
1415

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@ const mark = style({
2828
borderWidth: 0,
2929
borderStartWidth: 2,
3030
borderStyle: 'solid',
31-
marginX: 'calc(var(--code-padding-x) * -1)',
32-
paddingX: 'calc(var(--code-padding-x) - self(borderStartWidth))',
31+
marginStart: 'calc(var(--code-padding-start) * -1)',
32+
marginEnd: 'calc(var(--code-padding-end) * -1)',
33+
paddingStart: 'calc(var(--code-padding-start) - self(borderStartWidth))',
34+
paddingEnd: '--code-padding-end',
3335
color: 'inherit'
3436
});
3537

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

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,15 @@ const example = style({
2424
});
2525

2626
const standaloneCode = style({
27-
'--code-padding-x': {
28-
type: 'paddingTop',
27+
'--code-padding-start': {
28+
type: 'paddingStart',
2929
value: 32
3030
},
31-
padding: '--code-padding-x',
31+
'--code-padding-end': {
32+
type: 'paddingEnd',
33+
value: 32
34+
},
35+
padding: '--code-padding-start',
3236
marginY: 32,
3337
backgroundColor: 'layer-1',
3438
borderRadius: 'xl',
@@ -89,7 +93,7 @@ export function CodeBlock({render, children, files, expanded, hidden, hideExampl
8993
);
9094

9195
return (
92-
<div className={example}>
96+
<div role="group" aria-label="Example" className={example}>
9397
<ExampleOutput
9498
component={render}
9599
align={props.align} />
@@ -128,9 +132,11 @@ function TruncatedCode({children, maxLines = 6, ...props}: TruncatedCodeProps) {
128132
</ExpandableCode>
129133
)
130134
: (
131-
<Pre>
132-
<Code {...props}>{children}</Code>
133-
</Pre>
135+
<div className={style({overflow: 'auto'})}>
136+
<Pre>
137+
<Code {...props}>{children}</Code>
138+
</Pre>
139+
</div>
134140
);
135141
}
136142

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

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,30 @@ import {createStackBlitz} from './StackBlitz';
77
import Download from '@react-spectrum/s2/icons/Download';
88
import {iconStyle, style} from '@react-spectrum/s2/style' with {type: 'macro'};
99
import {Key} from 'react-aria';
10+
import {Library} from './library';
1011
import LinkIcon from '@react-spectrum/s2/icons/Link';
1112
import OpenIn from '@react-spectrum/s2/icons/OpenIn';
1213
import Polygon4 from '@react-spectrum/s2/icons/Polygon4';
1314
import Prompt from '@react-spectrum/s2/icons/Prompt';
14-
import React, {ReactNode, useEffect, useRef, useState} from 'react';
15+
import React, {createContext, ReactNode, useContext, useEffect, useRef, useState} from 'react';
1516
import {zip} from './zip';
1617

1718
const platterStyle = style({
1819
backgroundColor: 'layer-2',
1920
borderRadius: 'lg',
20-
'--code-padding-x': {
21-
type: 'paddingTop',
21+
'--code-padding-start': {
22+
type: 'paddingStart',
23+
value: 16
24+
},
25+
'--code-padding-end': {
26+
type: 'paddingEnd',
2227
value: 16
2328
},
2429
'--code-padding-y': {
2530
type: 'paddingTop',
2631
value: 16
2732
},
28-
position: 'relative',
29-
maxHeight: 600,
30-
overflow: 'auto'
33+
position: 'relative'
3134
});
3235

3336
interface CodePlatterProps {
@@ -38,21 +41,38 @@ interface CodePlatterProps {
3841
registryUrl?: string
3942
}
4043

44+
interface CodePlatterContextValue {
45+
library: Library
46+
}
47+
48+
const CodePlatterContext = createContext<CodePlatterContextValue>({library: 'react-spectrum'});
49+
export function CodePlatterProvider(props: CodePlatterContextValue & {children: any}) {
50+
return <CodePlatterContext.Provider value={props}>{props.children}</CodePlatterContext.Provider>;
51+
}
52+
4153
export function CodePlatter({children, shareUrl, files, type, registryUrl}: CodePlatterProps) {
4254
let codeRef = useRef<HTMLDivElement | null>(null);
4355
let [showShadcn, setShowShadcn] = useState(false);
4456
let getText = () => codeRef.current!.querySelector('pre')!.textContent!;
57+
let {library} = useContext(CodePlatterContext);
58+
if (!type) {
59+
if (library === 'react-aria') {
60+
type = 'vanilla';
61+
} else if (library === 'react-spectrum') {
62+
type = 's2';
63+
}
64+
}
4565

4666
return (
4767
<div className={platterStyle}>
48-
<div className={style({display: 'flex', justifyContent: 'end', float: 'inline-end', padding: 16, position: 'relative', zIndex: 1})}>
68+
<div className={style({display: 'flex', justifyContent: 'end', padding: 4, position: 'absolute', top: 8, insetEnd: 8, backgroundColor: 'layer-2', boxShadow: 'elevated', borderRadius: 'default', zIndex: 1})}>
4969
<ActionButtonGroup
5070
orientation="vertical"
5171
isQuiet
5272
density="regular"
5373
size="S">
5474
<CopyButton ariaLabel="Copy code" tooltip="Copy code" getText={getText} />
55-
{(shareUrl || files || type || registryUrl) && <MenuTrigger>
75+
{(shareUrl || files || type || registryUrl) && <MenuTrigger align="end">
5676
<TooltipTrigger placement="end">
5777
<ActionButton aria-label="Open in…">
5878
<OpenIn />
@@ -167,9 +187,23 @@ export function CodePlatter({children, shareUrl, files, type, registryUrl}: Code
167187
);
168188
}
169189

190+
const pre = style({
191+
borderRadius: 'lg',
192+
font: {
193+
default: 'code-xs',
194+
lg: 'code-sm'
195+
},
196+
margin: 0,
197+
paddingStart: '--code-padding-start',
198+
paddingEnd: '--code-padding-end',
199+
paddingY: '--code-padding-y',
200+
width: 'fit',
201+
minWidth: 'full'
202+
});
203+
170204
export function Pre({children}) {
171205
return (
172-
<pre className={style({borderRadius: 'lg', font: {default: 'code-xs', lg: 'code-sm'}, whiteSpace: 'pre-wrap', margin: 0, paddingX: '--code-padding-x', paddingY: '--code-padding-y'})} style={{overflowWrap: 'break-word'}}>
206+
<pre className={pre}>
173207
{children}
174208
</pre>
175209
);
@@ -250,7 +284,7 @@ function ShadcnDialog({registryUrl}) {
250284
flexDirection: 'column',
251285
gap: 16
252286
})}>
253-
<SegmentedControl selectedKey={packageManager} onSelectionChange={onSelectionChange}>
287+
<SegmentedControl aria-label="Package manager" selectedKey={packageManager} onSelectionChange={onSelectionChange}>
254288
<SegmentedControlItem id="npm">npm</SegmentedControlItem>
255289
<SegmentedControlItem id="yarn">yarn</SegmentedControlItem>
256290
<SegmentedControlItem id="pnpm">pnpm</SegmentedControlItem>

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ interface ExampleOutputProps {
1212

1313
export function ExampleOutput({component, props = {}, align = 'center', orientation = 'horizontal'}: ExampleOutputProps) {
1414
return (
15-
<div
15+
<div
16+
role="group"
17+
aria-label="Rendered component"
1618
className={style({
1719
display: 'flex',
1820
flexDirection: {

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

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

3+
import {Content, ContextualHelp, Heading, Picker, PickerItem, SegmentedControl, SegmentedControlItem} from '@react-spectrum/s2';
34
import {createContext, useEffect, useState} from 'react';
45
import {Key} from 'react-aria-components';
5-
import {Picker, PickerItem, SegmentedControl, SegmentedControlItem} from '@react-spectrum/s2';
66
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
77

88
const exampleStyle = style({
@@ -123,7 +123,7 @@ export function ExampleSwitcher({type = 'style', examples = DEFAULT_EXAMPLES, ch
123123
return (
124124
<div className={exampleStyle} data-example-switcher>
125125
<div className={switcher}>
126-
<SegmentedControl selectedKey={selected} onSelectionChange={onSelectionChange}>
126+
<SegmentedControl aria-label={type || 'example'} selectedKey={selected} onSelectionChange={onSelectionChange}>
127127
{examples.map(example => <SegmentedControlItem key={example} id={example}>{example}</SegmentedControlItem>)}
128128
</SegmentedControl>
129129
</div>
@@ -133,7 +133,13 @@ export function ExampleSwitcher({type = 'style', examples = DEFAULT_EXAMPLES, ch
133133
labelPosition="side"
134134
value={theme}
135135
onChange={onThemeChange}
136-
styles={themePicker}>
136+
styles={themePicker}
137+
contextualHelp={
138+
<ContextualHelp>
139+
<Heading>Vanilla CSS theme</Heading>
140+
<Content>This sets the <code className={style({font: 'code-sm'})}>--tint</code> CSS variable used by the Vanilla CSS examples.</Content>
141+
</ContextualHelp>
142+
}>
137143
<PickerItem id="indigo">Indigo</PickerItem>
138144
<PickerItem id="blue">Blue</PickerItem>
139145
<PickerItem id="cyan">Cyan</PickerItem>

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

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ const example = style({
99
font: 'code-lg',
1010
maxHeight: {
1111
default: '[6lh]',
12-
isExpanded: 'unset'
12+
isExpanded: 800
1313
},
1414
overflow: {
1515
default: 'clip',
16-
isExpanded: 'visible'
16+
isExpanded: 'auto'
1717
},
1818
position: 'relative',
1919
width: 'full',
@@ -24,6 +24,13 @@ const example = style({
2424
default: 'none',
2525
isExpanded: 'inline'
2626
}
27+
},
28+
'--code-padding-end': {
29+
type: 'paddingEnd',
30+
value: {
31+
default: 16,
32+
isExpanded: 64 // Extra space for the toolbar
33+
}
2734
}
2835
});
2936

@@ -50,8 +57,8 @@ export function ExpandableCode({children, hasHighlightedLine}: {children: ReactN
5057
mask = 'linear-gradient(transparent, white 25% 50%, transparent), linear-gradient(to right, white 0% 85%, transparent)';
5158
padding = '0px';
5259
} else {
53-
// only mask the bottom
54-
mask = 'linear-gradient(white 0% 50%, transparent)';
60+
// only mask the bottom and right
61+
mask = 'linear-gradient(white 0% 50%, transparent), linear-gradient(to right, white 0% 85%, transparent)';
5562
}
5663
}
5764

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

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ import './anatomy.css';
1212
import {ClassAPI} from './ClassAPI';
1313
import {Code} from './Code';
1414
import {CodeBlock} from './CodeBlock';
15+
import {CodePlatterProvider} from './CodePlatter';
1516
import {ExampleSwitcher} from './ExampleSwitcher';
16-
import {getLibraryFromPage, getLibraryLabel} from './library';
17+
import {getLibraryFromPage, getLibraryFromUrl, getLibraryLabel} from './library';
18+
import {getTextWidth} from './textWidth';
1719
import {H2, H3, H4} from './Headings';
1820
import Header from './Header';
1921
import {Link} from './Link';
@@ -23,10 +25,21 @@ import {PropTable} from './PropTable';
2325
import {StateTable} from './StateTable';
2426
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
2527
import {TypeLink} from './types';
28+
import {VersionBadge} from './VersionBadge';
2629
import {VisualExample} from './VisualExample';
2730

31+
const h1 = style({
32+
font: 'heading-3xl',
33+
fontSize: {
34+
// On mobile, adjust heading to fit in the viewport, and clamp between a min and max font size.
35+
default: 'clamp(35px, (100vw - 32px) / var(--width-per-em), 55px)',
36+
lg: 'heading-3xl'
37+
},
38+
marginY: 0
39+
});
40+
2841
const components = {
29-
h1: ({children, ...props}) => <h1 {...props} id="top" className={style({font: {default: 'heading-2xl', lg: 'heading-3xl'}, marginY: 0})}>{children}</h1>,
42+
h1: ({children, ...props}) => <h1 {...props} id="top" style={{'--width-per-em': getTextWidth(children)} as any} className={h1}>{children}</h1>,
3043
h2: H2,
3144
h3: H3,
3245
h4: H4,
@@ -226,10 +239,13 @@ export function Layout(props: PageProps & {children: ReactElement<any>}) {
226239
lg: 'auto'
227240
}
228241
})}>
229-
<article
230-
className={articleStyles({isWithToC: hasToC})}>
231-
{React.cloneElement(children, {components})}
232-
</article>
242+
<CodePlatterProvider library={getLibraryFromUrl(currentPage.url)}>
243+
<article
244+
className={articleStyles({isWithToC: hasToC})}>
245+
{currentPage.exports?.version && <VersionBadge version={currentPage.exports.version} />}
246+
{React.cloneElement(children, {components})}
247+
</article>
248+
</CodePlatterProvider>
233249
{hasToC && <aside
234250
className={style({
235251
position: 'sticky',

0 commit comments

Comments
 (0)