Dialog solution
This commit is contained in:
@@ -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>
|
||||
}
|
||||
|
||||
@@ -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} />
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user