Repository navigation
feat: modernize drawer #5052
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: modernize drawer #5052
Changes from all commits
555b23e
b746c65
ad5c200
b845692
d85720f
de1a5c0
ddb2b9c
cb43d83
f6e0a26
ce6db57
0ee42bc
d71d652
09fe61b
c665c63
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -6,6 +6,23 @@ TBC | |||||||||||||
|
|
||||||||||||||
| ## Components | ||||||||||||||
|
|
||||||||||||||
| ### Drawer | ||||||||||||||
|
|
||||||||||||||
| The `Drawer` API is unchanged in Paper 6.x — no props were renamed, removed, or given new defaults. `Drawer.Item` and `Drawer.Section` were realigned with the current Material Design 3 navigation drawer spec, so their appearance changes: | ||||||||||||||
|
|
||||||||||||||
| - **Trailing padding.** `Drawer.Item` reserved 36dp on the trailing edge and 28dp on the leading edge. Both are now 28dp, as the spec requires. Items sit 8dp wider. | ||||||||||||||
| - **Active label weight.** The label of an active `Drawer.Item` now uses the prominent `labelLargeEmphasized` weight (700). Inactive labels are unchanged at 500. | ||||||||||||||
| - **Section divider colour.** `Drawer.Section` drew its divider in a fixed grey that ignored the theme and was wrong in dark mode. It now uses `theme.colors.outlineVariant`, like every other `Divider`. | ||||||||||||||
| - **Focus indicator.** `Drawer.Item` gains a keyboard focus ring in `theme.colors.secondary`. It appears only on keyboard focus, not on press. | ||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The list leaves out the disabled change. A disabled
Suggested change
(via Claude, verify if it makes sense) |
||||||||||||||
|
|
||||||||||||||
| If you were pixel-matching a drawer against Paper 5.x, the first two points are the ones that will shift your layout. To restore the old trailing padding, pass it through `style`: | ||||||||||||||
|
|
||||||||||||||
| ```tsx | ||||||||||||||
| <Drawer.Item label="Inbox" icon="inbox" style={{ marginEnd: 20 }} /> | ||||||||||||||
| ``` | ||||||||||||||
|
Comment on lines
+18
to
+22
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This snippet does not restore the 5.x layout.
Suggested change
(via Claude, verify if it makes sense) |
||||||||||||||
|
|
||||||||||||||
| The theme also gains the 15 `*Emphasized` typescale keys (`labelLargeEmphasized`, `titleSmallEmphasized`, and so on). The values already existed in the token set; only the types were missing, so `<Text variant="labelLargeEmphasized">` now typechecks. This is additive — no existing key changed. | ||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two problems with this paragraph:
|
||||||||||||||
|
|
||||||||||||||
| ### TextInput | ||||||||||||||
|
|
||||||||||||||
| The Paper 6.x `TextInput` is a complete rewrite with a new API. Import the component the same way, but note that the props and behavior have changed significantly. | ||||||||||||||
|
|
||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,196 @@ | ||||||||||||||||||||||||||||||||
| import * as React from 'react'; | ||||||||||||||||||||||||||||||||
| import { StyleSheet, View } from 'react-native'; | ||||||||||||||||||||||||||||||||
| import type { ColorValue } from 'react-native'; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| import { Badge, Drawer, Text, useTheme } from 'react-native-paper'; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| import ScreenWrapper from '../ScreenWrapper'; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| const DRAWER_WIDTH = 360; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| const Section = ({ | ||||||||||||||||||||||||||||||||
| title, | ||||||||||||||||||||||||||||||||
| children, | ||||||||||||||||||||||||||||||||
| }: { | ||||||||||||||||||||||||||||||||
| title: string; | ||||||||||||||||||||||||||||||||
| children: React.ReactNode; | ||||||||||||||||||||||||||||||||
| }) => { | ||||||||||||||||||||||||||||||||
| const theme = useTheme(); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||
| <View style={styles.section}> | ||||||||||||||||||||||||||||||||
| <Text | ||||||||||||||||||||||||||||||||
| variant="labelSmall" | ||||||||||||||||||||||||||||||||
| style={[styles.caption, { color: theme.colors.onSurfaceVariant }]} | ||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||
| {title} | ||||||||||||||||||||||||||||||||
| </Text> | ||||||||||||||||||||||||||||||||
| <View | ||||||||||||||||||||||||||||||||
| style={[ | ||||||||||||||||||||||||||||||||
| styles.drawer, | ||||||||||||||||||||||||||||||||
| { backgroundColor: theme.colors.surfaceContainerLow }, | ||||||||||||||||||||||||||||||||
| ]} | ||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||
| {children} | ||||||||||||||||||||||||||||||||
| </View> | ||||||||||||||||||||||||||||||||
| </View> | ||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| const Destinations = () => { | ||||||||||||||||||||||||||||||||
| const [active, setActive] = React.useState('inbox'); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||
| <Drawer.Section title="Mail" showDivider={false}> | ||||||||||||||||||||||||||||||||
| <Drawer.Item | ||||||||||||||||||||||||||||||||
| icon="inbox" | ||||||||||||||||||||||||||||||||
| label="Inbox" | ||||||||||||||||||||||||||||||||
| active={active === 'inbox'} | ||||||||||||||||||||||||||||||||
| onPress={() => setActive('inbox')} | ||||||||||||||||||||||||||||||||
| right={() => <Text variant="labelLarge">24</Text>} | ||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||
| <Drawer.Item | ||||||||||||||||||||||||||||||||
| icon="star" | ||||||||||||||||||||||||||||||||
| label="Starred" | ||||||||||||||||||||||||||||||||
| active={active === 'starred'} | ||||||||||||||||||||||||||||||||
| onPress={() => setActive('starred')} | ||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||
| <Drawer.Item | ||||||||||||||||||||||||||||||||
| icon="send" | ||||||||||||||||||||||||||||||||
| label="Sent" | ||||||||||||||||||||||||||||||||
| active={active === 'sent'} | ||||||||||||||||||||||||||||||||
| onPress={() => setActive('sent')} | ||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||
| </Drawer.Section> | ||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| const DrawerExample = () => { | ||||||||||||||||||||||||||||||||
| const [collapsed, setCollapsed] = React.useState('inbox'); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||
| <ScreenWrapper contentContainerStyle={styles.content}> | ||||||||||||||||||||||||||||||||
| <Section title="Destinations — tap to change the active one"> | ||||||||||||||||||||||||||||||||
| <Destinations /> | ||||||||||||||||||||||||||||||||
| </Section> | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| <Section title="Without an icon, and with a truncated label"> | ||||||||||||||||||||||||||||||||
| <Drawer.Section showDivider={false}> | ||||||||||||||||||||||||||||||||
| <Drawer.Item label="No icon" /> | ||||||||||||||||||||||||||||||||
| <Drawer.Item | ||||||||||||||||||||||||||||||||
| icon="delete" | ||||||||||||||||||||||||||||||||
| label="A very long destination label that will be truncated" | ||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||
| </Drawer.Section> | ||||||||||||||||||||||||||||||||
| </Section> | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| <Section title="Disabled"> | ||||||||||||||||||||||||||||||||
| <Drawer.Section showDivider={false}> | ||||||||||||||||||||||||||||||||
| <Drawer.Item icon="archive" label="Archive" disabled /> | ||||||||||||||||||||||||||||||||
| <Drawer.Item | ||||||||||||||||||||||||||||||||
| icon="star" | ||||||||||||||||||||||||||||||||
| label="Active and disabled" | ||||||||||||||||||||||||||||||||
| active | ||||||||||||||||||||||||||||||||
| disabled | ||||||||||||||||||||||||||||||||
| right={() => <Text variant="labelLarge">24</Text>} | ||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||
| </Drawer.Section> | ||||||||||||||||||||||||||||||||
| </Section> | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| <Section title="Trailing slot"> | ||||||||||||||||||||||||||||||||
| <Drawer.Section showDivider={false}> | ||||||||||||||||||||||||||||||||
| <Drawer.Item | ||||||||||||||||||||||||||||||||
| icon="alert" | ||||||||||||||||||||||||||||||||
| label="Badge" | ||||||||||||||||||||||||||||||||
| right={() => <Badge visible style={styles.badge} />} | ||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||
| <Drawer.Item | ||||||||||||||||||||||||||||||||
| icon="palette" | ||||||||||||||||||||||||||||||||
| label="Coloured dot" | ||||||||||||||||||||||||||||||||
| right={({ color }: { color: ColorValue }) => ( | ||||||||||||||||||||||||||||||||
| <Badge | ||||||||||||||||||||||||||||||||
| visible | ||||||||||||||||||||||||||||||||
| style={[styles.badge, { backgroundColor: color }]} | ||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||
| </Drawer.Section> | ||||||||||||||||||||||||||||||||
| </Section> | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| <Section title="Sections separated by a divider"> | ||||||||||||||||||||||||||||||||
| <Drawer.Section title="Mailboxes"> | ||||||||||||||||||||||||||||||||
| <Drawer.Item icon="inbox" label="Inbox" /> | ||||||||||||||||||||||||||||||||
| </Drawer.Section> | ||||||||||||||||||||||||||||||||
| <Drawer.Section title="Labels" showDivider={false}> | ||||||||||||||||||||||||||||||||
| <Drawer.Item icon="tag" label="Work" /> | ||||||||||||||||||||||||||||||||
| </Drawer.Section> | ||||||||||||||||||||||||||||||||
| </Section> | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| <Section title="Collapsed destinations"> | ||||||||||||||||||||||||||||||||
| <View style={styles.collapsed}> | ||||||||||||||||||||||||||||||||
| <Drawer.CollapsedItem | ||||||||||||||||||||||||||||||||
| focusedIcon="inbox" | ||||||||||||||||||||||||||||||||
| unfocusedIcon="inbox-outline" | ||||||||||||||||||||||||||||||||
| label="Inbox" | ||||||||||||||||||||||||||||||||
| badge={24} | ||||||||||||||||||||||||||||||||
| active={collapsed === 'inbox'} | ||||||||||||||||||||||||||||||||
| onPress={() => setCollapsed('inbox')} | ||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||
| <Drawer.CollapsedItem | ||||||||||||||||||||||||||||||||
| focusedIcon="star" | ||||||||||||||||||||||||||||||||
| unfocusedIcon="star-outline" | ||||||||||||||||||||||||||||||||
| label="Starred" | ||||||||||||||||||||||||||||||||
| active={collapsed === 'starred'} | ||||||||||||||||||||||||||||||||
| onPress={() => setCollapsed('starred')} | ||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||
| <Drawer.CollapsedItem | ||||||||||||||||||||||||||||||||
| focusedIcon="bell" | ||||||||||||||||||||||||||||||||
| unfocusedIcon="bell-outline" | ||||||||||||||||||||||||||||||||
| badge | ||||||||||||||||||||||||||||||||
| active={collapsed === 'alerts'} | ||||||||||||||||||||||||||||||||
| onPress={() => setCollapsed('alerts')} | ||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||
|
Comment on lines
+146
to
+152
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This item has no
Suggested change
(via Claude, verify if it makes sense) |
||||||||||||||||||||||||||||||||
| <Drawer.CollapsedItem | ||||||||||||||||||||||||||||||||
| focusedIcon="archive" | ||||||||||||||||||||||||||||||||
| unfocusedIcon="archive-outline" | ||||||||||||||||||||||||||||||||
| label="Disabled" | ||||||||||||||||||||||||||||||||
| disabled | ||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||
| </View> | ||||||||||||||||||||||||||||||||
| </Section> | ||||||||||||||||||||||||||||||||
| </ScreenWrapper> | ||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| DrawerExample.title = 'Drawer'; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| const styles = StyleSheet.create({ | ||||||||||||||||||||||||||||||||
| content: { | ||||||||||||||||||||||||||||||||
| paddingVertical: 16, | ||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||
| section: { | ||||||||||||||||||||||||||||||||
| marginBottom: 24, | ||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||
| caption: { | ||||||||||||||||||||||||||||||||
| marginBottom: 8, | ||||||||||||||||||||||||||||||||
| marginHorizontal: 16, | ||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||
| drawer: { | ||||||||||||||||||||||||||||||||
| width: DRAWER_WIDTH, | ||||||||||||||||||||||||||||||||
| maxWidth: '100%', | ||||||||||||||||||||||||||||||||
| alignSelf: 'center', | ||||||||||||||||||||||||||||||||
| paddingVertical: 8, | ||||||||||||||||||||||||||||||||
| borderTopEndRadius: 16, | ||||||||||||||||||||||||||||||||
| borderBottomEndRadius: 16, | ||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||
| badge: { | ||||||||||||||||||||||||||||||||
| alignSelf: 'center', | ||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||
| collapsed: { | ||||||||||||||||||||||||||||||||
| flexDirection: 'row', | ||||||||||||||||||||||||||||||||
| justifyContent: 'center', | ||||||||||||||||||||||||||||||||
| paddingVertical: 8, | ||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| export default DrawerExample; | ||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Items sit 8dp wider" is not what changed. The active indicator keeps its size: 12dp from each drawer edge on main and in this PR (336dp wide in a 360dp drawer). Only the content area grows by 8dp on the trailing side, so long labels truncate later and the
rightcontent moves 8dp toward the edge.(via Claude, verify if it makes sense)