WIP custom dialog
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
import {createContext, useMemo, useContext, useState, ReactNode} from 'react'
|
||||
import {View, ScrollView, useWindowDimensions} from 'react-native'
|
||||
// import {FocusScope} from 'radix-ui/internal'
|
||||
// import {RemoveScrollBar} from 'react-remove-scroll-bar'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import {LinearGradient} from 'expo-linear-gradient'
|
||||
|
||||
import {isNative} from '#/platform/detection'
|
||||
import {atoms as a, useTheme, useBreakpoints, web, flatten} from '#/alf'
|
||||
import {transparentifyColor} from '#/alf/util/colorGeneration'
|
||||
import {useA11y} from '#/state/a11y'
|
||||
|
||||
const GUTTER = 24
|
||||
|
||||
export const Context = createContext({
|
||||
close: () => {},
|
||||
})
|
||||
|
||||
export function useAnnouncementDialogContext() {
|
||||
return useContext(Context)
|
||||
}
|
||||
|
||||
export function AnnouncementDialogOuter({children}: {children: ReactNode}) {
|
||||
const [open, setOpen] = useState(true)
|
||||
|
||||
const ctx = useMemo(
|
||||
() => ({
|
||||
close() {
|
||||
setOpen(false)
|
||||
},
|
||||
}),
|
||||
[setOpen],
|
||||
)
|
||||
|
||||
return <Context.Provider value={ctx}>{open && children}</Context.Provider>
|
||||
}
|
||||
|
||||
export function AnnouncementDialog({
|
||||
children,
|
||||
label,
|
||||
}: {
|
||||
children: ReactNode
|
||||
label: string
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const {gtPhone} = useBreakpoints()
|
||||
const {reduceMotionEnabled} = useA11y()
|
||||
const {height} = useWindowDimensions()
|
||||
const insets = useSafeAreaInsets()
|
||||
|
||||
return (
|
||||
<>
|
||||
<View style={[a.fixed, a.inset_0, !reduceMotionEnabled && a.fade_in]}>
|
||||
<LinearGradient
|
||||
colors={[
|
||||
transparentifyColor(t.atoms.bg.backgroundColor, 0),
|
||||
t.atoms.bg.backgroundColor,
|
||||
t.atoms.bg.backgroundColor,
|
||||
]}
|
||||
start={[0.5, 0]}
|
||||
end={[0.5, 1]}
|
||||
style={[a.absolute, a.inset_0]}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* <RemoveScrollBar /> */}
|
||||
|
||||
<ScrollView
|
||||
showsVerticalScrollIndicator={false}
|
||||
style={[a.fixed, a.inset_0, a.z_10]}
|
||||
contentContainerStyle={[
|
||||
a.align_center,
|
||||
gtPhone &&
|
||||
web({
|
||||
paddingHorizontal: GUTTER,
|
||||
paddingVertical: '10vh',
|
||||
}),
|
||||
]}>
|
||||
{/**
|
||||
* This is needed to prevent centered dialogs from overflowing
|
||||
* above the screen, and provides a "natural" centering so that
|
||||
* stacked dialogs appear relatively aligned.
|
||||
*/}
|
||||
<View
|
||||
style={[
|
||||
a.w_full,
|
||||
a.z_20,
|
||||
a.align_center,
|
||||
!gtPhone && a.justify_end,
|
||||
{minHeight: height},
|
||||
isNative && [
|
||||
{
|
||||
paddingBottom: Math.max(insets.bottom, a.p_2xl.padding),
|
||||
},
|
||||
],
|
||||
]}>
|
||||
{/* <FocusScope.FocusScope loop asChild trapped> */}
|
||||
|
||||
{!gtPhone && (
|
||||
<View
|
||||
style={[
|
||||
a.flex_1,
|
||||
a.w_full,
|
||||
{
|
||||
minHeight: Math.max(insets.top, a.p_2xl.padding),
|
||||
},
|
||||
]}>
|
||||
<LinearGradient
|
||||
colors={[
|
||||
transparentifyColor(t.atoms.bg.backgroundColor, 0),
|
||||
t.atoms.bg.backgroundColor,
|
||||
]}
|
||||
start={[0.5, 0]}
|
||||
end={[0.5, 1]}
|
||||
style={[a.absolute, a.inset_0]}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
|
||||
<View
|
||||
role="dialog"
|
||||
aria-role="dialog"
|
||||
aria-label={label}
|
||||
style={flatten([
|
||||
a.relative,
|
||||
a.w_full,
|
||||
a.p_2xl,
|
||||
t.atoms.bg,
|
||||
!reduceMotionEnabled && a.zoom_fade_in,
|
||||
gtPhone && [
|
||||
a.rounded_md,
|
||||
a.border,
|
||||
t.atoms.shadow_lg,
|
||||
t.atoms.border_contrast_low,
|
||||
web({
|
||||
maxWidth: 420,
|
||||
}),
|
||||
],
|
||||
])}>
|
||||
{children}
|
||||
</View>
|
||||
{/* </FocusScope.FocusScope> */}
|
||||
</View>
|
||||
</ScrollView>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -4,16 +4,15 @@ import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {Nux} from '#/state/queries/nuxs'
|
||||
import {atoms as a, useTheme, web} from '#/alf'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Button, ButtonText} from '#/components/Button'
|
||||
import * as Dialog from '#/components/Dialog'
|
||||
import {
|
||||
AnnouncementBadge,
|
||||
useAnnouncementState,
|
||||
useForceClose,
|
||||
} from '#/components/dialogs/BlockingAnnouncements/common'
|
||||
import {InlineLinkText} from '#/components/Link'
|
||||
import {Span, Text} from '#/components/Typography'
|
||||
import {AnnouncementDialog, useAnnouncementDialogContext} from '#/components/dialogs/BlockingAnnouncements/AnnouncementDialog'
|
||||
|
||||
export function useLocalState() {
|
||||
return useAnnouncementState({
|
||||
@@ -24,12 +23,12 @@ export function useLocalState() {
|
||||
export function Announcement() {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const forceClose = useForceClose()
|
||||
const {complete} = useLocalState()
|
||||
const {close} = useAnnouncementDialogContext()
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
forceClose(() => complete())
|
||||
}, [forceClose, complete])
|
||||
close()
|
||||
}, [close, complete])
|
||||
|
||||
const linkStyle = [a.text_md]
|
||||
const links = {
|
||||
@@ -66,9 +65,7 @@ export function Announcement() {
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog.ScrollableInner
|
||||
label={_(msg`We’re updating our policies`)}
|
||||
style={[web({maxWidth: 420})]}>
|
||||
<AnnouncementDialog label={_(msg`We're updating our policies`)}>
|
||||
<View style={[a.align_start, a.gap_xl]}>
|
||||
<AnnouncementBadge />
|
||||
|
||||
@@ -136,6 +133,6 @@ export function Announcement() {
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</Dialog.ScrollableInner>
|
||||
</AnnouncementDialog>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {BlockingAnnouncementDialogOuter} from '#/components/dialogs/BlockingAnnouncements/common'
|
||||
import {AnnouncementDialogOuter} from '#/components/dialogs/BlockingAnnouncements/AnnouncementDialog'
|
||||
import * as PolicyUpdate20250801 from '#/components/dialogs/BlockingAnnouncements/PolicyUpdate20250801'
|
||||
|
||||
export function BlockingAnnouncements() {
|
||||
@@ -9,13 +9,11 @@ export function BlockingAnnouncements() {
|
||||
* NUX state for local testing and debugging.
|
||||
*/
|
||||
|
||||
if (policyUpdate20250801.completed) return null
|
||||
|
||||
return (
|
||||
<>
|
||||
{!policyUpdate20250801.completed && (
|
||||
<BlockingAnnouncementDialogOuter>
|
||||
<PolicyUpdate20250801.Announcement />
|
||||
</BlockingAnnouncementDialogOuter>
|
||||
)}
|
||||
</>
|
||||
<AnnouncementDialogOuter>
|
||||
<PolicyUpdate20250801.Announcement />
|
||||
</AnnouncementDialogOuter>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -156,7 +156,6 @@ function ShellInner() {
|
||||
<ModalsContainer />
|
||||
<MutedWordsDialog />
|
||||
<SigninDialog />
|
||||
<BlockingAnnouncements />
|
||||
<EmailDialog />
|
||||
<AgeAssuranceRedirectDialog />
|
||||
<InAppBrowserConsentDialog />
|
||||
@@ -164,6 +163,7 @@ function ShellInner() {
|
||||
<Lightbox />
|
||||
<PortalOutlet />
|
||||
<BottomSheetOutlet />
|
||||
<BlockingAnnouncements />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -71,7 +71,6 @@ function ShellInner() {
|
||||
<ModalsContainer />
|
||||
<MutedWordsDialog />
|
||||
<SigninDialog />
|
||||
<BlockingAnnouncements />
|
||||
<EmailDialog />
|
||||
<AgeAssuranceRedirectDialog />
|
||||
<LinkWarningDialog />
|
||||
@@ -115,6 +114,8 @@ function ShellInner() {
|
||||
</TouchableWithoutFeedback>
|
||||
</>
|
||||
)}
|
||||
|
||||
<BlockingAnnouncements />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user