Repository navigation
feat: StepList round two - #10794
feat: StepList round two#10794snowystinger wants to merge 4 commits into
Conversation
|
Build successful! 🎉 |
| <InternalStepListContext.Provider value={{selectedId, groupId}}> | ||
| <dom.ol | ||
| {...mergeProps(DOMProps, renderProps)} | ||
| role="list" |
There was a problem hiding this comment.
Are the roles needed here, aren't they implicit?
There was a problem hiding this comment.
Oh, TIL Safari removes semantics when you add list-style: none https://www.havardbrynjulfsen.design/writing/a-new-way-to-remove-list-styles-in-safari
There was a problem hiding this comment.
yeah... that was a really annoying one to track down and fix, I think it's easier than the strange display empty string in that blog, though another interesting approach. Can't ensure it for RAC though since we are generally style-less
|
|
||
| // Need this so I can get an id on the contents so that the announcement makes sense. It lands on this element, not the `li` itself. | ||
| export const StepListItemContent = /*#__PURE__*/ (forwardRef as forwardRefType)( | ||
| function StepListItemContent(props: StepListItemContentProps, ref: ForwardedRef<HTMLDivElement>) { |
There was a problem hiding this comment.
Should this have render props?
There was a problem hiding this comment.
Honestly, I'm still trying to get rid of this component entirely, open to ideas. One idea I had was using Text and its context.
| // A step is completed if it is rendered before the current step. This can only be determined once | ||
| // all of the steps in the group have been rendered, so it is resolved against the DOM. |
There was a problem hiding this comment.
What's the reason for not using a collection instead? This means SSR is not supported, no? That would probably also help with textValue to skip StepListItemContent?
Also just for my planning, is the plan to ship the "readonly" version first, then the wizard later? I'm waiting on #10630 and #10556 before I was going to open a draft for the state, because I don't want to spam you guys. Those are technically not required for async nav, but I don't like to have this many PRs open at once.
There was a problem hiding this comment.
Yeah, still more to sort out, but I plan to add the "wizard" version in this PR as well. Hopefully will find some time to work on that today.
Reason for not using the collection was the hopes that this readonly version that must be sequential and is literally just a simple html list (it's silly it even needs a component) wouldn't need everything that goes along with Collections. The point about SSR is a good thing to consider however. Will need to rethink if there's some other way I can predict the items before vs after the current one.
Right now, the perceived benefits of using the readonly component over just making your own list are:
- we handle adding the completed/current/not completed labels
- group all the text within an item so it announces cohesively and in Safari
But that's really about it.
textValue isn't really for display (or announcements), it's more like a value and is typically used for typeahead/type select.
For the "wizard" btw, we're finding that the use case that will cover is more akin to tabs, random access is permitted.
There was a problem hiding this comment.
textValue isn't really for display (or announcements), it's more like a value and is typically used for typeahead/type select.
Oh, good to know. I knew it wasn't meant for display, but there are a couple precedents for announcement (e.g. useComboBox, useDropIndicator, etc.), so that was new to me.
For the "wizard" btw, we're finding that the use case that will cover is more akin to tabs, random access is permitted.
Hm, that's interesting. So even forwards? What sets it apart from Tabs then? I was imagining something along the lines of a "guided tour", where each step is tied to remote state (e.g. URL), thereby also implying async actions/navigation to progress. Conceptually, what I have in mind for state thinks of Tab as the marker to a TabPanel. This maps well to other uses of async navigation, e.g. ToC, Carousel or Pagination, etc.
There was a problem hiding this comment.
there are a couple precedents for announcement (e.g. useComboBox, useDropIndicator, etc.), so that was new to me.
Hmm may want to revisit those at some date then. In general I'd try not to add more of them though until I sort that out. That's been my own mental model for them.
So even forwards?
Yes, though we'll probably give a prop or make that fall under "controlled" behaviour. The name "wizard" is still pending, we're still hashing it out.
The main use case for this seems to be more about authoring steps for a user to take.
What sets it apart from Tabs then
A great question. We're still on the fence about it. The main difference would be again handling completed/current/uncompleted and making the announcements nice.
And if you wanted a the scenario where you must go in order and the current state is tracked outside, then you'd use the (currently called) readonly steplist. Hopefully with links if I can figure that out.
This whole pattern comes from probably the 90s and the aria example is out of date, so we're still trying to figure out where it fits in the aria world.
Some prior art:
https://reui.io/docs/components/base/stepper
https://reui.io/blocks/application/wizard
https://stylexblocks.com/components/base-ui/steps/
There was a problem hiding this comment.
Chatted about it today, moving readonly to use collections so APIs match more easily and we can handle the SSR case.
| {...DOMProps} | ||
| ref={objRef} | ||
| id={id} | ||
| role="link" // No role === default group which means three arrow keys to get through each item |
There was a problem hiding this comment.
img, perhaps with localized aria-roledescription, to avoid VO+Space announcement?
There was a problem hiding this comment.
yeah, both of them feel like a lie :-/ but i like the idea of img, less implied interaction. I'd still like for people to be able to pass a link in here (Step by step example) and neither link nor img would allow for that
There was a problem hiding this comment.
tested some more with img and actual links, I think it's a better experience with img, lets users know it's not interactive and it's just representing a future step I think. I'll get our a11y team to review it as well, but tentatively moving to it now.
|
Build successful! 🎉 |
|
Build successful! 🎉 |
|
Build successful! 🎉 |
## API Changes
react-aria-components/react-aria-components:GridListItem GridListItem <T> {
allowsArrowNavigation?: boolean
children?: ChildrenOrFunction<GridListItemRenderProps>
className?: ClassNameOrFunction<GridListItemRenderProps> = 'react-aria-GridListItem'
download?: boolean | string
focusMode?: 'child' | 'row'
href?: Href
hrefLang?: string
id?: Key
isDisabled?: boolean
onAction?: () => void
- onBlur?: (FocusEvent<HTMLDivElement>) => void
onClick?: (MouseEvent<FocusableElement>) => void
- onFocus?: (FocusEvent<HTMLDivElement>) => void
- onFocusChange?: (boolean) => void
onHoverChange?: (boolean) => void
onHoverEnd?: (HoverEvent) => void
onHoverStart?: (HoverEvent) => void
onPress?: (PressEvent) => void
onPressEnd?: (PressEvent) => void
onPressStart?: (PressEvent) => void
onPressUp?: (PressEvent) => void
ping?: string
referrerPolicy?: HTMLAttributeReferrerPolicy
rel?: string
render?: DOMRenderFunction<keyof React.JSX.IntrinsicElements, GridListItemRenderProps>
routerOptions?: RouterOptions
style?: StyleOrFunction<GridListItemRenderProps>
target?: HTMLAttributeAnchorTarget
textValue?: string
value?: T
}/react-aria-components:Select Select <M extends SelectionMode = 'single', T> {
allowsEmptyCollection?: boolean
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
autoComplete?: string
autoFocus?: boolean
children?: ChildrenOrFunction<SelectRenderProps>
className?: ClassNameOrFunction<SelectRenderProps> = 'react-aria-Select'
defaultOpen?: boolean
defaultValue?: ValueType<SelectionMode>
disabledKeys?: Iterable<Key>
+ excludeFromTabOrder?: boolean
form?: string
id?: string
isDisabled?: boolean
isInvalid?: boolean
isRequired?: boolean
name?: string
onBlur?: (FocusEvent<Target>) => void
onChange?: (ChangeValueType<SelectionMode>) => void
onFocus?: (FocusEvent<Target>) => void
onFocusChange?: (boolean) => void
onKeyDown?: (KeyboardEvent) => void
onKeyUp?: (KeyboardEvent) => void
onOpenChange?: (boolean) => void
placeholder?: string = 'Select an item' (localized)
render?: DOMRenderFunction<keyof React.JSX.IntrinsicElements, SelectRenderProps>
selectionMode?: SelectionMode = 'single'
shouldCloseOnSelect?: boolean
slot?: string | null
style?: StyleOrFunction<SelectRenderProps>
validate?: (ValidationType<SelectionMode>) => ValidationError | boolean | null | undefined
validationBehavior?: 'native' | 'aria' = 'native'
value?: ValueType<SelectionMode>
}/react-aria-components:GridListItemProps GridListItemProps <T = {}> {
allowsArrowNavigation?: boolean
children?: ChildrenOrFunction<GridListItemRenderProps>
className?: ClassNameOrFunction<GridListItemRenderProps> = 'react-aria-GridListItem'
download?: boolean | string
focusMode?: 'child' | 'row'
href?: Href
hrefLang?: string
id?: Key
isDisabled?: boolean
onAction?: () => void
- onBlur?: (FocusEvent<HTMLDivElement>) => void
onClick?: (MouseEvent<FocusableElement>) => void
- onFocus?: (FocusEvent<HTMLDivElement>) => void
- onFocusChange?: (boolean) => void
onHoverChange?: (boolean) => void
onHoverEnd?: (HoverEvent) => void
onHoverStart?: (HoverEvent) => void
onPress?: (PressEvent) => void
onPressEnd?: (PressEvent) => void
onPressStart?: (PressEvent) => void
onPressUp?: (PressEvent) => void
ping?: string
referrerPolicy?: HTMLAttributeReferrerPolicy
rel?: string
render?: DOMRenderFunction<keyof React.JSX.IntrinsicElements, GridListItemRenderProps>
routerOptions?: RouterOptions
style?: StyleOrFunction<GridListItemRenderProps>
target?: HTMLAttributeAnchorTarget
textValue?: string
value?: T
}/react-aria-components:SelectProps SelectProps <M extends SelectionMode = 'single', T = {
}> {
allowsEmptyCollection?: boolean
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
autoComplete?: string
autoFocus?: boolean
children?: ChildrenOrFunction<SelectRenderProps>
className?: ClassNameOrFunction<SelectRenderProps> = 'react-aria-Select'
defaultOpen?: boolean
defaultValue?: ValueType<SelectionMode>
disabledKeys?: Iterable<Key>
+ excludeFromTabOrder?: boolean
form?: string
id?: string
isDisabled?: boolean
isInvalid?: boolean
isRequired?: boolean
name?: string
onBlur?: (FocusEvent<Target>) => void
onChange?: (ChangeValueType<SelectionMode>) => void
onFocus?: (FocusEvent<Target>) => void
onFocusChange?: (boolean) => void
onKeyDown?: (KeyboardEvent) => void
onKeyUp?: (KeyboardEvent) => void
onOpenChange?: (boolean) => void
placeholder?: string = 'Select an item' (localized)
render?: DOMRenderFunction<keyof React.JSX.IntrinsicElements, SelectRenderProps>
selectionMode?: SelectionMode = 'single'
shouldCloseOnSelect?: boolean
slot?: string | null
style?: StyleOrFunction<SelectRenderProps>
validate?: (ValidationType<SelectionMode>) => ValidationError | boolean | null | undefined
validationBehavior?: 'native' | 'aria' = 'native'
value?: ValueType<SelectionMode>
}@react-aria/select/@react-aria/select:AriaSelectProps AriaSelectProps <M extends SelectionMode = 'single', T> {
allowsEmptyCollection?: boolean
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
autoComplete?: string
autoFocus?: boolean
children: CollectionChildren<T>
defaultOpen?: boolean
defaultValue?: ValueType<SelectionMode>
description?: ReactNode
disabledKeys?: Iterable<Key>
errorMessage?: ReactNode | (ValidationResult) => ReactNode
+ excludeFromTabOrder?: boolean
form?: string
id?: string
isDisabled?: boolean
isInvalid?: boolean
isRequired?: boolean
items?: Iterable<T>
label?: ReactNode
name?: string
onBlur?: (FocusEvent<Target>) => void
onChange?: (ChangeValueType<SelectionMode>) => void
onFocus?: (FocusEvent<Target>) => void
onFocusChange?: (boolean) => void
onKeyDown?: (KeyboardEvent) => void
onKeyUp?: (KeyboardEvent) => void
onOpenChange?: (boolean) => void
placeholder?: string
selectionMode?: SelectionMode = 'single'
shouldCloseOnSelect?: boolean
validate?: (ValidationType<SelectionMode>) => ValidationError | boolean | null | undefined
validationBehavior?: 'aria' | 'native' = 'aria'
value?: ValueType<SelectionMode>
}/@react-aria/select:AriaSelectOptions AriaSelectOptions <M extends SelectionMode = 'single', T> {
allowsEmptyCollection?: boolean
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
autoComplete?: string
autoFocus?: boolean
defaultOpen?: boolean
defaultValue?: ValueType<SelectionMode>
description?: ReactNode
disabledKeys?: Iterable<Key>
errorMessage?: ReactNode | (ValidationResult) => ReactNode
+ excludeFromTabOrder?: boolean
form?: string
id?: string
isDisabled?: boolean
isInvalid?: boolean
isRequired?: boolean
items?: Iterable<T>
keyboardDelegate?: KeyboardDelegate
label?: ReactNode
name?: string
onBlur?: (FocusEvent<Target>) => void
onChange?: (ChangeValueType<SelectionMode>) => void
onFocus?: (FocusEvent<Target>) => void
onFocusChange?: (boolean) => void
onKeyDown?: (KeyboardEvent) => void
onKeyUp?: (KeyboardEvent) => void
onOpenChange?: (boolean) => void
placeholder?: string
selectionMode?: SelectionMode = 'single'
shouldCloseOnSelect?: boolean
validate?: (ValidationType<SelectionMode>) => ValidationError | boolean | null | undefined
validationBehavior?: 'aria' | 'native' = 'aria'
value?: ValueType<SelectionMode>
}@react-spectrum/ai/@react-spectrum/ai:Attachment Attachment {
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
children: ReactNode
density?: 'compact' | 'regular' | 'spacious' = 'regular'
download?: boolean | string
href?: Href
hrefLang?: string
id?: Key
isDisabled?: boolean
isInvalid?: boolean
onAction?: () => void
- onBlur?: (FocusEvent<HTMLDivElement>) => void
- onFocus?: (FocusEvent<HTMLDivElement>) => void
- onFocusChange?: (boolean) => void
onPress?: (PressEvent) => void
onPressChange?: (boolean) => void
onPressEnd?: (PressEvent) => void
onPressStart?: (PressEvent) => void
ping?: string
referrerPolicy?: HTMLAttributeReferrerPolicy
rel?: string
render?: DOMRenderFunction<keyof React.JSX.IntrinsicElements, TagRenderProps>
routerOptions?: RouterOptions
size?: 'XS' | 'S' | 'M' | 'L' | 'XL' = 'M'
styles?: StyleString
target?: HTMLAttributeAnchorTarget
textValue?: string
uploadProgress?: number
value?: T
variant?: 'primary' | 'secondary' | 'tertiary' | 'quiet' = 'primary'
}/@react-spectrum/ai:AttachmentProps AttachmentProps {
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
children: ReactNode
density?: 'compact' | 'regular' | 'spacious' = 'regular'
download?: boolean | string
href?: Href
hrefLang?: string
id?: Key
isDisabled?: boolean
isInvalid?: boolean
onAction?: () => void
- onBlur?: (FocusEvent<HTMLDivElement>) => void
- onFocus?: (FocusEvent<HTMLDivElement>) => void
- onFocusChange?: (boolean) => void
onPress?: (PressEvent) => void
onPressChange?: (boolean) => void
onPressEnd?: (PressEvent) => void
onPressStart?: (PressEvent) => void
ping?: string
referrerPolicy?: HTMLAttributeReferrerPolicy
rel?: string
render?: DOMRenderFunction<keyof React.JSX.IntrinsicElements, TagRenderProps>
routerOptions?: RouterOptions
size?: 'XS' | 'S' | 'M' | 'L' | 'XL' = 'M'
styles?: StyleString
target?: HTMLAttributeAnchorTarget
textValue?: string
uploadProgress?: number
value?: T
variant?: 'primary' | 'secondary' | 'tertiary' | 'quiet' = 'primary'
}@react-spectrum/picker/@react-spectrum/picker:Picker Picker <T extends {}> {
UNSAFE_className?: string
UNSAFE_style?: CSSProperties
align?: Alignment = 'start'
alignSelf?: Responsive<'auto' | 'normal' | 'start' | 'end' | 'center' | 'flex-start' | 'flex-end' | 'self-start' | 'self-end' | 'stretch'>
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
autoComplete?: string
autoFocus?: boolean
bottom?: Responsive<DimensionValue>
children: CollectionChildren<T>
contextualHelp?: ReactNode
defaultOpen?: boolean
defaultSelectedKey?: Key | null
description?: ReactNode
direction?: 'bottom' | 'top' = 'bottom'
disabledKeys?: Iterable<Key>
end?: Responsive<DimensionValue>
errorMessage?: ReactNode | (ValidationResult) => ReactNode
+ excludeFromTabOrder?: boolean
flex?: Responsive<string | number | boolean>
flexBasis?: Responsive<number | string>
flexGrow?: Responsive<number>
flexShrink?: Responsive<number>
gridArea?: Responsive<string>
gridColumn?: Responsive<string>
gridColumnEnd?: Responsive<string>
gridColumnStart?: Responsive<string>
gridRow?: Responsive<string>
gridRowEnd?: Responsive<string>
gridRowStart?: Responsive<string>
height?: Responsive<DimensionValue>
id?: string
isDisabled?: boolean
isHidden?: Responsive<boolean>
isInvalid?: boolean
isLoading?: boolean
isOpen?: boolean
isQuiet?: boolean
isRequired?: boolean
items?: Iterable<T>
justifySelf?: Responsive<'auto' | 'normal' | 'start' | 'end' | 'flex-start' | 'flex-end' | 'self-start' | 'self-end' | 'center' | 'left' | 'right' | 'stretch'>
label?: ReactNode
labelAlign?: Alignment = 'start'
labelPosition?: LabelPosition = 'top'
left?: Responsive<DimensionValue>
margin?: Responsive<DimensionValue>
marginBottom?: Responsive<DimensionValue>
marginEnd?: Responsive<DimensionValue>
marginStart?: Responsive<DimensionValue>
marginTop?: Responsive<DimensionValue>
marginX?: Responsive<DimensionValue>
marginY?: Responsive<DimensionValue>
maxHeight?: Responsive<DimensionValue>
maxWidth?: Responsive<DimensionValue>
menuWidth?: DimensionValue
minHeight?: Responsive<DimensionValue>
minWidth?: Responsive<DimensionValue>
name?: string
necessityIndicator?: NecessityIndicator = 'icon'
onBlur?: (FocusEvent<Target>) => void
onFocus?: (FocusEvent<Target>) => void
onFocusChange?: (boolean) => void
onKeyDown?: (KeyboardEvent) => void
onKeyUp?: (KeyboardEvent) => void
onLoadMore?: () => any
onOpenChange?: (boolean) => void
onSelectionChange?: (Key | null) => void
order?: Responsive<number>
placeholder?: string
position?: Responsive<'static' | 'relative' | 'absolute' | 'fixed' | 'sticky'>
right?: Responsive<DimensionValue>
selectedKey?: Key | null
shouldCloseOnSelect?: boolean
shouldFlip?: boolean = true
start?: Responsive<DimensionValue>
top?: Responsive<DimensionValue>
validate?: (ValidationType<SelectionMode>) => ValidationError | boolean | null | undefined
validationBehavior?: 'aria' | 'native' = 'aria'
width?: Responsive<DimensionValue>
zIndex?: Responsive<number>
}/@react-spectrum/picker:SpectrumPickerProps SpectrumPickerProps <T> {
UNSAFE_className?: string
UNSAFE_style?: CSSProperties
align?: Alignment = 'start'
alignSelf?: Responsive<'auto' | 'normal' | 'start' | 'end' | 'center' | 'flex-start' | 'flex-end' | 'self-start' | 'self-end' | 'stretch'>
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
autoComplete?: string
autoFocus?: boolean
bottom?: Responsive<DimensionValue>
children: CollectionChildren<T>
contextualHelp?: ReactNode
defaultOpen?: boolean
defaultSelectedKey?: Key | null
description?: ReactNode
direction?: 'bottom' | 'top' = 'bottom'
disabledKeys?: Iterable<Key>
end?: Responsive<DimensionValue>
errorMessage?: ReactNode | (ValidationResult) => ReactNode
+ excludeFromTabOrder?: boolean
flex?: Responsive<string | number | boolean>
flexBasis?: Responsive<number | string>
flexGrow?: Responsive<number>
flexShrink?: Responsive<number>
gridArea?: Responsive<string>
gridColumn?: Responsive<string>
gridColumnEnd?: Responsive<string>
gridColumnStart?: Responsive<string>
gridRow?: Responsive<string>
gridRowEnd?: Responsive<string>
gridRowStart?: Responsive<string>
height?: Responsive<DimensionValue>
id?: string
isDisabled?: boolean
isHidden?: Responsive<boolean>
isInvalid?: boolean
isLoading?: boolean
isOpen?: boolean
isQuiet?: boolean
isRequired?: boolean
items?: Iterable<T>
justifySelf?: Responsive<'auto' | 'normal' | 'start' | 'end' | 'flex-start' | 'flex-end' | 'self-start' | 'self-end' | 'center' | 'left' | 'right' | 'stretch'>
label?: ReactNode
labelAlign?: Alignment = 'start'
labelPosition?: LabelPosition = 'top'
left?: Responsive<DimensionValue>
margin?: Responsive<DimensionValue>
marginBottom?: Responsive<DimensionValue>
marginEnd?: Responsive<DimensionValue>
marginStart?: Responsive<DimensionValue>
marginTop?: Responsive<DimensionValue>
marginX?: Responsive<DimensionValue>
marginY?: Responsive<DimensionValue>
maxHeight?: Responsive<DimensionValue>
maxWidth?: Responsive<DimensionValue>
menuWidth?: DimensionValue
minHeight?: Responsive<DimensionValue>
minWidth?: Responsive<DimensionValue>
name?: string
necessityIndicator?: NecessityIndicator = 'icon'
onBlur?: (FocusEvent<Target>) => void
onFocus?: (FocusEvent<Target>) => void
onFocusChange?: (boolean) => void
onKeyDown?: (KeyboardEvent) => void
onKeyUp?: (KeyboardEvent) => void
onLoadMore?: () => any
onOpenChange?: (boolean) => void
onSelectionChange?: (Key | null) => void
order?: Responsive<number>
placeholder?: string
position?: Responsive<'static' | 'relative' | 'absolute' | 'fixed' | 'sticky'>
right?: Responsive<DimensionValue>
selectedKey?: Key | null
shouldCloseOnSelect?: boolean
shouldFlip?: boolean = true
start?: Responsive<DimensionValue>
top?: Responsive<DimensionValue>
validate?: (ValidationType<SelectionMode>) => ValidationError | boolean | null | undefined
validationBehavior?: 'aria' | 'native' = 'aria'
width?: Responsive<DimensionValue>
zIndex?: Responsive<number>
}@react-spectrum/s2/@react-spectrum/s2:Card Card {
UNSAFE_className?: UnsafeClassName
UNSAFE_style?: CSSProperties
allowsArrowNavigation?: boolean
children: ReactNode | (CardRenderProps) => ReactNode
density?: 'compact' | 'regular' | 'spacious' = 'regular'
download?: boolean | string
focusMode?: 'child' | 'row'
href?: Href
hrefLang?: string
id?: Key
isDisabled?: boolean
onAction?: () => void
- onBlur?: (FocusEvent<HTMLDivElement>) => void
- onFocus?: (FocusEvent<HTMLDivElement>) => void
- onFocusChange?: (boolean) => void
onPress?: (PressEvent) => void
onPressChange?: (boolean) => void
onPressEnd?: (PressEvent) => void
onPressStart?: (PressEvent) => void
ping?: string
referrerPolicy?: HTMLAttributeReferrerPolicy
rel?: string
routerOptions?: RouterOptions
size?: 'XS' | 'S' | 'M' | 'L' | 'XL' = 'M'
styles?: StylesProp
target?: HTMLAttributeAnchorTarget
textValue?: string
value?: T
variant?: 'primary' | 'secondary' | 'tertiary' | 'quiet' = 'primary'
}/@react-spectrum/s2:AssetCard AssetCard {
UNSAFE_className?: UnsafeClassName
UNSAFE_style?: CSSProperties
allowsArrowNavigation?: boolean
children: ReactNode | (CardRenderProps) => ReactNode
download?: boolean | string
focusMode?: 'child' | 'row'
href?: Href
hrefLang?: string
id?: Key
isDisabled?: boolean
onAction?: () => void
- onBlur?: (FocusEvent<HTMLDivElement>) => void
- onFocus?: (FocusEvent<HTMLDivElement>) => void
- onFocusChange?: (boolean) => void
onPress?: (PressEvent) => void
onPressChange?: (boolean) => void
onPressEnd?: (PressEvent) => void
onPressStart?: (PressEvent) => void
ping?: string
referrerPolicy?: HTMLAttributeReferrerPolicy
rel?: string
routerOptions?: RouterOptions
size?: 'XS' | 'S' | 'M' | 'L' | 'XL' = 'M'
styles?: StylesProp
target?: HTMLAttributeAnchorTarget
textValue?: string
value?: T
variant?: 'primary' | 'secondary' | 'tertiary' | 'quiet' = 'primary'
}/@react-spectrum/s2:UserCard UserCard {
UNSAFE_className?: UnsafeClassName
UNSAFE_style?: CSSProperties
allowsArrowNavigation?: boolean
children: ReactNode | (CardRenderProps) => ReactNode
download?: boolean | string
focusMode?: 'child' | 'row'
href?: Href
hrefLang?: string
id?: Key
isDisabled?: boolean
onAction?: () => void
- onBlur?: (FocusEvent<HTMLDivElement>) => void
- onFocus?: (FocusEvent<HTMLDivElement>) => void
- onFocusChange?: (boolean) => void
onPress?: (PressEvent) => void
onPressChange?: (boolean) => void
onPressEnd?: (PressEvent) => void
onPressStart?: (PressEvent) => void
ping?: string
referrerPolicy?: HTMLAttributeReferrerPolicy
rel?: string
routerOptions?: RouterOptions
size?: 'XS' | 'S' | 'M' | 'L' | 'XL' = 'M'
styles?: StylesProp
target?: HTMLAttributeAnchorTarget
textValue?: string
value?: T
variant?: 'primary' | 'secondary' | 'tertiary'
}/@react-spectrum/s2:ProductCard ProductCard {
UNSAFE_className?: UnsafeClassName
UNSAFE_style?: CSSProperties
allowsArrowNavigation?: boolean
children: ReactNode | (CardRenderProps) => ReactNode
download?: boolean | string
focusMode?: 'child' | 'row'
href?: Href
hrefLang?: string
id?: Key
isDisabled?: boolean
onAction?: () => void
- onBlur?: (FocusEvent<HTMLDivElement>) => void
- onFocus?: (FocusEvent<HTMLDivElement>) => void
- onFocusChange?: (boolean) => void
onPress?: (PressEvent) => void
onPressChange?: (boolean) => void
onPressEnd?: (PressEvent) => void
onPressStart?: (PressEvent) => void
ping?: string
referrerPolicy?: HTMLAttributeReferrerPolicy
rel?: string
routerOptions?: RouterOptions
size?: 'XS' | 'S' | 'M' | 'L' | 'XL' = 'M'
styles?: StylesProp
target?: HTMLAttributeAnchorTarget
textValue?: string
value?: T
variant?: 'primary' | 'secondary' | 'tertiary'
}/@react-spectrum/s2:ListViewItem ListViewItem {
allowsArrowNavigation?: boolean
children: ReactNode
download?: boolean | string
focusMode?: 'child' | 'row'
hasChildItems?: boolean
href?: Href
hrefLang?: string
id?: Key
isDisabled?: boolean
onAction?: () => void
- onBlur?: (FocusEvent<HTMLDivElement>) => void
- onFocus?: (FocusEvent<HTMLDivElement>) => void
- onFocusChange?: (boolean) => void
onHoverChange?: (boolean) => void
onHoverEnd?: (HoverEvent) => void
onHoverStart?: (HoverEvent) => void
onPress?: (PressEvent) => void
onPressEnd?: (PressEvent) => void
onPressStart?: (PressEvent) => void
onPressUp?: (PressEvent) => void
ping?: string
referrerPolicy?: HTMLAttributeReferrerPolicy
rel?: string
routerOptions?: RouterOptions
target?: HTMLAttributeAnchorTarget
textValue?: string
value?: T
}/@react-spectrum/s2:Picker Picker <M extends SelectionMode = 'single', T> {
UNSAFE_className?: UnsafeClassName
UNSAFE_style?: CSSProperties
align?: 'start' | 'end' = 'start'
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
autoComplete?: string
autoFocus?: boolean
children: ReactNode | (T) => ReactNode
contextualHelp?: ReactNode
defaultOpen?: boolean
defaultValue?: ValueType<SelectionMode>
dependencies?: ReadonlyArray<any>
description?: ReactNode
direction?: 'bottom' | 'top' = 'bottom'
disabledKeys?: Iterable<Key>
errorMessage?: ReactNode | (ValidationResult) => ReactNode
+ excludeFromTabOrder?: boolean
form?: string
id?: string
isDisabled?: boolean
isInvalid?: boolean
isQuiet?: boolean
isRequired?: boolean
items?: Iterable<T>
label?: ReactNode
labelAlign?: Alignment = 'start'
labelPosition?: LabelPosition = 'top'
loadingState?: LoadingState
menuWidth?: number
name?: string
necessityIndicator?: NecessityIndicator = 'icon'
onBlur?: (FocusEvent<Target>) => void
onChange?: (ChangeValueType<SelectionMode>) => void
onFocus?: (FocusEvent<Target>) => void
onFocusChange?: (boolean) => void
onKeyDown?: (KeyboardEvent) => void
onKeyUp?: (KeyboardEvent) => void
onLoadMore?: () => any
onOpenChange?: (boolean) => void
placeholder?: string = 'Select an item' (localized)
renderValue?: (Array<T>) => ReactNode
selectionMode?: SelectionMode = 'single'
shouldCloseOnSelect?: boolean
shouldFlip?: boolean = true
size?: 'S' | 'M' | 'L' | 'XL' = 'M'
slot?: string | null
styles?: StylesProp
validate?: (ValidationType<SelectionMode>) => ValidationError | boolean | null | undefined
validationBehavior?: 'native' | 'aria' = 'native'
value?: ValueType<SelectionMode>
}/@react-spectrum/s2:CardProps CardProps {
UNSAFE_className?: UnsafeClassName
UNSAFE_style?: CSSProperties
allowsArrowNavigation?: boolean
children: ReactNode | (CardRenderProps) => ReactNode
density?: 'compact' | 'regular' | 'spacious' = 'regular'
download?: boolean | string
focusMode?: 'child' | 'row'
href?: Href
hrefLang?: string
id?: Key
isDisabled?: boolean
onAction?: () => void
- onBlur?: (FocusEvent<HTMLDivElement>) => void
- onFocus?: (FocusEvent<HTMLDivElement>) => void
- onFocusChange?: (boolean) => void
onPress?: (PressEvent) => void
onPressChange?: (boolean) => void
onPressEnd?: (PressEvent) => void
onPressStart?: (PressEvent) => void
ping?: string
referrerPolicy?: HTMLAttributeReferrerPolicy
rel?: string
routerOptions?: RouterOptions
size?: 'XS' | 'S' | 'M' | 'L' | 'XL' = 'M'
styles?: StylesProp
target?: HTMLAttributeAnchorTarget
textValue?: string
value?: T
variant?: 'primary' | 'secondary' | 'tertiary' | 'quiet' = 'primary'
}/@react-spectrum/s2:AssetCardProps AssetCardProps {
UNSAFE_className?: UnsafeClassName
UNSAFE_style?: CSSProperties
allowsArrowNavigation?: boolean
children: ReactNode | (CardRenderProps) => ReactNode
download?: boolean | string
focusMode?: 'child' | 'row'
href?: Href
hrefLang?: string
id?: Key
isDisabled?: boolean
onAction?: () => void
- onBlur?: (FocusEvent<HTMLDivElement>) => void
- onFocus?: (FocusEvent<HTMLDivElement>) => void
- onFocusChange?: (boolean) => void
onPress?: (PressEvent) => void
onPressChange?: (boolean) => void
onPressEnd?: (PressEvent) => void
onPressStart?: (PressEvent) => void
ping?: string
referrerPolicy?: HTMLAttributeReferrerPolicy
rel?: string
routerOptions?: RouterOptions
size?: 'XS' | 'S' | 'M' | 'L' | 'XL' = 'M'
styles?: StylesProp
target?: HTMLAttributeAnchorTarget
textValue?: string
value?: T
variant?: 'primary' | 'secondary' | 'tertiary' | 'quiet' = 'primary'
}/@react-spectrum/s2:ProductCardProps ProductCardProps {
UNSAFE_className?: UnsafeClassName
UNSAFE_style?: CSSProperties
allowsArrowNavigation?: boolean
children: ReactNode | (CardRenderProps) => ReactNode
download?: boolean | string
focusMode?: 'child' | 'row'
href?: Href
hrefLang?: string
id?: Key
isDisabled?: boolean
onAction?: () => void
- onBlur?: (FocusEvent<HTMLDivElement>) => void
- onFocus?: (FocusEvent<HTMLDivElement>) => void
- onFocusChange?: (boolean) => void
onPress?: (PressEvent) => void
onPressChange?: (boolean) => void
onPressEnd?: (PressEvent) => void
onPressStart?: (PressEvent) => void
ping?: string
referrerPolicy?: HTMLAttributeReferrerPolicy
rel?: string
routerOptions?: RouterOptions
size?: 'XS' | 'S' | 'M' | 'L' | 'XL' = 'M'
styles?: StylesProp
target?: HTMLAttributeAnchorTarget
textValue?: string
value?: T
variant?: 'primary' | 'secondary' | 'tertiary'
}/@react-spectrum/s2:UserCardProps UserCardProps {
UNSAFE_className?: UnsafeClassName
UNSAFE_style?: CSSProperties
allowsArrowNavigation?: boolean
children: ReactNode | (CardRenderProps) => ReactNode
download?: boolean | string
focusMode?: 'child' | 'row'
href?: Href
hrefLang?: string
id?: Key
isDisabled?: boolean
onAction?: () => void
- onBlur?: (FocusEvent<HTMLDivElement>) => void
- onFocus?: (FocusEvent<HTMLDivElement>) => void
- onFocusChange?: (boolean) => void
onPress?: (PressEvent) => void
onPressChange?: (boolean) => void
onPressEnd?: (PressEvent) => void
onPressStart?: (PressEvent) => void
ping?: string
referrerPolicy?: HTMLAttributeReferrerPolicy
rel?: string
routerOptions?: RouterOptions
size?: 'XS' | 'S' | 'M' | 'L' | 'XL' = 'M'
styles?: StylesProp
target?: HTMLAttributeAnchorTarget
textValue?: string
value?: T
variant?: 'primary' | 'secondary' | 'tertiary'
}/@react-spectrum/s2:ListViewItemProps ListViewItemProps {
allowsArrowNavigation?: boolean
children: ReactNode
download?: boolean | string
focusMode?: 'child' | 'row'
hasChildItems?: boolean
href?: Href
hrefLang?: string
id?: Key
isDisabled?: boolean
onAction?: () => void
- onBlur?: (FocusEvent<HTMLDivElement>) => void
- onFocus?: (FocusEvent<HTMLDivElement>) => void
- onFocusChange?: (boolean) => void
onHoverChange?: (boolean) => void
onHoverEnd?: (HoverEvent) => void
onHoverStart?: (HoverEvent) => void
onPress?: (PressEvent) => void
onPressEnd?: (PressEvent) => void
onPressStart?: (PressEvent) => void
onPressUp?: (PressEvent) => void
ping?: string
referrerPolicy?: HTMLAttributeReferrerPolicy
rel?: string
routerOptions?: RouterOptions
target?: HTMLAttributeAnchorTarget
textValue?: string
value?: T
}/@react-spectrum/s2:PickerProps PickerProps <M extends SelectionMode = 'single', T> {
UNSAFE_className?: UnsafeClassName
UNSAFE_style?: CSSProperties
align?: 'start' | 'end' = 'start'
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
autoComplete?: string
autoFocus?: boolean
children: ReactNode | (T) => ReactNode
contextualHelp?: ReactNode
defaultOpen?: boolean
defaultValue?: ValueType<SelectionMode>
dependencies?: ReadonlyArray<any>
description?: ReactNode
direction?: 'bottom' | 'top' = 'bottom'
disabledKeys?: Iterable<Key>
errorMessage?: ReactNode | (ValidationResult) => ReactNode
+ excludeFromTabOrder?: boolean
form?: string
id?: string
isDisabled?: boolean
isInvalid?: boolean
isQuiet?: boolean
isRequired?: boolean
items?: Iterable<T>
label?: ReactNode
labelAlign?: Alignment = 'start'
labelPosition?: LabelPosition = 'top'
loadingState?: LoadingState
menuWidth?: number
name?: string
necessityIndicator?: NecessityIndicator = 'icon'
onBlur?: (FocusEvent<Target>) => void
onChange?: (ChangeValueType<SelectionMode>) => void
onFocus?: (FocusEvent<Target>) => void
onFocusChange?: (boolean) => void
onKeyDown?: (KeyboardEvent) => void
onKeyUp?: (KeyboardEvent) => void
onLoadMore?: () => any
onOpenChange?: (boolean) => void
placeholder?: string = 'Select an item' (localized)
renderValue?: (Array<T>) => ReactNode
selectionMode?: SelectionMode = 'single'
shouldCloseOnSelect?: boolean
shouldFlip?: boolean = true
size?: 'S' | 'M' | 'L' | 'XL' = 'M'
slot?: string | null
styles?: StylesProp
validate?: (ValidationType<SelectionMode>) => ValidationError | boolean | null | undefined
validationBehavior?: 'native' | 'aria' = 'native'
value?: ValueType<SelectionMode>
} |
Closes
From discussion, split into two components. A "readonly" StepList based on html
oland an interactive Wizard based on tabs.✅ Pull Request Checklist:
📝 Test Instructions:
🧢 Your Project: