-
Notifications
You must be signed in to change notification settings - Fork 1.4k
docs: Add docs for horizontal orientation #9843
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 4 commits
f61d08e
01b5d84
4a1bba0
177c7fe
cbfdd67
f1250cb
164706a
c020c54
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,7 +12,7 @@ export const description = 'Renders a scrollable collection of data using custom | |
|
|
||
| <PageDescription>{docs.exports.Virtualizer.description}</PageDescription> | ||
|
|
||
| ```tsx render docs={docs.exports.ListLayoutOptions} links={docs.links} props={['rowHeight', 'gap', 'padding']} initialProps={{rowHeight: 32, gap: 4, padding: 4}} propsObject="layoutOptions" wide | ||
| ```tsx render docs={docs.exports.ListLayoutOptions} links={docs.links} props={['rowSize', 'gap', 'padding']} initialProps={{rowSize: 32, gap: 4, padding: 4}} propsObject="layoutOptions" wide | ||
| "use client"; | ||
| import {Virtualizer, ListLayout} from 'react-aria-components'; | ||
| import {ListBox, ListBoxItem} from 'vanilla-starter/ListBox'; | ||
|
|
@@ -49,9 +49,9 @@ Virtualizer uses <TypeLink links={docs.links} type={docs.exports.Layout} /> obje | |
|
|
||
| ### List | ||
|
|
||
| `ListLayout` supports layout of items in a vertical stack. Rows can be fixed or variable height. When using variable heights, set the `estimatedRowHeight` to a reasonable guess for how tall the rows will be on average. This allows the size of the scrollbar to be calculated. | ||
| `ListLayout` places items along its orientation. Rows can be fixed or variable size. When using variable size, set the `estimatedRowSize` to a reasonable guess for how tall or wide the rows will be on average. This allows the size of the scrollbar to be calculated. | ||
|
|
||
| ```tsx render docs={docs.exports.ListLayoutOptions} links={docs.links} props={['gap', 'padding']} initialProps={{estimatedRowHeight: 75, gap: 4, padding: 4}} propsObject="layoutOptions" wide | ||
| ```tsx render docs={docs.exports.ListLayoutOptions} links={docs.links} props={['gap', 'padding']} initialProps={{estimatedRowSize: 75, gap: 4, padding: 4}} propsObject="layoutOptions" wide | ||
| "use client"; | ||
| import {Virtualizer, ListLayout} from 'react-aria-components'; | ||
| import {ListBox, ListBoxItem} from 'vanilla-starter/ListBox'; | ||
|
|
@@ -80,6 +80,41 @@ for (let i = 0; i < 5000; i++) { | |
| </Virtualizer> | ||
| ``` | ||
|
|
||
|
|
||
| Use the `orientation` option to arrange items horizontally or vertically. Provide the same `orientation` on the collection component so keyboard navigation matches the layout. | ||
|
|
||
| ```tsx render docs={docs.exports.ListLayoutOptions} links={docs.links} props={['gap', 'padding']} initialProps={{estimatedRowSize: 100, gap: 4, padding: 4, orientation: 'horizontal'}} propsObject="layoutOptions" wide | ||
| "use client"; | ||
| import {Virtualizer, ListLayout} from 'react-aria-components'; | ||
| import {ListBox, ListBoxItem} from 'vanilla-starter/ListBox'; | ||
|
|
||
| let lorem = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin sit amet tristique risus. In sit amet suscipit lorem. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In condimentum imperdiet metus non condimentum. Duis eu velit et quam accumsan tempus at id velit. Duis elementum elementum purus, id tempus mauris posuere a. Nunc vestibulum sapien pellentesque lectus commodo ornare.'.split(' '); | ||
| let items: {id: number, name: string}[] = []; | ||
| for (let i = 0; i < 5000; i++) { | ||
| let words = Math.max(2, Math.floor(Math.random() * 10)); | ||
| let name = lorem.slice(0, words).join(' '); | ||
| items.push({id: i, name}); | ||
| } | ||
|
|
||
| <Virtualizer | ||
| /*- begin highlight -*/ | ||
| layout={ListLayout} | ||
| /* PROPS */ | ||
| > | ||
| {/*- end highlight -*/} | ||
| <ListBox | ||
| /*- begin highlight -*/ | ||
| orientation="horizontal" | ||
| /*- end highlight -*/ | ||
| aria-label="Horizontal virtualized list" | ||
| selectionMode="multiple" | ||
| items={items} | ||
| style={{display: 'block', padding: 0, height: 100}}> | ||
| {(item) => <ListBoxItem style={{height: '100%'}}>{item.name}</ListBoxItem>} | ||
|
||
| </ListBox> | ||
| </Virtualizer> | ||
| ``` | ||
|
|
||
| ### Grid | ||
|
|
||
| `GridLayout` supports layout of items in an equal size grid. The items are sized between a minimum and maximum size depending on the width of the container. Make sure to set `layout="grid"` on the `ListBox` or `GridList` component as well so that keyboard navigation behavior is correct. | ||
|
|
@@ -426,7 +461,7 @@ for (let i = 0; images.length < 500; i++) { | |
|
|
||
| `TableLayout` provides layout of items in rows and columns, supporting virtualization of both horizontal and vertical scrolling. It should be used with the [Table](Table) component. Rows can be fixed or variable height. When using variable heights, set the `estimatedRowHeight` to a reasonable guess for how tall the rows will be on average. This allows the size of the scrollbar to be calculated. | ||
|
|
||
| ```tsx render docs={docs.exports.ListLayoutOptions} links={docs.links} props={['rowHeight', 'headingHeight', 'padding', 'gap']} initialProps={{rowHeight: 32, headingHeight: 32, padding: 4, gap: 4}} propsObject="layoutOptions" wide | ||
| ```tsx render docs={docs.exports.TableLayoutProps} links={docs.links} props={['rowHeight', 'headingHeight', 'padding', 'gap']} initialProps={{rowHeight: 32, headingHeight: 32, padding: 4, gap: 4}} propsObject="layoutOptions" wide | ||
| "use client"; | ||
| import {Virtualizer, TableLayout} from 'react-aria-components'; | ||
| import {Cell, Column, Row, Table, TableBody, TableHeader} from 'vanilla-starter/Table'; | ||
|
|
@@ -501,4 +536,4 @@ for (let i = 0; i < 1000; i++) { | |
|
|
||
| ### TableLayout | ||
|
|
||
| <GroupedPropTable {...docs.exports.ListLayoutOptions} links={docs.links} /> | ||
| <GroupedPropTable {...docs.exports.TableLayoutProps} links={docs.links} /> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,25 +25,25 @@ export interface ListLayoutOptions { | |
| */ | ||
| orientation?: Orientation, | ||
| /** | ||
| * The fixed height of a row in px. | ||
| * The fixed size of a row in px with respect to the applied orientation. | ||
| * @default 48 | ||
| */ | ||
| rowHeight?: number, | ||
| /** The estimated height of a row, when row heights are variable. */ | ||
| estimatedRowHeight?: number, | ||
| rowSize?: number, | ||
| /** The estimated size of a row in px with respect to the applied orientation, when row sizes are variable. */ | ||
| estimatedRowSize?: number, | ||
| /** | ||
| * The fixed height of a section header in px. | ||
| * The fixed size of a section header in px with respect to the applied orientation. | ||
| * @default 48 | ||
| */ | ||
| headingHeight?: number, | ||
| /** The estimated height of a section header, when the height is variable. */ | ||
| estimatedHeadingHeight?: number, | ||
| headingSize?: number, | ||
| /** The estimated size of a section header in px with respect to the applied orientation, when heading sizes are variable. */ | ||
| estimatedHeadingSize?: number, | ||
| /** | ||
| * The fixed height of a loader element in px. This loader is specifically for | ||
| * The fixed size of a loader element in px with respect to the applied orientation. This loader is specifically for | ||
| * "load more" elements rendered when loading more rows at the root level or inside nested row/sections. | ||
| * @default 48 | ||
| */ | ||
| loaderHeight?: number, | ||
| loaderSize?: number, | ||
| /** | ||
| * The thickness of the drop indicator. | ||
| * @default 2 | ||
|
|
@@ -58,7 +58,34 @@ export interface ListLayoutOptions { | |
| * The padding around the list. | ||
| * @default 0 | ||
| */ | ||
| padding?: number | ||
| padding?: number, | ||
| /** | ||
| * The fixed height of a row in px. | ||
| * @default 48 | ||
| * @deprecated Use `rowSize` instead. | ||
| */ | ||
| rowHeight?: number, | ||
| /** The estimated height of a row, when row heights are variable. | ||
| * @deprecated Use `estimatedRowSize` instead. | ||
| */ | ||
| estimatedRowHeight?: number, | ||
| /** | ||
| * The fixed height of a section header in px. | ||
| * @default 48 | ||
| * @deprecated Use `headingSize` instead. | ||
| */ | ||
| headingHeight?: number, | ||
| /** The estimated height of a section header, when the height is variable. | ||
| * @deprecated Use `estimatedHeadingSize` instead. | ||
| */ | ||
| estimatedHeadingHeight?: number, | ||
| /** | ||
| * The fixed height of a loader element in px. This loader is specifically for | ||
| * "load more" elements rendered when loading more rows at the root level or inside nested row/sections. | ||
| * @default 48 | ||
| * @deprecated Use `loaderSize` instead. | ||
| */ | ||
| loaderHeight?: number | ||
| } | ||
|
|
||
| // A wrapper around LayoutInfo that supports hierarchy | ||
|
|
@@ -74,8 +101,8 @@ const DEFAULT_HEIGHT = 48; | |
|
|
||
| /** | ||
| * ListLayout is a virtualizer Layout implementation | ||
| * that arranges its items in a vertical stack. It supports both fixed | ||
| * and variable height items. | ||
| * that arranges its items in a stack along its applied orientation. | ||
| * It supports both fixed and variable size items. | ||
| */ | ||
| export class ListLayout<T, O extends ListLayoutOptions = ListLayoutOptions> extends Layout<Node<T>, O> implements DropTargetDelegate { | ||
| protected rowHeight: number | null; | ||
|
|
@@ -103,12 +130,12 @@ export class ListLayout<T, O extends ListLayoutOptions = ListLayoutOptions> exte | |
| */ | ||
| constructor(options: ListLayoutOptions = {}) { | ||
| super(); | ||
| this.rowHeight = options.rowHeight ?? null; | ||
| this.rowHeight = options?.rowSize ?? options?.rowHeight ?? null; | ||
|
||
| this.orientation = options.orientation ?? 'vertical'; | ||
| this.estimatedRowHeight = options.estimatedRowHeight ?? null; | ||
| this.headingHeight = options.headingHeight ?? null; | ||
| this.estimatedHeadingHeight = options.estimatedHeadingHeight ?? null; | ||
| this.loaderHeight = options.loaderHeight ?? null; | ||
| this.estimatedRowHeight = options?.estimatedRowSize ?? options?.estimatedRowHeight ?? null; | ||
|
||
| this.headingHeight = options?.headingSize ?? options?.headingHeight ?? null; | ||
| this.estimatedHeadingHeight = options?.estimatedHeadingSize ?? options?.estimatedHeadingHeight ?? null; | ||
| this.loaderHeight = options?.loaderSize ?? options?.loaderHeight ?? null; | ||
| this.dropIndicatorThickness = options.dropIndicatorThickness || 2; | ||
| this.gap = options.gap || 0; | ||
| this.padding = options.padding || 0; | ||
|
|
@@ -208,21 +235,21 @@ export class ListLayout<T, O extends ListLayoutOptions = ListLayoutOptions> exte | |
| // Also invalidate if fixed sizes/gaps change. | ||
| let options = invalidationContext.layoutOptions; | ||
| return invalidationContext.sizeChanged | ||
| || this.rowHeight !== (options?.rowHeight ?? this.rowHeight) | ||
| || this.rowHeight !== (options?.rowSize ?? options?.rowHeight ?? this.rowHeight) | ||
| || this.orientation !== (options?.orientation ?? this.orientation) | ||
| || this.headingHeight !== (options?.headingHeight ?? this.headingHeight) | ||
| || this.loaderHeight !== (options?.loaderHeight ?? this.loaderHeight) | ||
| || this.headingHeight !== (options?.headingSize ?? options?.headingHeight ?? this.headingHeight) | ||
| || this.loaderHeight !== (options?.loaderSize ?? options?.loaderHeight ?? this.loaderHeight) | ||
| || this.gap !== (options?.gap ?? this.gap) | ||
| || this.padding !== (options?.padding ?? this.padding); | ||
| } | ||
|
|
||
| shouldInvalidateLayoutOptions(newOptions: O, oldOptions: O): boolean { | ||
| return newOptions.rowHeight !== oldOptions.rowHeight | ||
| return (newOptions?.rowSize ?? newOptions?.rowHeight) !== (oldOptions?.rowSize ?? oldOptions?.rowHeight) | ||
| || newOptions.orientation !== oldOptions.orientation | ||
| || newOptions.estimatedRowHeight !== oldOptions.estimatedRowHeight | ||
| || newOptions.headingHeight !== oldOptions.headingHeight | ||
| || newOptions.estimatedHeadingHeight !== oldOptions.estimatedHeadingHeight | ||
| || newOptions.loaderHeight !== oldOptions.loaderHeight | ||
| || (newOptions?.estimatedRowSize ?? newOptions?.estimatedRowHeight) !== (oldOptions?.estimatedRowSize ?? oldOptions?.estimatedRowHeight) | ||
| || (newOptions?.headingSize ?? newOptions?.headingHeight) !== (oldOptions?.headingSize ?? oldOptions?.headingHeight) | ||
| || (newOptions?.estimatedHeadingSize ?? newOptions?.estimatedHeadingHeight) !== (oldOptions?.estimatedHeadingSize ?? oldOptions?.estimatedHeadingHeight) | ||
| || (newOptions?.loaderSize ?? newOptions?.loaderHeight) !== (oldOptions?.loaderSize ?? oldOptions?.loaderHeight) | ||
| || newOptions.dropIndicatorThickness !== oldOptions.dropIndicatorThickness | ||
| || newOptions.gap !== oldOptions.gap | ||
| || newOptions.padding !== oldOptions.padding; | ||
|
|
@@ -240,12 +267,12 @@ export class ListLayout<T, O extends ListLayoutOptions = ListLayoutOptions> exte | |
| } | ||
|
|
||
| let options = invalidationContext.layoutOptions; | ||
| this.rowHeight = options?.rowHeight ?? this.rowHeight; | ||
| this.rowHeight = options?.rowSize ?? options?.rowHeight ?? this.rowHeight; | ||
| this.orientation = options?.orientation ?? this.orientation; | ||
| this.estimatedRowHeight = options?.estimatedRowHeight ?? this.estimatedRowHeight; | ||
| this.headingHeight = options?.headingHeight ?? this.headingHeight; | ||
| this.estimatedHeadingHeight = options?.estimatedHeadingHeight ?? this.estimatedHeadingHeight; | ||
| this.loaderHeight = options?.loaderHeight ?? this.loaderHeight; | ||
| this.estimatedRowHeight = options?.estimatedRowSize ?? options?.estimatedRowHeight ?? this.estimatedRowHeight; | ||
| this.headingHeight = options?.headingSize ?? options?.headingHeight ?? this.headingHeight; | ||
| this.estimatedHeadingHeight = options?.estimatedHeadingSize ?? options?.estimatedHeadingHeight ?? this.estimatedHeadingHeight; | ||
| this.loaderHeight = options?.loaderSize ?? options?.loaderHeight ?? this.loaderHeight; | ||
| this.dropIndicatorThickness = options?.dropIndicatorThickness ?? this.dropIndicatorThickness; | ||
| this.gap = options?.gap ?? this.gap; | ||
| this.padding = options?.padding ?? this.padding; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -58,6 +58,26 @@ | |
| display: grid; | ||
| grid-template-columns: auto; | ||
| align-items: center; | ||
|
|
||
| &[data-orientation=horizontal] { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need this in the tailwind starter as well |
||
| display: flex; | ||
| flex-direction: row; | ||
| justify-content: normal; | ||
|
|
||
| .react-aria-GridListItem { | ||
| flex-shrink: 0; | ||
| width: var(--grid-item-size); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| &[data-layout=grid][data-orientation=horizontal] { | ||
| grid-auto-flow: column; | ||
| grid-template-rows: auto auto; | ||
| grid-template-columns: none; | ||
| grid-auto-columns: var(--grid-item-size); | ||
| justify-content: normal; | ||
| max-height: none; | ||
| } | ||
|
|
||
| &[data-focus-visible] { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.