Use InnerFlatList and Dialog.Header for drafts dialog

- Switch from ScrollableInner to InnerFlatList
- Add Dialog.Header with back button in left slot
- Use sticky header

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Samuel Newman
2026-01-13 13:58:57 +02:00
parent ff3be5f841
commit ead99f123b
@@ -1,4 +1,4 @@
import {useCallback} from 'react' import {useCallback, useMemo} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {msg, Trans} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
@@ -11,7 +11,9 @@ import {
useLoadDraft, useLoadDraft,
} from '#/state/drafts' } from '#/state/drafts'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {Button, ButtonIcon} from '#/components/Button'
import * as Dialog from '#/components/Dialog' import * as Dialog from '#/components/Dialog'
import {ArrowLeft_Stroke2_Corner0_Rounded as ArrowLeftIcon} from '#/components/icons/Arrow'
import {Loader} from '#/components/Loader' import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {DraftItem} from './DraftItem' import {DraftItem} from './DraftItem'
@@ -48,42 +50,76 @@ export function DraftsListDialog({
[deleteDraft], [deleteDraft],
) )
return ( const backButton = useCallback(
<Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}> () => (
<Dialog.Handle /> <Button
<Dialog.ScrollableInner label={_(msg`Your Drafts`)}> label={_(msg`Back`)}
<View style={[a.gap_md]}> onPress={() => control.close()}
<Text style={[a.text_2xl, a.font_semi_bold]}> size="small"
<Trans>Your Drafts</Trans> color="primary"
</Text> variant="ghost"
shape="round">
<ButtonIcon icon={ArrowLeftIcon} size="md" />
</Button>
),
[control, _],
)
{isLoading ? ( const listHeader = useMemo(() => {
<View style={[a.py_xl, a.align_center]}> return (
<Loader size="lg" /> <Dialog.Header renderLeft={backButton}>
</View> <Dialog.HeaderText>
) : drafts && drafts.length > 0 ? ( <Trans>Drafts</Trans>
<View style={[a.gap_sm]}> </Dialog.HeaderText>
{drafts.map(draft => ( </Dialog.Header>
)
}, [backButton])
const renderItem = useCallback(
({item}: {item: DraftSummary}) => {
return (
<DraftItem <DraftItem
key={draft.id} draft={item}
draft={draft}
onSelect={handleSelectDraft} onSelect={handleSelectDraft}
onDelete={handleDeleteDraft} onDelete={handleDeleteDraft}
isDeleting={isDeleting} isDeleting={isDeleting}
/> />
))} )
},
[handleSelectDraft, handleDeleteDraft, isDeleting],
)
const emptyComponent = useMemo(() => {
if (isLoading) {
return (
<View style={[a.py_xl, a.align_center]}>
<Loader size="lg" />
</View> </View>
) : ( )
}
return (
<View style={[a.py_xl, a.align_center]}> <View style={[a.py_xl, a.align_center]}>
<Text style={[t.atoms.text_contrast_medium]}> <Text style={[t.atoms.text_contrast_medium]}>
<Trans>No drafts saved</Trans> <Trans>No drafts saved</Trans>
</Text> </Text>
</View> </View>
)} )
</View> }, [isLoading, t.atoms.text_contrast_medium])
<Dialog.Close /> return (
</Dialog.ScrollableInner> <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}>
<Dialog.Handle />
<Dialog.InnerFlatList
data={drafts ?? []}
renderItem={renderItem}
keyExtractor={item => item.id}
ListHeaderComponent={listHeader}
ListEmptyComponent={emptyComponent}
stickyHeaderIndices={[0]}
contentContainerStyle={[a.pb_lg]}
ItemSeparatorComponent={() => <View style={[{height: 8}]} />}
style={[a.px_lg]}
/>
</Dialog.Outer> </Dialog.Outer>
) )
} }