Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 92 additions & 35 deletions packages/@react-spectrum/ai/src/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
* governing permissions and limitations under the License.
*/

import {ActionButton} from '@react-spectrum/s2';
import {announce} from 'react-aria/private/live-announcer/LiveAnnouncer';
import {ButtonContext} from 'react-aria-components/Button';
import ChevronDown from '@react-spectrum/s2/icons/ChevronDown';
import {
CollectionRendererContext,
createLeafComponent
Expand All @@ -34,6 +36,7 @@ import {DEFAULT_SLOT, Provider} from 'react-aria-components/slots';
import {DOMRef, forwardRefType, Node} from '@react-types/shared';
import {filterDOMProps} from 'react-aria/filterDOMProps';
import {focusRing, style, StyleString} from '@react-spectrum/s2/style' with {type: 'macro'};
// @ts-ignore
import {
GridList,
GridListItem,
Expand All @@ -42,12 +45,12 @@ import {
GridListProps
} from 'react-aria-components/GridList';
import {inertValue} from 'react-aria/private/utils/inertValue';
// @ts-ignore
import intlMessages from '../intl/*.json';
import {ListLayout} from './ListLayout';
import {ListStateContext} from 'react-aria-components/ListBox';
import {LoaderNode} from 'react-aria/private/collections/BaseCollection';
import {mergeStyles} from '@react-spectrum/s2/mergeStyles';
import {scrollFade} from './tokens.macro' with {type: 'macro'};
import {useDOMRef} from './useDOMRef';
import {useEnterAnimation, useExitAnimation} from 'react-aria/private/utils/animation';
import {useFocusWithin} from 'react-aria/useFocusWithin';
Expand Down Expand Up @@ -227,7 +230,23 @@ export const Chat = /*#__PURE__*/ (forwardRef as forwardRefType)(function Chat(
}
]
]}>
<div ref={domRef} className={styles} {...focusWithinProps}>
<div
ref={domRef}
className={mergeStyles(
style({
display: 'flex',
flexDirection: 'column',
overflow: 'hidden',
flexGrow: 1,
paddingX: 16,
boxSizing: 'border-box',
minWidth: 0,
containerType: 'size',
height: 'full'
}),
styles
)}
{...focusWithinProps}>
{children}
</div>
</Provider>
Expand Down Expand Up @@ -288,39 +307,77 @@ export function Thread<T extends object>(props: ThreadProps<T>) {
}, [setIsNearBottom, scrollEndThreshold]);

return (
<Virtualizer
layout={ListLayout}
layoutOptions={{
estimatedRowHeight: 100,
padding: 4,
gap: 8,
anchorTo: 'end',
loaderSize: 48,
scrollEndThreshold
}}
shouldObserveItemSize>
<GridList
ref={callbackRef}
disallowTypeAhead
onScroll={handleScroll}
keyboardNavigationBehavior="tab"
UNSTABLE_focusOnEntry="last"
items={items}
aria-label={ariaLabel}
aria-labelledby={ariaLabelledby}
// TODO: for now we enforce this, but to be configurable?
style={
{
display: 'flex',
boxSizing: 'border-box',
minWidth: 0,
scrollbarGutter: 'stable'
} as CSSProperties
}
className={styles}>
{children}
</GridList>
</Virtualizer>
<div
className={mergeStyles(
style({
position: 'relative',
flexGrow: 1,
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
minWidth: 0
}),
styles
)}>
{/* TODO: do we want the scroll button to be optional? */}
<div
className={style({
position: 'absolute',
bottom: 16,
left: '50%',
transform: 'translateX(-50%)',
zIndex: 1
})}>
<ThreadScrollButton>
<ActionButton slot="scroll" aria-label="Scroll to bottom">
<ChevronDown />
</ActionButton>
</ThreadScrollButton>
</div>
<Virtualizer
layout={ListLayout}
layoutOptions={{
estimatedRowHeight: 100,
// TODO: adjust this for small size prompt field (line up with icon/buttons)
padding: 24,
gap: 16,
anchorTo: 'end',
loaderSize: 48,
scrollEndThreshold
}}
shouldObserveItemSize>
<GridList
ref={callbackRef}
disallowTypeAhead
onScroll={handleScroll}
keyboardNavigationBehavior="tab"
UNSTABLE_focusOnEntry="last"
items={items}
aria-label={ariaLabel}
aria-labelledby={ariaLabelledby}
// TODO: for now we enforce this, but to be configurable?
style={
{
display: 'flex',
boxSizing: 'border-box',
minWidth: 0,
scrollbarGutter: 'stable'
} as CSSProperties
}
className={
scrollFade({y: 32}) +
' ' +
style({
flexGrow: 1,
overflowX: 'hidden',
overflowY: 'auto',
scrollPadding: 24
})
}>
{children}
</GridList>
</Virtualizer>
</div>
);
}

Expand Down
Loading