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
34 changes: 28 additions & 6 deletions packages/@react-spectrum/s2/src/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {AvatarContext} from './Avatar';
import {ButtonContext, LinkButtonContext} from './Button';
import {Checkbox} from './Checkbox';
import {color, focusRing, lightDark, space, style} from '../style' with {type: 'macro'};
import {composeRenderProps, ContextValue, DEFAULT_SLOT, type GridListItem, GridListItemProps, Provider} from 'react-aria-components';
import {composeRenderProps, ContextValue, DEFAULT_SLOT, type GridListItem, GridListItemProps, Link, Provider} from 'react-aria-components';
import {ContentContext, FooterContext, TextContext} from './Content';
import {createContext, CSSProperties, forwardRef, ReactNode, useContext} from 'react';
import {DividerContext} from './Divider';
Expand Down Expand Up @@ -95,18 +95,19 @@ let card = style({
variant: {
tertiary: {
// Render border with box-shadow to avoid affecting layout.
default: `[0 0 0 1px ${color('gray-100')}]`,
isHovered: `[0 0 0 1px ${color('gray-200')}]`,
isFocusVisible: `[0 0 0 1px ${color('gray-200')}]`,
default: `[0 0 0 2px ${color('gray-100')}]`,
isHovered: `[0 0 0 2px ${color('gray-200')}]`,
isFocusVisible: `[0 0 0 2px ${color('gray-200')}]`,
isSelected: 'none',
forcedColors: '[0 0 0 1px ButtonBorder]'
forcedColors: '[0 0 0 2px ButtonBorder]'
},
quiet: 'none'
}
},
forcedColorAdjust: 'none',
transition: 'default',
fontFamily: 'sans',
textDecoration: 'none',
overflow: {
default: 'clip',
variant: {
Expand Down Expand Up @@ -424,6 +425,28 @@ export const Card = forwardRef(function Card(props: CardProps, ref: DOMRef<HTMLD
</Provider>
);

let press = pressScale(domRef, UNSAFE_style);
if (ElementType === 'div' && !isSkeleton && props.href) {
// Standalone Card that has an href should be rendered as a Link.
// NOTE: In this case, the card must not contain interactive elements.
Copy link
Member Author

Choose a reason for hiding this comment

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

We don't really have a way to enforce this...

return (
<Link
{...filterDOMProps(otherProps, {isLink: true})}
ref={domRef as any}
className={renderProps => UNSAFE_className + card({...renderProps, size, density, variant, isCardView: false, isLink: true}, styles)}
style={renderProps =>
// Only the preview in quiet cards scales down on press
variant === 'quiet' ? UNSAFE_style : press(renderProps)
}>
{(renderProps) => (
<InternalCardContext.Provider value={{size, isQuiet, isCheckboxSelection: false, isSelected: false, ...renderProps}}>
{children}
</InternalCardContext.Provider>
)}
</Link>
);
}

if (ElementType === 'div' || isSkeleton) {
return (
<div
Expand All @@ -441,7 +464,6 @@ export const Card = forwardRef(function Card(props: CardProps, ref: DOMRef<HTMLD
);
}

let press = pressScale(domRef, UNSAFE_style);
return (
<ElementType
{...props}
Expand Down
8 changes: 2 additions & 6 deletions packages/@react-spectrum/s2/style/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,14 @@
*/

import type * as CSS from 'csstype';
import {Inset, fontRelative as internalFontRelative, size as internalSize, space as internalSpace, Spacing, style} from './spectrum-theme';
import {Inset, fontRelative as internalFontRelative, space as internalSpace, Spacing, style} from './spectrum-theme';
import type {MacroContext} from '@parcel/macros';
import {StyleString} from './types';

export {baseColor, color, edgeToText, lightDark, linearGradient, colorMix, style} from './spectrum-theme';
export {baseColor, color, edgeToText, lightDark, linearGradient, colorMix, size, style} from './spectrum-theme';
export type {StyleString} from './types';

// Wrap these functions in arbitrary value syntax when called from the outside.
export function size(px: number): `[${string}]` {
return `[${internalSize(px)}]`;
}

export function space(px: number): `[${string}]` {
return `[${internalSpace(px)}]`;
}
Expand Down
5 changes: 1 addition & 4 deletions packages/@react-spectrum/s2/style/spectrum-theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ const padding = {
...relativeSpacing
};

export function size(this: MacroContext | void, px: number): string {
export function size(this: MacroContext | void, px: number): `calc(${string})` {
return `calc(${pxToRem(px)} * var(--s2-scale))`;
}

Expand Down Expand Up @@ -767,9 +767,6 @@ export const style = createTheme({
}, fontSize),
fontWeight: new ExpandedProperty<keyof typeof fontWeight>(['fontWeight', 'fontVariationSettings', 'fontSynthesisWeight'], (value) => {
return {
// Set font-variation-settings in addition to font-weight to work around typekit issue.
// (This was fixed, but leaving for backward compatibility for now.)
fontVariationSettings: value === 'inherit' ? 'inherit' : `"wght" ${value}`,
fontWeight: value as any,
fontSynthesisWeight: 'none'
};
Expand Down
8 changes: 6 additions & 2 deletions packages/@react-stately/layout/src/WaterfallLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,12 @@ export interface WaterfallLayoutOptions {

class WaterfallLayoutInfo extends LayoutInfo {
column = 0;
index = 0;

copy(): WaterfallLayoutInfo {
let res = super.copy() as WaterfallLayoutInfo;
res.column = this.column;
res.index = this.index;
return res;
}
}
Expand Down Expand Up @@ -123,18 +125,19 @@ export class WaterfallLayout<T extends object, O extends WaterfallLayoutOptions
// Setup an array of column heights
let columnHeights = Array(numColumns).fill(minSpace.height);
let newLayoutInfos = new Map();
let index = 0;
let addNode = (key: Key, node: Node<T>) => {
let oldLayoutInfo = this.layoutInfos.get(key);
let height = itemHeight;
let estimatedSize = true;
if (oldLayoutInfo) {
height = oldLayoutInfo.rect.height;
height = oldLayoutInfo.rect.height / oldLayoutInfo.rect.width * itemWidth;
Copy link
Member Author

Choose a reason for hiding this comment

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

If the card size changes (e.g. user drags slider in photo library example), re-calculate the height proportionally.

estimatedSize = invalidationContext.sizeChanged || oldLayoutInfo.estimatedSize || oldLayoutInfo.content !== node;
}

// Figure out which column to place the item in, and compute its position.
// Preserve the previous column index so items don't jump around during resizing unless the number of columns changed.
let prevColumn = numColumns === this.numColumns && oldLayoutInfo && oldLayoutInfo.rect.y < this.virtualizer!.visibleRect.maxY ? oldLayoutInfo.column : undefined;
let prevColumn = numColumns === this.numColumns && oldLayoutInfo && oldLayoutInfo.index === index && oldLayoutInfo.rect.y < this.virtualizer!.visibleRect.maxY ? oldLayoutInfo.column : undefined;
Copy link
Member Author

Choose a reason for hiding this comment

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

Don't preserve the column if the index within the collection changed. When filtering the photo library, the cards were staying where they were previously, resulting in "holes" appearing. We want to re-flow in this case.

let column = prevColumn ?? columnHeights.reduce((minIndex, h, i) => h < columnHeights[minIndex] ? i : minIndex, 0);
let x = horizontalSpacing + column * (itemWidth + horizontalSpacing) + this.margin;
let y = columnHeights[column];
Expand All @@ -145,6 +148,7 @@ export class WaterfallLayout<T extends object, O extends WaterfallLayoutOptions
layoutInfo.allowOverflow = true;
layoutInfo.content = node;
layoutInfo.column = column;
layoutInfo.index = index++;
newLayoutInfos.set(key, layoutInfo);

columnHeights[column] += layoutInfo.rect.height + minSpace.height;
Expand Down
1 change: 1 addition & 0 deletions packages/dev/s2-docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"@react-spectrum/utils": "^3.12.6",
"@react-types/shared": "^3.30.0",
"@react-types/textfield": "^3.12.3",
"emojibase-data": "^16.0.3",
"fast-glob": "^3.3.3",
"globals-docs": "^2.4.1",
"gray-matter": "^4.0.3",
Expand Down
1 change: 1 addition & 0 deletions packages/dev/s2-docs/pages/error.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export default Layout;
import docs from 'docs:@react-spectrum/s2';

export const hideFromSearch = true;
export const hideNav = true;
export const description = 'Page not found';

<Error />
13 changes: 8 additions & 5 deletions packages/dev/s2-docs/pages/react-aria/Autocomplete.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,8 @@ function Example(props) {
"use client";
import {Select, Label, SelectValue, Autocomplete, useFilter} from 'react-aria-components';
import {Button} from 'vanilla-starter/Button';
import {SelectItem} from 'vanilla-starter/Select';
import {SelectListBox, SelectItem} from 'vanilla-starter/Select';
import {Popover} from 'vanilla-starter/Popover';
import {ListBox} from 'vanilla-starter/ListBox';
import {SearchField} from 'vanilla-starter/SearchField';
import {ChevronDown} from 'lucide-react';

Expand Down Expand Up @@ -232,7 +231,7 @@ function Example(props) {
<SelectValue />
<ChevronDown size={18} />
</Button>
<Popover hideArrow style={{display: 'flex', flexDirection: 'column'}}>
<Popover hideArrow className="select-popover" style={{display: 'flex', flexDirection: 'column'}}>
{/*- begin highlight -*/}
<Autocomplete {...props}/* PROPS */ filter={contains}>
{/*- end highlight -*/}
Expand All @@ -241,12 +240,12 @@ function Example(props) {
aria-label="Search states"
placeholder="Search states"
style={{margin: 4}} />
<ListBox
<SelectListBox
items={states}
renderEmptyState={() => 'No results.'}
style={{flex: 1}}>
{state => <SelectItem>{state.name}</SelectItem>}
</ListBox>
</SelectListBox>
</Autocomplete>
</Popover>
</Select>
Expand Down Expand Up @@ -1101,6 +1100,10 @@ function AsyncLoadingExample() {
}
```

## Examples

<ExampleList tag="autocomplete" pages={props.pages} />

## API

```tsx links={{Autocomplete: '#autocomplete', SearchField: 'SearchField.html', TextField: 'TextField.html', Menu: 'Menu.html', ListBox: 'ListBox.html', TagGroup: 'TagGroup.html', GridList: 'GridList.html', Table: 'Table.html'}}
Expand Down
4 changes: 4 additions & 0 deletions packages/dev/s2-docs/pages/react-aria/Button.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ import {Link} from 'react-aria-components';
</Link>
```

## Examples

<ExampleList tag="button" pages={props.pages} />

## API

<PropTable component={docs.exports.Button} links={docs.links} />
4 changes: 4 additions & 0 deletions packages/dev/s2-docs/pages/react-aria/DropZone.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ export const tags = ['file', 'drag', 'dnd', 'upload'];
```
</ExampleSwitcher>

## Examples

<ExampleList tag="dropzone" pages={props.pages} />

## API

```tsx links={{DropZone: '#dropzone'}}
Expand Down
4 changes: 4 additions & 0 deletions packages/dev/s2-docs/pages/react-aria/Form.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,10 @@ function Example() {
}
```

## Examples

<ExampleList tag="form" pages={props.pages} />

## API

<PropTable component={docs.exports.Form} links={docs.links} />
4 changes: 4 additions & 0 deletions packages/dev/s2-docs/pages/react-aria/GridList.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,10 @@ function Example() {
}
```

## Examples

<ExampleList tag="gridlist" pages={props.pages} />

## API

<Anatomy role="img" aria-label="Anatomy diagram of a list container, consisting of multiple list items. Each list item contains a drag button, a selection checkbox, an icon, a title, and a description." />
Expand Down
4 changes: 4 additions & 0 deletions packages/dev/s2-docs/pages/react-aria/ListBox.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,10 @@ function Example() {
}
```

## Examples

<ExampleList tag="listbox" pages={props.pages} />

## API

<Anatomy role="img" aria-label="Anatomy diagram of a list container, consisting of multiple list items. Each list item contains a label and description. The items are grouped into a section with a header." />
Expand Down
4 changes: 4 additions & 0 deletions packages/dev/s2-docs/pages/react-aria/Menu.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,10 @@ import {ChevronDown} from 'lucide-react';
</MenuTrigger>
```

## Examples

<ExampleList tag="menu" pages={props.pages} />

## API

<Anatomy />
Expand Down
4 changes: 4 additions & 0 deletions packages/dev/s2-docs/pages/react-aria/Modal.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ const CustomTrigger = React.forwardRef((props, ref) => (
));
```

## Examples

<ExampleList tag="modal" pages={props.pages} />

## API

<Anatomy />
Expand Down
4 changes: 4 additions & 0 deletions packages/dev/s2-docs/pages/react-aria/Popover.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ function Example() {
}
```

## Examples

<ExampleList tag="popover" pages={props.pages} />

## API

<Anatomy />
Expand Down
4 changes: 4 additions & 0 deletions packages/dev/s2-docs/pages/react-aria/SearchField.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ function Example(props) {
}
```

## Examples

<ExampleList tag="searchfield" pages={props.pages} />

## API

<Anatomy />
Expand Down
18 changes: 9 additions & 9 deletions packages/dev/s2-docs/pages/react-aria/Select.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,8 @@ function Example() {
"use client";
import {Select, Label, SelectValue, Autocomplete, useFilter} from 'react-aria-components';
import {Button} from 'vanilla-starter/Button';
import {SelectItem} from 'vanilla-starter/Select';
import {SelectListBox, SelectItem} from 'vanilla-starter/Select';
import {Popover} from 'vanilla-starter/Popover';
import {ListBox} from 'vanilla-starter/ListBox';
import {SearchField} from 'vanilla-starter/SearchField';
import {ChevronDown} from 'lucide-react';

Expand All @@ -119,11 +118,11 @@ function Example() {
<SelectValue />
<ChevronDown size={18} />
</Button>
<Popover hideArrow>
<Popover hideArrow className="select-popover">
{/*- begin highlight -*/}
<Autocomplete filter={contains}>
<SearchField aria-label="Search tags" placeholder="Search tags" autoFocus style={{margin: 4}} />
<ListBox>
<SelectListBox>
{/*- end highlight -*/}
<SelectItem>News</SelectItem>
<SelectItem>Travel</SelectItem>
Expand All @@ -134,7 +133,7 @@ function Example() {
<SelectItem>Technology</SelectItem>
<SelectItem>Health</SelectItem>
<SelectItem>Science</SelectItem>
</ListBox>
</SelectListBox>
</Autocomplete>
</Popover>
</Select>
Expand All @@ -150,7 +149,7 @@ Use the `SelectValue` render prop function to display the selected items as a [T
"use client";
import {Autocomplete, Select, SelectValue, Group, useFilter} from 'react-aria-components';
import {Button} from 'vanilla-starter/Button';
import {ListBox, DropdownItem} from 'vanilla-starter/ListBox';
import {SelectListBox, SelectItem} from 'vanilla-starter/Select';
import {Label} from 'vanilla-starter/Form';
import {Popover} from 'vanilla-starter/Popover';
import {Plus} from 'lucide-react';
Expand Down Expand Up @@ -247,12 +246,13 @@ function SelectWithTagGroup() {
// Position popover relative to the wrapping div instead of the Button
triggerRef={triggerRef}
hideArrow
className="select-popover"
style={{display: 'flex', flexDirection: 'column', width: 250, padding: 4}}>
<Autocomplete filter={contains}>
<SearchField aria-label="Search states" placeholder="Search states" autoFocus style={{marginBottom: 4}} />
<ListBox items={states}>
{state => <DropdownItem>{state.name}</DropdownItem>}
</ListBox>
<SelectListBox items={states}>
{state => <SelectItem>{state.name}</SelectItem>}
</SelectListBox>
</Autocomplete>
</Popover>
</Select>
Expand Down
4 changes: 4 additions & 0 deletions packages/dev/s2-docs/pages/react-aria/Slider.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ By default, slider values are percentages between 0 and 100. Use the `minValue`,
step: 5
}} />

## Examples

<ExampleList tag="slider" pages={props.pages} />

## API

<Anatomy />
Expand Down
4 changes: 4 additions & 0 deletions packages/dev/s2-docs/pages/react-aria/Table.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,10 @@ function ReorderableTable() {
}
```

## Examples

<ExampleList tag="table" pages={props.pages} />

## API

<Anatomy role="img" aria-label="Anatomy diagram of a table, consisting of multiple rows and columns. The table header includes a select all checkbox, file name and size columns, and a column resizer. Each row in the table body contains a drag button, a selection checkbox, and file name and size cells." />
Expand Down
Loading