diff --git a/packages/@react-spectrum/ai/exports/AttachmentList.ts b/packages/@react-spectrum/ai/exports/AttachmentList.ts deleted file mode 100644 index 6daac523b4d..00000000000 --- a/packages/@react-spectrum/ai/exports/AttachmentList.ts +++ /dev/null @@ -1 +0,0 @@ -export {Attachment, AttachmentList} from '../src/AttachmentList'; diff --git a/packages/@react-spectrum/ai/exports/HorizontalCard.ts b/packages/@react-spectrum/ai/exports/HorizontalCard.ts deleted file mode 100644 index 07442cb6638..00000000000 --- a/packages/@react-spectrum/ai/exports/HorizontalCard.ts +++ /dev/null @@ -1,2 +0,0 @@ -export {BasicHorizontalCard, HorizontalCard, CardPreview} from '../src/HorizontalCard'; -export type {CardProps, BasicCardProps} from '../src/HorizontalCard'; diff --git a/packages/@react-spectrum/ai/exports/MessageFeedback.ts b/packages/@react-spectrum/ai/exports/MessageFeedback.ts deleted file mode 100644 index cca83d4afb5..00000000000 --- a/packages/@react-spectrum/ai/exports/MessageFeedback.ts +++ /dev/null @@ -1 +0,0 @@ -export {MessageFeedback} from '../src/MessageFeedback'; diff --git a/packages/@react-spectrum/ai/exports/MessageSource.ts b/packages/@react-spectrum/ai/exports/MessageSource.ts deleted file mode 100644 index 45f17aca4ce..00000000000 --- a/packages/@react-spectrum/ai/exports/MessageSource.ts +++ /dev/null @@ -1,8 +0,0 @@ -export {MessageSource, SourceList, SourceListItem, NumberBadge} from '../src/MessageSource'; - -export type { - MessageSourceProps, - SourceListProps, - SourceListItemProps, - NumberBadgeProps -} from '../src/MessageSource'; diff --git a/packages/@react-spectrum/ai/exports/MessageSuggestion.ts b/packages/@react-spectrum/ai/exports/MessageSuggestion.ts deleted file mode 100644 index 03edf7e545e..00000000000 --- a/packages/@react-spectrum/ai/exports/MessageSuggestion.ts +++ /dev/null @@ -1 +0,0 @@ -export {MessageSuggestion, MessageSuggestionList} from '../src/MessageSuggestion'; diff --git a/packages/@react-spectrum/ai/exports/ResponseStatus.ts b/packages/@react-spectrum/ai/exports/ResponseStatus.ts deleted file mode 100644 index de2ca50f993..00000000000 --- a/packages/@react-spectrum/ai/exports/ResponseStatus.ts +++ /dev/null @@ -1,7 +0,0 @@ -export {ResponseStatus, ResponseStatusTitle, ResponseStatusPanel} from '../src/ResponseStatus'; - -export type { - ResponseStatusProps, - ResponseStatusTitleProps, - ResponseStatusPanelProps -} from '../src/ResponseStatus'; diff --git a/packages/@react-spectrum/ai/exports/UserMessage.ts b/packages/@react-spectrum/ai/exports/UserMessage.ts deleted file mode 100644 index f5cbd1b36bf..00000000000 --- a/packages/@react-spectrum/ai/exports/UserMessage.ts +++ /dev/null @@ -1 +0,0 @@ -export {UserMessage} from '../src/UserMessage'; diff --git a/packages/@react-spectrum/ai/exports/index.ts b/packages/@react-spectrum/ai/exports/index.ts index 40978ed667f..50bc70ba511 100644 --- a/packages/@react-spectrum/ai/exports/index.ts +++ b/packages/@react-spectrum/ai/exports/index.ts @@ -1,6 +1,45 @@ export {Attachment, AttachmentList} from '../src/AttachmentList'; -export {BasicHorizontalCard, HorizontalCard} from '../src/HorizontalCard'; +export {BasicHorizontalCard, CardPreview, HorizontalCard} from '../src/HorizontalCard'; export {MessageFeedback} from '../src/MessageFeedback'; +export {MessageSource, SourceList, SourceListItem} from '../src/MessageSource'; export {MessageSuggestion, MessageSuggestionList} from '../src/MessageSuggestion'; -export {ResponseStatus, ResponseStatusPanel} from '../src/ResponseStatus'; +export { + PromptField, + PromptFieldSubmitButton, + PromptTokenField, + AttachFileMenuItem, + InsertMenuButton, + InsertTokenMenuItem, + PromptFieldAttachmentList, + PromptFieldToolbar, + PromptToken +} from '../src/PromptField'; +export {ResponseStatus, ResponseStatusTitle, ResponseStatusPanel} from '../src/ResponseStatus'; +export {Chat, Thread, ThreadItem, ThreadScrollButton} from '../src/Chat'; +export {TokenSegmentList} from '../src/TokenSegmentList'; export {UserMessage} from '../src/UserMessage'; + +export type {AttachmentProps, AttachmentListProps} from '../src/AttachmentList'; +export type {HorizontalCardProps, BasicCardProps} from '../src/HorizontalCard'; +export type { + PromptFieldProps, + PromptFieldSubmitButtonProps, + PromptTokenFieldProps, + PromptTokenProps, + PromptFieldAttachment, + PromptFieldAttachmentListProps, + PromptTokenFieldPopoverProps, + PromptFieldToolbarProps, + InsertMenuItemProps +} from '../src/PromptField'; +export type {MessageFeedbackProps} from '../src/MessageFeedback'; +export type {MessageSourceProps, SourceListProps, SourceListItemProps} from '../src/MessageSource'; +export type {MessageSuggestionProps, MessageSuggestionListProps} from '../src/MessageSuggestion'; +export type { + ResponseStatusProps, + ResponseStatusTitleProps, + ResponseStatusPanelProps +} from '../src/ResponseStatus'; +export type {ChatProps, ThreadProps, ThreadItemProps, ThreadScrollButtonProps} from '../src/Chat'; +export type {TokenSegmentListOptions} from '../src/TokenSegmentList'; +export type {UserMessageProps} from '../src/UserMessage'; diff --git a/packages/@react-spectrum/ai/src/AttachmentList.tsx b/packages/@react-spectrum/ai/src/AttachmentList.tsx index e5b8b93e847..8881b4426b0 100644 --- a/packages/@react-spectrum/ai/src/AttachmentList.tsx +++ b/packages/@react-spectrum/ai/src/AttachmentList.tsx @@ -10,22 +10,34 @@ * governing permissions and limitations under the License. */ -import {AriaLabelingProps, DOMRef, forwardRefType} from '@react-types/shared'; +import {AriaLabelingProps, DOMRef, forwardRefType, GlobalDOMAttributes} from '@react-types/shared'; import {baseColor, focusRing, style} from '@react-spectrum/s2/style' with {type: 'macro'}; import {BasicHorizontalCard} from './HorizontalCard'; import {Button} from 'react-aria-components/Button'; import {CardProps} from '@react-spectrum/s2/Card'; import Close from '@react-spectrum/s2/icons/Close'; -import {forwardRef, useRef} from 'react'; +import {forwardRef, ReactNode, useRef} from 'react'; import {iconStyle} from '@react-spectrum/s2/style' with {type: 'macro'}; import {ImageContext} from '@react-spectrum/s2/Image'; import {mergeStyles} from '@react-spectrum/s2/mergeStyles'; import {pressScale} from '@react-spectrum/s2/pressScale'; import {ProgressCircle} from '@react-spectrum/s2/ProgressCircle'; -import {StyleProps, TagProps} from '@react-spectrum/s2'; -import {Tag, TagGroup, TagGroupProps, TagList, TagListProps} from 'react-aria-components/TagGroup'; +import {StyleString} from './types'; +import { + Tag, + TagGroup, + TagGroupProps, + TagList, + TagListProps, + TagProps +} from 'react-aria-components/TagGroup'; import {useDOMRef} from './useDOMRef'; +interface AttachmentRenderProps { + /** The size of the Card. */ + size: 'XS' | 'S' | 'M' | 'L' | 'XL'; +} + const controlSizeM = { default: 32, size: { @@ -108,9 +120,29 @@ const CloseButton = function CloseButton(props) { export interface AttachmentListProps extends - Omit, - StyleProps, - Pick, 'items' | 'children' | 'dependencies'> {} + Omit< + TagGroupProps, + | 'children' + | 'selectionMode' + | 'defaultSelectedKeys' + | 'selectionBehavior' + | 'selectedKeys' + | 'disallowEmptySelection' + | 'escapeKeyBehavior' + | 'onSelectionChange' + | 'shouldSelectOnPressUp' + | 'onAction' + | 'render' + | 'style' + | 'className' + | keyof GlobalDOMAttributes + >, + Pick, 'items' | 'children' | 'dependencies'> { + /** + * Spectrum-defined styles, returned by the `style()` macro. + */ + styles?: StyleString; +} export const AttachmentList = (forwardRef as forwardRefType)(function AttachmentList( props: AttachmentListProps, @@ -137,10 +169,27 @@ export const AttachmentList = (forwardRef as forwardRefType)(function Attachment }); export interface AttachmentProps - extends CardProps, AriaLabelingProps, Pick { + extends + Omit, + AriaLabelingProps, + Pick { + /** The children of the Attachment. */ + children: ReactNode | ((renderProps: AttachmentRenderProps) => ReactNode); uploadProgress?: number; + /** + * Spectrum-defined styles, returned by the `style()` macro. + */ + styles?: StyleString; } +const tagStyles = style({ + flexShrink: 0, + flexGrow: 0, + position: 'relative', + ...focusRing(), + borderRadius: 'default' +}); + export const Attachment = forwardRef(function Attachment( props: AttachmentProps, ref: DOMRef @@ -162,13 +211,7 @@ export const Attachment = forwardRef(function Attachment( aria-labelledby={ariaLabelledby} aria-describedby={ariaDescribedby} ref={domRef} - className={style({ - flexShrink: 0, - flexGrow: 0, - position: 'relative', - ...focusRing(), - borderRadius: 'default' - })}> + className={renderProps => mergeStyles(tagStyles({...renderProps}), props.styles)}> {props.uploadProgress != null && props.uploadProgress < 100 && (
( }); // TODO: make this more RAC like (aka default class name and other RAC prop) -interface ChatProps { +export interface ChatProps { className?: string; style?: CSSProperties; children?: ReactNode; @@ -198,7 +198,7 @@ export const Chat = /*#__PURE__*/ (forwardRef as forwardRefType)(function Chat( }); // TODO: update the items/className/children/etc type to reflect a thread specific classname once we finalize API -interface ThreadProps extends Pick< +export interface ThreadProps extends Pick< GridListProps, 'items' | 'children' | 'UNSTABLE_focusOnEntry' | 'aria-label' | 'aria-labelledby' | 'className' > {} @@ -261,14 +261,19 @@ export function Thread(props: ThreadProps) { aria-label={ariaLabel} aria-labelledby={ariaLabelledby} // TODO: for now we enforce this, but to be configurable? - style={{display: 'flex', flexDirection: 'column-reverse'}} + style={{ + display: 'flex', + flexDirection: 'column-reverse', + boxSizing: 'border-box', + minWidth: 0 + }} className={className}> {children} ); } -interface ThreadScrollButtonProps { +export interface ThreadScrollButtonProps { children?: ReactNode; } @@ -310,7 +315,10 @@ function ThreadScrollButtonInner({domRef, isExiting, children}: ThreadScrollButt } // TODO: update the className type to reflect a thread specific classname once we finalize API -interface ThreadItemProps extends Pick { +export interface ThreadItemProps extends Pick< + GridListItemProps, + 'className' | 'children' | 'textValue' +> { /** Whether or not the item's content is currently being streamed in. */ isStreaming?: boolean; /** Announce textValue on mount even when isStreaming is provided. */ diff --git a/packages/@react-spectrum/ai/src/HorizontalCard.tsx b/packages/@react-spectrum/ai/src/HorizontalCard.tsx index b56af6bcc1f..4135e44dbb3 100644 --- a/packages/@react-spectrum/ai/src/HorizontalCard.tsx +++ b/packages/@react-spectrum/ai/src/HorizontalCard.tsx @@ -39,12 +39,12 @@ import {SkeletonContext, useIsSkeleton} from '@react-spectrum/s2/Skeleton'; import {StyleString} from './types'; import {TextContext} from '@react-spectrum/s2/Text'; import {useDOMRef} from './useDOMRef'; -interface CardRenderProps { +interface HorizontalCardRenderProps { /** The size of the Card. */ size: 'XS' | 'S' | 'M' | 'L' | 'XL'; } -export interface CardProps extends Omit< +export interface HorizontalCardProps extends Omit< GridListItemProps, | 'className' | 'style' @@ -57,7 +57,7 @@ export interface CardProps extends Omit< | keyof GlobalDOMAttributes > { /** The children of the Card. */ - children: ReactNode | ((renderProps: CardRenderProps) => ReactNode); + children: ReactNode | ((renderProps: HorizontalCardRenderProps) => ReactNode); /** * The size of the Card. * @@ -82,7 +82,7 @@ export interface CardProps extends Omit< styles?: StyleString; } -export interface BasicCardProps extends Omit { +export interface BasicCardProps extends Omit { /** * The visual style of the Card. * @@ -193,8 +193,7 @@ let card = style({ XL: 80 } }, - isCardView: 'full', - [onlyPreview]: 68 + isCardView: 'full' }, width: { default: 'full', @@ -456,7 +455,7 @@ const actionButtonSize = { } as const; const Card = forwardRef(function Card( - props: Omit & { + props: Omit & { isBasic?: boolean; variant?: 'primary' | 'secondary' | 'tertiary' | 'quiet'; }, @@ -669,6 +668,7 @@ export interface CardPreviewProps extends DOMProps { styles?: StyleString; } +// TODO: this should be the same component as the one in @react-spectrum/s2/Card export const CardPreview = forwardRef(function CardPreview( props: CardPreviewProps, ref: DOMRef @@ -681,10 +681,7 @@ export const CardPreview = forwardRef(function CardPreview( {...filterDOMProps(props)} slot="preview" ref={domRef} - className={mergeStyles( - preview({size, isQuiet, isHovered, isFocusVisible, isSelected}), - props.styles - )} + className={preview({size, isQuiet, isHovered, isFocusVisible, isSelected})} style={isQuiet ? pressScale(domRef)({isPressed}) : undefined}> {isQuiet && } {isQuiet && isCheckboxSelection && } @@ -742,7 +739,7 @@ const buttonSize = { } as const; export const HorizontalCard = forwardRef(function HorizontalCard( - props: CardProps, + props: HorizontalCardProps, ref: DOMRef ) { let {size = 'M'} = props; diff --git a/packages/@react-spectrum/ai/src/MessageSource.tsx b/packages/@react-spectrum/ai/src/MessageSource.tsx index 687557b2a7e..e27648f6bd8 100644 --- a/packages/@react-spectrum/ai/src/MessageSource.tsx +++ b/packages/@react-spectrum/ai/src/MessageSource.tsx @@ -10,7 +10,13 @@ * governing permissions and limitations under the License. */ -import {AriaLabelingProps, DOMProps, DOMRef, forwardRefType} from '@react-types/shared'; +import { + AriaLabelingProps, + DOMProps, + DOMRef, + forwardRefType, + GlobalDOMAttributes +} from '@react-types/shared'; import {baseColor, focusRing, style} from '@react-spectrum/s2/style' with {type: 'macro'}; import { Disclosure, @@ -28,6 +34,7 @@ import {SlotProps} from 'react-aria-components/slots'; import {StyleString} from './types'; import {useDOMRef} from './useDOMRef'; import {useLocale} from 'react-aria/I18nProvider'; + export interface MessageSourceProps extends Omit< DisclosureProps, 'isQuiet' | 'styles' | 'UNSAFE_className' | 'UNSAFE_style' @@ -139,7 +146,8 @@ const linkStyles = style({ disableTapHighlight: true }); -export interface SourceListItemProps extends Omit, DOMProps { +export interface SourceListItemProps + extends Omit, DOMProps { /** The content of the source list item. */ children: React.ReactNode; /** diff --git a/packages/@react-spectrum/ai/src/MessageSuggestion.tsx b/packages/@react-spectrum/ai/src/MessageSuggestion.tsx index c1daf4303b1..6c3fc377b8f 100644 --- a/packages/@react-spectrum/ai/src/MessageSuggestion.tsx +++ b/packages/@react-spectrum/ai/src/MessageSuggestion.tsx @@ -10,7 +10,7 @@ * governing permissions and limitations under the License. */ -import {AriaLabelingProps, DOMProps, DOMRef} from '@react-types/shared'; +import {AriaLabelingProps, DOMProps, DOMRef, GlobalDOMAttributes} from '@react-types/shared'; import ArrowCurved from '@react-spectrum/s2/icons/ArrowCurved'; import { baseColor, @@ -42,7 +42,7 @@ const controlSizeM = { export interface MessageSuggestionProps extends Omit< ButtonProps, - 'style' | 'className' | 'isPending' | 'isDisabled' + 'style' | 'className' | 'isPending' | 'isDisabled' | keyof GlobalDOMAttributes > { /** The text content of the suggestion. */ children: ReactNode; diff --git a/packages/@react-spectrum/ai/src/PromptField.tsx b/packages/@react-spectrum/ai/src/PromptField.tsx index d4ca06edbd7..66851d662b0 100644 --- a/packages/@react-spectrum/ai/src/PromptField.tsx +++ b/packages/@react-spectrum/ai/src/PromptField.tsx @@ -52,26 +52,26 @@ import Send from '@react-spectrum/s2/icons/ArrowUpSend'; import Stop from '@react-spectrum/s2/icons/StopProcessing'; import {useFocusWithin} from 'react-aria/useFocusWithin'; -interface Attachment { +export interface PromptFieldAttachment { id: string; file: File; image: string; } -interface PromptFieldProps extends UnsafeStyles { +export interface PromptFieldProps extends UnsafeStyles { children: React.ReactNode; acceptedAttachmentTypes?: string[]; - onSubmit?: (prompt: TokenSegmentList, attachments: Attachment[]) => void; + onSubmit?: (prompt: TokenSegmentList, attachments: PromptFieldAttachment[]) => void; isGenerating?: boolean; onStop?: () => void; - onAddAttachments?: (attachments: Attachment[]) => void; - onRemoveAttachments?: (attachments: Attachment[]) => void; + onAddAttachments?: (attachments: PromptFieldAttachment[]) => void; + onRemoveAttachments?: (attachments: PromptFieldAttachment[]) => void; styles?: StyleString; } interface PromptFieldState { - attachments: Attachment[]; - setAttachments: React.Dispatch>; + attachments: PromptFieldAttachment[]; + setAttachments: React.Dispatch>; acceptedAttachmentTypes?: string[]; prompt: TokenSegmentList; setPrompt: React.Dispatch>; @@ -79,8 +79,8 @@ interface PromptFieldState { onSubmit?: () => void; onStop?: () => void; isGenerating: boolean; - onAddAttachments?: (attachments: Attachment[]) => void; - onRemoveAttachments?: (attachments: Attachment[]) => void; + onAddAttachments?: (attachments: PromptFieldAttachment[]) => void; + onRemoveAttachments?: (attachments: PromptFieldAttachment[]) => void; } // TODO: make this customizable @@ -146,7 +146,7 @@ export function PromptField(props: PromptFieldProps) { onRemoveAttachments } = props; let [prompt, setPrompt] = useState(new AutoLinkingSegmentList([])); - let [attachments, setAttachments] = useState([]); + let [attachments, setAttachments] = useState([]); // Not using RAC DropZone because it adds its own focusable button, // and we want to avoid an extra tab. We support pasting files directly into the input. @@ -261,8 +261,8 @@ export function PromptField(props: PromptFieldProps) { ); } -interface PromptFieldAttachmentListProps extends AttachmentListProps { - children?: (attachment: Attachment) => React.ReactNode; +export interface PromptFieldAttachmentListProps extends AttachmentListProps { + children?: (attachment: PromptFieldAttachment) => React.ReactNode; } export function PromptFieldAttachmentList(props: PromptFieldAttachmentListProps) { @@ -295,7 +295,7 @@ export function PromptFieldAttachmentList(props: PromptFieldAttachmentListProps) ); } -interface PromptTokenFieldProps { +export interface PromptTokenFieldProps { completionTrigger?: RegExp; renderCompletions?: ( filterValue: string @@ -358,7 +358,7 @@ export function PromptTokenField(props: PromptTokenFieldProps) { acceptedAttachmentTypes ? e => { let clipboardData = e.clipboardData as DataTransfer; - let attachments: Attachment[] = []; + let attachments: PromptFieldAttachment[] = []; for (let item of clipboardData.items) { if (matchMimeType(item.type, acceptedAttachmentTypes)) { let file = item.getAsFile()!; @@ -404,7 +404,7 @@ export function PromptTokenField(props: PromptTokenFieldProps) { ); } -interface PromptTokenFieldPopoverProps extends PopoverProps { +export interface PromptTokenFieldPopoverProps extends PopoverProps { filterAnchor?: Position | null; items?: React.ReactNode[] | null | Promise; isFocused?: boolean; @@ -496,7 +496,7 @@ export function PromptToken(props: PromptTokenProps) { ); } -interface PromptFieldToolbarProps { +export interface PromptFieldToolbarProps { children: React.ReactNode; } @@ -515,7 +515,10 @@ export function PromptFieldToolbar(props: PromptFieldToolbarProps) { ); } -export function PromptFieldSubmitButton() { +export interface PromptFieldSubmitButtonProps {} + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export function PromptFieldSubmitButton(props: PromptFieldSubmitButtonProps) { let {prompt, isGenerating, onSubmit, onStop} = useContext(PromptFieldContext); return (