Dialog solution

This commit is contained in:
Eric Bailey
2024-02-08 13:15:14 -06:00
parent 15d0f2e90b
commit 4edbcd2b94
11 changed files with 154 additions and 105 deletions
+15 -19
View File
@@ -1,10 +1,11 @@
import React from 'react'
import {View} from 'react-native'
import * as Dialog from '#/components/Dialog'
import {Text} from '#/components/Typography'
import {Context} from '#/components/dialogs'
import * as Dialog from '#/components/Dialog'
import {GlobalDialogProps} from '#/components/dialogs'
export type DialogParams =
export type ReportDialogProps =
| {
type: 'post'
uri: string
@@ -15,25 +16,20 @@ export type DialogParams =
did: string
}
export function useReportDialogControl() {
return React.useContext(Context).report
}
export function ReportDialog(props: GlobalDialogProps<ReportDialogProps>) {
const control = Dialog.useDialogControl()
export function ReportDialog() {
const control = useReportDialogControl()
const onClose = React.useCallback(() => {
props.cleanup()
}, [props])
return (
<Dialog.Outer control={control}>
<Dialog.Handle />
<Dialog.ScrollableInner label="Report dialog">
<Inner />
</Dialog.ScrollableInner>
<Dialog.Outer defaultOpen control={control} onClose={onClose}>
<Dialog.Inner label="Report Dialog">
<View style={{height: 500}}>
<Text>hello {JSON.stringify(props)}</Text>
</View>
</Dialog.Inner>
</Dialog.Outer>
)
}
function Inner() {
const ctx = Dialog.useDialogContext<DialogParams>()
return <Text>hello {JSON.stringify(ctx.params)}</Text>
}
+77 -14
View File
@@ -2,31 +2,94 @@ import React from 'react'
import * as Dialog from '#/components/Dialog'
import {DialogParams as ReportDialogParams} from '#/components/dialogs/ReportDialog'
/**
* Type util for global dialog components. Wrap individual dialog component
* types with this to get types for the additional properties applied by the
* the global dialon controller.
*/
export type GlobalDialogProps<T = any> = {
params: T
cleanup(): void
options?: Dialog.DialogControlOpenOptions
}
type ActiveDialog<T extends React.ComponentType<GlobalDialogProps>> = {
component: T
props: React.ComponentProps<T>
options?: Dialog.DialogControlOpenOptions
}
type ContextProps = {
activeDialogs: ActiveDialog<any>[]
open<T extends React.ComponentType<GlobalDialogProps>>(
component: T,
props: React.ComponentProps<T>['params'],
options?: Dialog.DialogControlOpenOptions,
): void
popTopDialog(): void
}
export const Context = React.createContext<ContextProps>({
activeDialogs: [],
open() {},
popTopDialog() {},
})
/**
* Global dialog context. Name each dialog and specify its parameters.
* Hook to open a "global" dialog.
*
* @example
* ```tsx
* const openGlobalDialog = useOpenGlobalDialog()
* openGlobalDialog(
* MyDialog,
* // component props
* {foo: 'bar'},
* // base Dialog options
* { index: 1 }
* )
* ```
*/
type Context = {
report: Dialog.DialogControlWithRefProps<ReportDialogParams>
export function useOpenGlobalDialog() {
return React.useContext(Context).open
}
/**
* Global dialog context.
*/
export const Context = React.createContext<Context>({} as Context)
/**
* Global dialog context provider.
* Provider for "global" dialogs _only_. ALL dialogs are still registered by
* `#/state/dialogs` as well.
*/
export function Provider({children}: React.PropsWithChildren<{}>) {
const report = Dialog.useDialogControl<ReportDialogParams>()
const ctx = React.useMemo<Context>(
const [activeDialogs, setActiveDialogs] = React.useState<ActiveDialog<any>[]>(
[],
)
const ctx = React.useMemo<ContextProps>(
() => ({
report,
activeDialogs,
open(component, props, options) {
setActiveDialogs(s => [...s, {component, props, options}])
},
popTopDialog() {
setActiveDialogs(s => s.slice(0, -1))
},
}),
[report],
[activeDialogs, setActiveDialogs],
)
return <Context.Provider value={ctx}>{children}</Context.Provider>
}
/**
* Outlet for any active "global" dialogs. Since these are rendered into a
* portal in the root, this is technically not their final resting place.
*/
export function GlobalDialog() {
const {activeDialogs, popTopDialog} = React.useContext(Context)
const cleanup = React.useCallback(() => {
popTopDialog()
}, [popTopDialog])
return activeDialogs.map(({component: Comp, props, options}, i) => {
return <Comp key={i} {...props} cleanup={cleanup} options={options} />
})
}