From 2d1c2a4402620ad97e156fbd1a420f4c0ee22342 Mon Sep 17 00:00:00 2001 From: Jeff Luyau Date: Thu, 29 Jul 2021 18:12:14 -0700 Subject: [PATCH 01/17] add density, slots, and fix styling for list view --- .../actiongroup/src/ActionGroup.tsx | 3 +- .../@react-spectrum/list/src/ListView.tsx | 9 +++- .../@react-spectrum/list/src/ListViewItem.tsx | 16 +++++- .../@react-spectrum/list/src/listview.css | 50 ++++++++++++++++++- .../list/stories/ListView.stories.tsx | 47 +++++++++++++++++ 5 files changed, 120 insertions(+), 5 deletions(-) diff --git a/packages/@react-spectrum/actiongroup/src/ActionGroup.tsx b/packages/@react-spectrum/actiongroup/src/ActionGroup.tsx index bf9e5641ccb..5e0d9ceb981 100644 --- a/packages/@react-spectrum/actiongroup/src/ActionGroup.tsx +++ b/packages/@react-spectrum/actiongroup/src/ActionGroup.tsx @@ -14,7 +14,7 @@ import {ActionButton} from '@react-spectrum/button'; import {AriaLabelingProps, DOMProps, DOMRef, Node, StyleProps} from '@react-types/shared'; import buttonStyles from '@adobe/spectrum-css-temp/components/button/vars.css'; import ChevronDownMedium from '@spectrum-icons/ui/ChevronDownMedium'; -import {classNames, SlotProvider, useDOMRef, useStyleProps, useValueEffect} from '@react-spectrum/utils'; +import {classNames, SlotProvider, useDOMRef, useSlotProps, useStyleProps, useValueEffect} from '@react-spectrum/utils'; import {filterDOMProps, mergeProps, useId, useLayoutEffect, useResizeObserver} from '@react-aria/utils'; import {Item, Menu, MenuTrigger} from '@react-spectrum/menu'; import {ListState, useListState} from '@react-stately/list'; @@ -32,6 +32,7 @@ import {useProviderProps} from '@react-spectrum/provider'; function ActionGroup(props: SpectrumActionGroupProps, ref: DOMRef) { props = useProviderProps(props); + props = useSlotProps(props, 'actionGroup'); let { isEmphasized, diff --git a/packages/@react-spectrum/list/src/ListView.tsx b/packages/@react-spectrum/list/src/ListView.tsx index 2bff970695f..70d8ebe2116 100644 --- a/packages/@react-spectrum/list/src/ListView.tsx +++ b/packages/@react-spectrum/list/src/ListView.tsx @@ -33,7 +33,7 @@ export function useListLayout(state: ListState) { let collator = useCollator({usage: 'search', sensitivity: 'base'}); let layout = useMemo(() => new ListLayout({ - estimatedRowHeight: scale === 'large' ? 48 : 32, + estimatedRowHeight: scale === 'large' ? 40 : 32, padding: 0, collator }) @@ -45,6 +45,11 @@ export function useListLayout(state: ListState) { } interface ListViewProps extends CollectionBase, DOMProps, AriaLabelingProps, StyleProps { + /** + * Sets the amount of vertical padding within each cell. + * @default 'regular' + */ + density?: 'compact' | 'regular' | 'spacious', isLoading?: boolean, renderEmptyState?: () => JSX.Element, transitionDuration?: number @@ -52,6 +57,7 @@ interface ListViewProps extends CollectionBase, DOMProps, AriaLabelingProp function ListView(props: ListViewProps, ref: DOMRef) { let { + density = 'regular', transitionDuration = 0 } = props; let domRef = useDOMRef(ref); @@ -107,6 +113,7 @@ function ListView(props: ListViewProps, ref: DOMRef - {item.rendered} + + + {item.rendered} + + ); diff --git a/packages/@react-spectrum/list/src/listview.css b/packages/@react-spectrum/list/src/listview.css index f5b4f13f232..7e27840ddbb 100644 --- a/packages/@react-spectrum/list/src/listview.css +++ b/packages/@react-spectrum/list/src/listview.css @@ -1,3 +1,10 @@ + +:root { + --spectrum-listview-item-compact-padding-y: var(--spectrum-global-dimension-size-50); + --spectrum-listview-item-regular-padding-y: var(--spectrum-global-dimension-size-75); + --spectrum-listview-item-spacious-padding-y: var(--spectrum-global-dimension-size-100); +} + .react-spectrum-ListView { border-color: var(--spectrum-table-border-color, var(--spectrum-alias-border-color-mid)); border-style: solid; @@ -21,7 +28,8 @@ font-size: var(--spectrum-table-cell-text-size, var(--spectrum-alias-font-size-default)); font-weight: var(--spectrum-table-cell-text-font-weight, var(--spectrum-global-font-weight-regular)); line-height: calc(var(--spectrum-table-cell-text-size, var(--spectrum-alias-font-size-default)) * var(--spectrum-table-cell-text-line-height, var(--spectrum-alias-body-text-line-height)) - 1px); - padding: var(--spectrum-global-dimension-size-125) var(--spectrum-table-cell-padding-x, var(--spectrum-global-dimension-size-200)); + padding-top: var(--spectrum-listview-item-regular-padding-y); + padding-bottom: var(--spectrum-listview-item-regular-padding-y); transition: background-color var(--spectrum-global-animation-duration-100) ease-in-out; position: relative; background-color: var(--spectrum-table-background-color, var(--spectrum-global-color-gray-50)); @@ -40,6 +48,46 @@ } } +.react-spectrum-ListView--compact .react-spectrum-ListViewItem { + padding-top: var(--spectrum-listview-item-compact-padding-y); + padding-bottom: var(--spectrum-listview-item-compact-padding-y); +} + +.react-spectrum-ListView--spacious .react-spectrum-ListViewItem { + padding-top: var(--spectrum-listview-item-spacious-padding-y); + padding-bottom: var(--spectrum-listview-item-spacious-padding-y); +} + +.react-spectrum-ListViewItem-grid { + display: grid; + grid-template-columns: auto auto 1fr auto; + grid-template-rows: 1fr; + grid-template-areas: "icon image content actionGroup"; + align-items: center; +} + +.react-spectrum-ListViewItem-image { + grid-area: image; + border-radius: var(--spectrum-global-dimension-size-25); + width: var(--spectrum-global-dimension-size-400); + height: var(--spectrum-global-dimension-size-400); +} + +.react-spectrum-ListViewItem-content { + grid-area: content; + padding-left: var(--spectrum-global-dimension-size-100); + padding-right: var(--spectrum-global-dimension-size-100); + flex-grow: 1; +} + +.react-spectrum-ListViewItem-actionGroup { + grid-area: actionGroup; + flex-grow: 0; + flex-shrink: 0; + margin-left: var(--spectrum-global-dimension-size-0); + margin-right: var(--spectrum-global-dimension-size-0); +} + .react-spectrum-ListView-centeredWrapper { display: flex; align-items: center; diff --git a/packages/@react-spectrum/list/stories/ListView.stories.tsx b/packages/@react-spectrum/list/stories/ListView.stories.tsx index 0c41986871b..aff232cd5d5 100644 --- a/packages/@react-spectrum/list/stories/ListView.stories.tsx +++ b/packages/@react-spectrum/list/stories/ListView.stories.tsx @@ -11,6 +11,8 @@ import {Menu, MenuTrigger} from '@react-spectrum/menu'; import MoreSmall from '@spectrum-icons/workflow/MoreSmall'; import React from 'react'; import {storiesOf} from '@storybook/react'; +import {Image} from '@react-spectrum/image'; +import {ActionGroup} from '@react-spectrum/actiongroup'; function renderEmptyState() { @@ -107,4 +109,49 @@ storiesOf('ListView', module) {[]} + )) + .add('density: compact', () => ( + + row 1 + row 2 + row 3 + + )) + .add('density: spacious', () => ( + + row 1 + row 2 + row 3 + + )) + .add('slots', () => ( + + + zapdos + Articuno + + + + + + + + zapdos + Zapdos + + + + + + + + zapdos + Moltres + + + + + + + )); From 4d1aeaf314b9b88fe0072314f0eb0e96e6f8c6af Mon Sep 17 00:00:00 2001 From: Jeff Luyau Date: Mon, 2 Aug 2021 15:12:29 -0700 Subject: [PATCH 02/17] listview poc --- packages/@react-spectrum/list/package.json | 1 + .../@react-spectrum/list/src/ListView.tsx | 16 ++-- .../@react-spectrum/list/src/ListViewItem.tsx | 86 +++++++++++++++++-- .../@react-spectrum/list/src/listview.css | 23 +++-- .../list/stories/ListView.stories.tsx | 70 +++++++++++++-- .../@react-types/shared/src/selection.d.ts | 4 +- 6 files changed, 174 insertions(+), 26 deletions(-) diff --git a/packages/@react-spectrum/list/package.json b/packages/@react-spectrum/list/package.json index 5123954675e..9f7c387ab90 100644 --- a/packages/@react-spectrum/list/package.json +++ b/packages/@react-spectrum/list/package.json @@ -41,6 +41,7 @@ "@react-aria/utils": "^3.8.1", "@react-aria/virtualizer": "^3.3.1", "@react-spectrum/button": "^3.5.0", + "@react-spectrum/checkbox": "^3.2.3", "@react-spectrum/layout": "^3.2.0", "@react-spectrum/listbox": "^3.4.3", "@react-spectrum/progress": "^3.1.1", diff --git a/packages/@react-spectrum/list/src/ListView.tsx b/packages/@react-spectrum/list/src/ListView.tsx index 70d8ebe2116..26cbc823005 100644 --- a/packages/@react-spectrum/list/src/ListView.tsx +++ b/packages/@react-spectrum/list/src/ListView.tsx @@ -9,7 +9,7 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ -import {AriaLabelingProps, CollectionBase, DOMProps, DOMRef, StyleProps} from '@react-types/shared'; +import {AriaLabelingProps, CollectionBase, DOMProps, DOMRef, MultipleSelection, StyleProps} from '@react-types/shared'; import {classNames, useDOMRef, useStyleProps} from '@react-spectrum/utils'; import {GridCollection, useGridState} from '@react-stately/grid'; import {GridKeyboardDelegate, useGrid} from '@react-aria/grid'; @@ -20,7 +20,7 @@ import {ListState, useListState} from '@react-stately/list'; import listStyles from './listview.css'; import {ListViewItem} from './ListViewItem'; import {ProgressCircle} from '@react-spectrum/progress'; -import React, {ReactElement, useContext, useMemo} from 'react'; +import React, {Key, ReactElement, useContext, useMemo, useState} from 'react'; import {useCollator, useLocale, useMessageFormatter} from '@react-aria/i18n'; import {useProvider} from '@react-spectrum/provider'; import {Virtualizer} from '@react-aria/virtualizer'; @@ -44,7 +44,7 @@ export function useListLayout(state: ListState) { return layout; } -interface ListViewProps extends CollectionBase, DOMProps, AriaLabelingProps, StyleProps { +interface ListViewProps extends CollectionBase, DOMProps, AriaLabelingProps, StyleProps, MultipleSelection { /** * Sets the amount of vertical padding within each cell. * @default 'regular' @@ -52,17 +52,21 @@ interface ListViewProps extends CollectionBase, DOMProps, AriaLabelingProp density?: 'compact' | 'regular' | 'spacious', isLoading?: boolean, renderEmptyState?: () => JSX.Element, - transitionDuration?: number + transitionDuration?: number, + onAction?: (key: Key) => void } function ListView(props: ListViewProps, ref: DOMRef) { let { density = 'regular', - transitionDuration = 0 + transitionDuration = 0, + selectionStyle = 'checkbox', + onAction } = props; let domRef = useDOMRef(ref); let {collection} = useListState(props); let formatMessage = useMessageFormatter(intlMessages); + let [selectionMode, setSelectionMode] = useState(false); let {styleProps} = useStyleProps(props); let {direction} = useLocale(); @@ -101,7 +105,7 @@ function ListView(props: ListViewProps, ref: DOMRef + (); + let isMobile = useIsMobileDevice(); let { isFocusVisible: isFocusVisibleWithin, focusProps: focusWithinProps @@ -45,11 +53,46 @@ export function ListViewItem(props) { gridCellProps, hoverProps, focusWithinProps, - focusProps + focusProps, + {...((state.selectionManager.selectionMode === 'none' && item.props.hasChildItems) && {onPointerUp: () => onAction(item.key)})}, + {...((isMobile) && { + onPointerUp: () => { + console.log('action', item.key); + onAction(item.key); + }, + onTouchStart: () => { + selectionTimeout = setTimeout(() => { + setSelectionMode(true); + }, SELECTION_INTERVAL); + }, + onTouchEnd: () => { + if (selectionTimeout) { + clearTimeout(selectionTimeout); + } + } + })} ); + let {checkboxProps} = useListSelectionCheckbox(props, state); + + let chevron = null; + if (item.props.hasChildItems) { + chevron = direction === 'ltr' + ? ( +