Skip to content
Merged
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
6 changes: 6 additions & 0 deletions packages/@internationalized/date/src/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ export function parseTime(value: string): Time {
export function parseDate(value: string): CalendarDate {
let m = value.match(DATE_RE);
if (!m) {
if (ABSOLUTE_RE.test(value)) {
throw new Error(`Invalid ISO 8601 date string: ${value}. Use parseAbsolute() instead.`);
}
throw new Error('Invalid ISO 8601 date string: ' + value);
}

Expand All @@ -63,6 +66,9 @@ export function parseDate(value: string): CalendarDate {
export function parseDateTime(value: string): CalendarDateTime {
let m = value.match(DATE_TIME_RE);
if (!m) {
if (ABSOLUTE_RE.test(value)) {
throw new Error(`Invalid ISO 8601 date time string: ${value}. Use parseAbsolute() instead.`);
}
throw new Error('Invalid ISO 8601 date time string: ' + value);
}

Expand Down
18 changes: 18 additions & 0 deletions packages/@internationalized/date/tests/string.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@ describe('string conversion', function () {
expect(() => parseDate('2020-02-30')).toThrow();
expect(() => parseDate('2024-01-00')).toThrow();
});

it('should provide helpful error when passed an absolute datetime string', function () {
expect(() => parseDate('2023-10-07T12:34:56.789Z')).toThrow(/parseAbsolute/);
const isoString = new Date('2023-10-07T12:00:00Z').toISOString();
expect(() => parseDate(isoString)).toThrow(/parseAbsolute/);
expect(() => parseDate('2020-02-03T12:23:24Z')).toThrow(/parseAbsolute/);
expect(() => parseDate('2020-02-03T12:23:24+05:00')).toThrow(/parseAbsolute/);
expect(() => parseDate('2020-02-03T12:23:24-08:00')).toThrow(/parseAbsolute/);
});
});

describe('CalendarDate#toString', function () {
Expand Down Expand Up @@ -195,6 +204,15 @@ describe('string conversion', function () {
expect(() => parseDateTime('2020-02-03T23:99')).toThrow();
expect(() => parseDateTime('2020-02-03T12:22:99')).toThrow();
});

it('should provide helpful error when passed an absolute datetime string', function () {
expect(() => parseDateTime('2023-10-07T12:34:56.789Z')).toThrow(/parseAbsolute/);
const isoString = new Date('2023-10-07T12:00:00Z').toISOString();
expect(() => parseDateTime(isoString)).toThrow(/parseAbsolute/);
expect(() => parseDateTime('2020-02-03T12:23:24Z')).toThrow(/parseAbsolute/);
expect(() => parseDateTime('2020-02-03T12:23:24+05:00')).toThrow(/parseAbsolute/);
expect(() => parseDateTime('2020-02-03T12:23:24-08:00')).toThrow(/parseAbsolute/);
});
});

describe('CalendarDateTime#toString', function () {
Expand Down
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
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
Loading
Loading