feat: Add TokenField to react-aria-components#10318
Conversation
| import {Key} from '@react-types/shared'; | ||
| import {TokenSegmentList} from 'react-aria-components/TokenField'; | ||
|
|
||
| export class ComboBoxSegmentList extends TokenSegmentList<Key> { |
There was a problem hiding this comment.
Do we want to maintain some of these subclasses shown in the docs as official implementations for any of these patterns? Or just rely on copy/paste for now?
|
Build successful! 🎉 |
|
Build successful! 🎉 |
## API Changes
react-aria-components/react-aria-components:TokenField+TokenField <T extends TokenSegmentList = TokenSegmentList> {
+ allowsNewlines?: boolean
+ aria-describedby?: string
+ aria-details?: string
+ aria-label?: string
+ aria-labelledby?: string
+ autoFocus?: boolean
+ children?: ChildrenOrFunction<TokenFieldRenderProps>
+ className?: ClassNameOrFunction<TokenFieldRenderProps> = 'react-aria-TokenField'
+ defaultValue?: TokenSegmentList
+ isDisabled?: boolean
+ isReadOnly?: boolean
+ onBlur?: (FocusEvent<Target>) => void
+ onChange?: (TokenSegmentList) => void
+ onCopy?: ClipboardEventHandler<TokenSegmentList>
+ onCut?: ClipboardEventHandler<TokenSegmentList>
+ onFocus?: (FocusEvent<Target>) => void
+ onFocusChange?: (boolean) => void
+ onKeyDown?: (KeyboardEvent) => void
+ onKeyUp?: (KeyboardEvent) => void
+ onPaste?: ClipboardEventHandler<TokenSegmentList>
+ onSubmit?: () => void
+ render?: DOMRenderFunction<keyof React.JSX.IntrinsicElements, TokenFieldRenderProps>
+ role?: 'textbox' | 'searchbox' | 'combobox' = 'textbox'
+ slot?: string | null
+ style?: StyleOrFunction<TokenFieldRenderProps>
+ value?: TokenSegmentList
+}/react-aria-components:TokenInput+TokenInput <T extends TokenSegmentList = TokenSegmentList> {
+ children: (TokenSegment<TokenSegmentList extends TokenSegmentList<any> ? V : never>) => React.ReactElement
+ className?: ClassNameOrFunction<TokenInputRenderProps> = 'react-aria-TokenInput'
+ isDisabled?: boolean
+ onHoverChange?: (boolean) => void
+ onHoverEnd?: (HoverEvent) => void
+ onHoverStart?: (HoverEvent) => void
+ render?: DOMRenderFunction<keyof React.JSX.IntrinsicElements, TokenInputRenderProps>
+ slot?: string | null
+ style?: StyleOrFunction<TokenInputRenderProps>
+}/react-aria-components:Token+Token {
+ children?: ChildrenOrFunction<TokenRenderProps>
+ className?: ClassNameOrFunction<TokenRenderProps> = 'react-aria-Token'
+ render?: DOMRenderFunction<keyof React.JSX.IntrinsicElements, TokenRenderProps>
+ style?: StyleOrFunction<TokenRenderProps>
+}/react-aria-components:TokenFieldContext+TokenFieldContext {
+ UNTYPED
+}/react-aria-components:TokenSegmentList+TokenSegmentList <T = any> {
+ caretPosition: Position
+ constructor: (readonly Array<TokenFieldSegment<T>>, TokenSegmentListOptions) => void
+ delete: (Position, Intl.Segmenter, any, any) => this
+ deleteLine: (Position, any, any) => this
+ endCoalescing: () => void
+ findBoundaryWithSegmenter: (Position, Intl.Segmenter, any) => Position | null
+ findLineBoundary: (Position, any) => Position | null
+ findText: (Position, any, string | RegExp) => Position | null
+ redo: () => this
+ replaceRange: (Position, Position, string, any) => this
+ replaceRangeWithSegments: (Position, Position, Array<TokenFieldSegment<T>>, any) => this
+ segments: readonly Array<TokenFieldSegment<T>>
+ slice: (Position, Position) => this
+ toString: () => string
+ undo: () => this
+ withCaretPosition: (Position) => this
+}/react-aria-components:TokenFieldProps+TokenFieldProps <T extends TokenSegmentList = TokenSegmentList> {
+ allowsNewlines?: boolean
+ aria-describedby?: string
+ aria-details?: string
+ aria-label?: string
+ aria-labelledby?: string
+ autoFocus?: boolean
+ children?: ChildrenOrFunction<TokenFieldRenderProps>
+ className?: ClassNameOrFunction<TokenFieldRenderProps> = 'react-aria-TokenField'
+ defaultValue?: TokenSegmentList
+ isDisabled?: boolean
+ isReadOnly?: boolean
+ onBlur?: (FocusEvent<Target>) => void
+ onChange?: (TokenSegmentList) => void
+ onCopy?: ClipboardEventHandler<TokenSegmentList>
+ onCut?: ClipboardEventHandler<TokenSegmentList>
+ onFocus?: (FocusEvent<Target>) => void
+ onFocusChange?: (boolean) => void
+ onKeyDown?: (KeyboardEvent) => void
+ onKeyUp?: (KeyboardEvent) => void
+ onPaste?: ClipboardEventHandler<TokenSegmentList>
+ onSubmit?: () => void
+ render?: DOMRenderFunction<keyof React.JSX.IntrinsicElements, TokenFieldRenderProps>
+ role?: 'textbox' | 'searchbox' | 'combobox' = 'textbox'
+ slot?: string | null
+ style?: StyleOrFunction<TokenFieldRenderProps>
+ value?: TokenSegmentList
+}/react-aria-components:TokenFieldRenderProps+TokenFieldRenderProps {
+ isDisabled: boolean
+ isReadOnly: boolean
+}/react-aria-components:TokenInputProps+TokenInputProps <T extends TokenSegmentList = TokenSegmentList> {
+ children: (TokenSegment<TokenSegmentList extends TokenSegmentList<any> ? V : never>) => React.ReactElement
+ className?: ClassNameOrFunction<TokenInputRenderProps> = 'react-aria-TokenInput'
+ isDisabled?: boolean
+ onHoverChange?: (boolean) => void
+ onHoverEnd?: (HoverEvent) => void
+ onHoverStart?: (HoverEvent) => void
+ render?: DOMRenderFunction<keyof React.JSX.IntrinsicElements, TokenInputRenderProps>
+ slot?: string | null
+ style?: StyleOrFunction<TokenInputRenderProps>
+}/react-aria-components:TokenInputRenderProps+TokenInputRenderProps {
+ isDisabled: boolean
+ isFocusVisible: boolean
+ isFocused: boolean
+ isHovered: boolean
+ isReadOnly: boolean
+}/react-aria-components:TokenProps+TokenProps {
+ children?: ChildrenOrFunction<TokenRenderProps>
+ className?: ClassNameOrFunction<TokenRenderProps> = 'react-aria-Token'
+ render?: DOMRenderFunction<keyof React.JSX.IntrinsicElements, TokenRenderProps>
+ style?: StyleOrFunction<TokenRenderProps>
+}/react-aria-components:TokenRenderProps+TokenRenderProps {
+ isDisabled: boolean
+ isSelected: boolean
+}@react-aria/combobox/@react-aria/combobox:AriaComboBoxOptions AriaComboBoxOptions <M extends SelectionMode = 'single', T> {
allowsCustomValue?: boolean
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
autoFocus?: boolean
buttonRef?: RefObject<Element | null>
defaultInputValue?: string
defaultItems?: Iterable<T>
defaultValue?: ValueType<SelectionMode>
description?: ReactNode
disabledKeys?: Iterable<Key>
errorMessage?: ReactNode | (ValidationResult) => ReactNode
form?: string
id?: string
inputRef: RefObject<HTMLInputElement | null>
inputValue?: string
isDisabled?: boolean
isInvalid?: boolean
isReadOnly?: boolean
isRequired?: boolean
items?: Iterable<T>
keyboardDelegate?: KeyboardDelegate
label?: ReactNode
+ labelElementType?: ElementType = 'label'
layoutDelegate?: LayoutDelegate
listBoxRef: RefObject<HTMLElement | null>
menuTrigger?: MenuTriggerAction = 'input'
name?: string
onChange?: (ChangeValueType<SelectionMode>) => void
onFocus?: (FocusEvent<HTMLInputElement>) => void
onFocusChange?: (boolean) => void
onInputChange?: (string) => void
onKeyDown?: (KeyboardEvent) => void
onKeyUp?: (KeyboardEvent) => void
onOpenChange?: (boolean, MenuTriggerAction) => void
placeholder?: string
popoverRef: RefObject<Element | null>
selectionMode?: SelectionMode = 'single'
shouldFocusWrap?: boolean
validate?: (ComboBoxValidationValue<SelectionMode>) => ValidationError | boolean | null | undefined
validationBehavior?: 'aria' | 'native' = 'aria'
value?: ValueType<SelectionMode>
}@react-spectrum/ai/@react-spectrum/ai:PromptToken PromptToken {
children: React.ReactNode
- className?: ClassNameOrFunction<TokenRenderProps>
+ className?: ClassNameOrFunction<TokenRenderProps> = 'react-aria-Token'
style?: StyleOrFunction<TokenRenderProps>
}/@react-spectrum/ai:PromptTokenProps PromptTokenProps {
children: React.ReactNode
- className?: ClassNameOrFunction<TokenRenderProps>
+ className?: ClassNameOrFunction<TokenRenderProps> = 'react-aria-Token'
style?: StyleOrFunction<TokenRenderProps>
} |
snowystinger
left a comment
There was a problem hiding this comment.
will continue reviewing tomorrow
| ('htmlFor' in labelProps && labelProps.htmlFor) || props.isDisabled | ||
| ? undefined | ||
| : () => { | ||
| inputRef.current?.focus(); |
There was a problem hiding this comment.
| inputRef.current?.focus(); | |
| inputRef.current?.focus({focusVisible: true}); |
Looks like this is pretty close to widely available. Should the interaction modality and visible really be true though? should we grab the current modality?
There was a problem hiding this comment.
@snowystinger On that topic, what's the target range you guys require? Is it strictly widely available, or is newly-available fine for new features?
There was a problem hiding this comment.
why now? we don't do this anywhere else.
There was a problem hiding this comment.
why now?
it was on my mind from another Issue I was responding to. I'm ok leaving it alone
There was a problem hiding this comment.
Is it strictly widely available
We transpile to widely available, if that's what you're asking? Otherwise, we look at fallbacks, polyfills, or just matching an API (Temporal).
There was a problem hiding this comment.
Yeah, it was more so directed at wheter a missing polyfill for a newly-available API (e.g. Navigation API) would be a blocker for new features requiring them. Thats of course if no other alternative for backwards compatibility can be found.
This adds a new TokenField component to react-aria-components. A token field allows users to enter text with inline tokens. Use it to build AI prompt fields, tag inputs, structured search fields, mention inputs, and multi-select comboboxes.
Changes: