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],
) )
const backButton = useCallback(
() => (
<Button
label={_(msg`Back`)}
onPress={() => control.close()}
size="small"
color="primary"
variant="ghost"
shape="round">
<ButtonIcon icon={ArrowLeftIcon} size="md" />
</Button>
),
[control, _],
)
const listHeader = useMemo(() => {
return (
<Dialog.Header renderLeft={backButton}>
<Dialog.HeaderText>
<Trans>Drafts</Trans>
</Dialog.HeaderText>
</Dialog.Header>
)
}, [backButton])
const renderItem = useCallback(
({item}: {item: DraftSummary}) => {
return (
<DraftItem
draft={item}
onSelect={handleSelectDraft}
onDelete={handleDeleteDraft}
isDeleting={isDeleting}
/>
)
},
[handleSelectDraft, handleDeleteDraft, isDeleting],
)
const emptyComponent = useMemo(() => {
if (isLoading) {
return (
<View style={[a.py_xl, a.align_center]}>
<Loader size="lg" />
</View>
)
}
return (
<View style={[a.py_xl, a.align_center]}>
<Text style={[t.atoms.text_contrast_medium]}>
<Trans>No drafts saved</Trans>
</Text>
</View>
)
}, [isLoading, t.atoms.text_contrast_medium])
return ( return (
<Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}> <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}>
<Dialog.Handle /> <Dialog.Handle />
<Dialog.ScrollableInner label={_(msg`Your Drafts`)}> <Dialog.InnerFlatList
<View style={[a.gap_md]}> data={drafts ?? []}
<Text style={[a.text_2xl, a.font_semi_bold]}> renderItem={renderItem}
<Trans>Your Drafts</Trans> keyExtractor={item => item.id}
</Text> ListHeaderComponent={listHeader}
ListEmptyComponent={emptyComponent}
{isLoading ? ( stickyHeaderIndices={[0]}
<View style={[a.py_xl, a.align_center]}> contentContainerStyle={[a.pb_lg]}
<Loader size="lg" /> ItemSeparatorComponent={() => <View style={[{height: 8}]} />}
</View> style={[a.px_lg]}
) : drafts && drafts.length > 0 ? ( />
<View style={[a.gap_sm]}>
{drafts.map(draft => (
<DraftItem
key={draft.id}
draft={draft}
onSelect={handleSelectDraft}
onDelete={handleDeleteDraft}
isDeleting={isDeleting}
/>
))}
</View>
) : (
<View style={[a.py_xl, a.align_center]}>
<Text style={[t.atoms.text_contrast_medium]}>
<Trans>No drafts saved</Trans>
</Text>
</View>
)}
</View>
<Dialog.Close />
</Dialog.ScrollableInner>
</Dialog.Outer> </Dialog.Outer>
) )
} }