Merge branch 'bluesky-social:main' into patch-3
This commit is contained in:
commit
200c4c1d37
8 changed files with 162 additions and 20 deletions
|
@ -3,7 +3,7 @@ import React from 'react'
|
||||||
import {useDialogStateContext} from '#/state/dialogs'
|
import {useDialogStateContext} from '#/state/dialogs'
|
||||||
import {
|
import {
|
||||||
DialogContextProps,
|
DialogContextProps,
|
||||||
DialogControlProps,
|
DialogControlRefProps,
|
||||||
DialogOuterProps,
|
DialogOuterProps,
|
||||||
} from '#/components/Dialog/types'
|
} from '#/components/Dialog/types'
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ export function useDialogContext() {
|
||||||
|
|
||||||
export function useDialogControl(): DialogOuterProps['control'] {
|
export function useDialogControl(): DialogOuterProps['control'] {
|
||||||
const id = React.useId()
|
const id = React.useId()
|
||||||
const control = React.useRef<DialogControlProps>({
|
const control = React.useRef<DialogControlRefProps>({
|
||||||
open: () => {},
|
open: () => {},
|
||||||
close: () => {},
|
close: () => {},
|
||||||
})
|
})
|
||||||
|
@ -32,8 +32,13 @@ export function useDialogControl(): DialogOuterProps['control'] {
|
||||||
}, [id, activeDialogs])
|
}, [id, activeDialogs])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
id,
|
||||||
ref: control,
|
ref: control,
|
||||||
open: () => control.current.open(),
|
open: () => {
|
||||||
close: cb => control.current.close(cb),
|
control.current.open()
|
||||||
|
},
|
||||||
|
close: cb => {
|
||||||
|
control.current.close(cb)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import {useTheme, atoms as a, flatten} from '#/alf'
|
||||||
import {Portal} from '#/components/Portal'
|
import {Portal} from '#/components/Portal'
|
||||||
import {createInput} from '#/components/forms/TextField'
|
import {createInput} from '#/components/forms/TextField'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
|
import {useDialogStateContext} from '#/state/dialogs'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DialogOuterProps,
|
DialogOuterProps,
|
||||||
|
@ -37,6 +38,7 @@ export function Outer({
|
||||||
const hasSnapPoints = !!sheetOptions.snapPoints
|
const hasSnapPoints = !!sheetOptions.snapPoints
|
||||||
const insets = useSafeAreaInsets()
|
const insets = useSafeAreaInsets()
|
||||||
const closeCallback = React.useRef<() => void>()
|
const closeCallback = React.useRef<() => void>()
|
||||||
|
const {openDialogs} = useDialogStateContext()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used to manage open/closed, but index is otherwise handled internally by `BottomSheet`
|
* Used to manage open/closed, but index is otherwise handled internally by `BottomSheet`
|
||||||
|
@ -50,10 +52,11 @@ export function Outer({
|
||||||
|
|
||||||
const open = React.useCallback<DialogControlProps['open']>(
|
const open = React.useCallback<DialogControlProps['open']>(
|
||||||
({index} = {}) => {
|
({index} = {}) => {
|
||||||
|
openDialogs.current.add(control.id)
|
||||||
// can be set to any index of `snapPoints`, but `0` is the first i.e. "open"
|
// can be set to any index of `snapPoints`, but `0` is the first i.e. "open"
|
||||||
setOpenIndex(index || 0)
|
setOpenIndex(index || 0)
|
||||||
},
|
},
|
||||||
[setOpenIndex],
|
[setOpenIndex, openDialogs, control.id],
|
||||||
)
|
)
|
||||||
|
|
||||||
const close = React.useCallback<DialogControlProps['close']>(cb => {
|
const close = React.useCallback<DialogControlProps['close']>(cb => {
|
||||||
|
@ -85,11 +88,12 @@ export function Outer({
|
||||||
closeCallback.current = undefined
|
closeCallback.current = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openDialogs.current.delete(control.id)
|
||||||
onClose?.()
|
onClose?.()
|
||||||
setOpenIndex(-1)
|
setOpenIndex(-1)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[onClose, setOpenIndex],
|
[onClose, setOpenIndex, openDialogs, control.id],
|
||||||
)
|
)
|
||||||
|
|
||||||
const context = React.useMemo(() => ({close}), [close])
|
const context = React.useMemo(() => ({close}), [close])
|
||||||
|
|
|
@ -12,6 +12,7 @@ import {DialogOuterProps, DialogInnerProps} from '#/components/Dialog/types'
|
||||||
import {Context} from '#/components/Dialog/context'
|
import {Context} from '#/components/Dialog/context'
|
||||||
import {Button, ButtonIcon} from '#/components/Button'
|
import {Button, ButtonIcon} from '#/components/Button'
|
||||||
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
||||||
|
import {useDialogStateContext} from '#/state/dialogs'
|
||||||
|
|
||||||
export {useDialogControl, useDialogContext} from '#/components/Dialog/context'
|
export {useDialogControl, useDialogContext} from '#/components/Dialog/context'
|
||||||
export * from '#/components/Dialog/types'
|
export * from '#/components/Dialog/types'
|
||||||
|
@ -29,18 +30,21 @@ export function Outer({
|
||||||
const {gtMobile} = useBreakpoints()
|
const {gtMobile} = useBreakpoints()
|
||||||
const [isOpen, setIsOpen] = React.useState(false)
|
const [isOpen, setIsOpen] = React.useState(false)
|
||||||
const [isVisible, setIsVisible] = React.useState(true)
|
const [isVisible, setIsVisible] = React.useState(true)
|
||||||
|
const {openDialogs} = useDialogStateContext()
|
||||||
|
|
||||||
const open = React.useCallback(() => {
|
const open = React.useCallback(() => {
|
||||||
setIsOpen(true)
|
setIsOpen(true)
|
||||||
}, [setIsOpen])
|
openDialogs.current.add(control.id)
|
||||||
|
}, [setIsOpen, openDialogs, control.id])
|
||||||
|
|
||||||
const close = React.useCallback(async () => {
|
const close = React.useCallback(async () => {
|
||||||
setIsVisible(false)
|
setIsVisible(false)
|
||||||
await new Promise(resolve => setTimeout(resolve, 150))
|
await new Promise(resolve => setTimeout(resolve, 150))
|
||||||
setIsOpen(false)
|
setIsOpen(false)
|
||||||
setIsVisible(true)
|
setIsVisible(true)
|
||||||
|
openDialogs.current.delete(control.id)
|
||||||
onClose?.()
|
onClose?.()
|
||||||
}, [onClose, setIsOpen])
|
}, [onClose, setIsOpen, openDialogs, control.id])
|
||||||
|
|
||||||
useImperativeHandle(
|
useImperativeHandle(
|
||||||
control.ref,
|
control.ref,
|
||||||
|
|
|
@ -6,11 +6,24 @@ import {ViewStyleProp} from '#/alf'
|
||||||
|
|
||||||
type A11yProps = Required<AccessibilityProps>
|
type A11yProps = Required<AccessibilityProps>
|
||||||
|
|
||||||
export type DialogControlProps = {
|
/**
|
||||||
|
* Mutated by useImperativeHandle to provide a public API for controlling the
|
||||||
|
* dialog. The methods here will actually become the handlers defined within
|
||||||
|
* the `Dialog.Outer` component.
|
||||||
|
*/
|
||||||
|
export type DialogControlRefProps = {
|
||||||
open: (options?: DialogControlOpenOptions) => void
|
open: (options?: DialogControlOpenOptions) => void
|
||||||
close: (callback?: () => void) => void
|
close: (callback?: () => void) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The return type of the useDialogControl hook.
|
||||||
|
*/
|
||||||
|
export type DialogControlProps = DialogControlRefProps & {
|
||||||
|
id: string
|
||||||
|
ref: React.RefObject<DialogControlRefProps>
|
||||||
|
}
|
||||||
|
|
||||||
export type DialogContextProps = {
|
export type DialogContextProps = {
|
||||||
close: DialogControlProps['close']
|
close: DialogControlProps['close']
|
||||||
}
|
}
|
||||||
|
@ -26,9 +39,7 @@ export type DialogControlOpenOptions = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DialogOuterProps = {
|
export type DialogOuterProps = {
|
||||||
control: {
|
control: DialogControlProps
|
||||||
ref: React.RefObject<DialogControlProps>
|
|
||||||
} & DialogControlProps
|
|
||||||
onClose?: () => void
|
onClose?: () => void
|
||||||
nativeOptions?: {
|
nativeOptions?: {
|
||||||
sheet?: Omit<BottomSheetProps, 'children'>
|
sheet?: Omit<BottomSheetProps, 'children'>
|
||||||
|
|
|
@ -16,6 +16,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: ['outlineTag'],
|
outlineTags: ['outlineTag'],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -32,6 +33,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: ['outlineTag'],
|
outlineTags: ['outlineTag'],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -48,6 +50,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: ['outlineTag'],
|
outlineTags: ['outlineTag'],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -64,6 +67,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(false)
|
expect(match).toBe(false)
|
||||||
|
@ -85,6 +89,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -101,6 +106,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(false)
|
expect(match).toBe(false)
|
||||||
|
@ -117,6 +123,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -135,6 +142,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -151,6 +159,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(false)
|
expect(match).toBe(false)
|
||||||
|
@ -167,6 +176,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -183,6 +193,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -202,6 +213,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -213,6 +225,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -231,6 +244,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -243,6 +257,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -261,6 +276,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -272,6 +288,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -291,6 +308,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -309,6 +327,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -320,6 +339,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -336,6 +356,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(false)
|
expect(match).toBe(false)
|
||||||
|
@ -354,6 +375,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -365,6 +387,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -383,6 +406,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -394,6 +418,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -405,6 +430,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -416,6 +442,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(false)
|
expect(match).toBe(false)
|
||||||
|
@ -434,6 +461,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -448,6 +476,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(false)
|
expect(match).toBe(false)
|
||||||
|
@ -460,6 +489,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -471,6 +501,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(false)
|
expect(match).toBe(false)
|
||||||
|
@ -489,6 +520,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -500,6 +532,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -511,6 +544,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -522,6 +556,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -540,6 +575,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -560,6 +596,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -571,6 +608,7 @@ describe(`hasMutedWord`, () => {
|
||||||
text: rt.text,
|
text: rt.text,
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
|
@ -594,10 +632,61 @@ describe(`hasMutedWord`, () => {
|
||||||
facets: rt.facets,
|
facets: rt.facets,
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
languages: ['ja'],
|
languages: ['ja'],
|
||||||
|
isOwnPost: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(match).toBe(true)
|
expect(match).toBe(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe(`doesn't mute own post`, () => {
|
||||||
|
it(`does mute if it isn't own post`, () => {
|
||||||
|
const rt = new RichText({
|
||||||
|
text: `Mute words!`,
|
||||||
|
})
|
||||||
|
|
||||||
|
const match = hasMutedWord({
|
||||||
|
mutedWords: [{value: 'words', targets: ['content']}],
|
||||||
|
text: rt.text,
|
||||||
|
facets: rt.facets,
|
||||||
|
outlineTags: [],
|
||||||
|
isOwnPost: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(match).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`doesn't mute own post when muted word is in text`, () => {
|
||||||
|
const rt = new RichText({
|
||||||
|
text: `Mute words!`,
|
||||||
|
})
|
||||||
|
|
||||||
|
const match = hasMutedWord({
|
||||||
|
mutedWords: [{value: 'words', targets: ['content']}],
|
||||||
|
text: rt.text,
|
||||||
|
facets: rt.facets,
|
||||||
|
outlineTags: [],
|
||||||
|
isOwnPost: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(match).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`doesn't mute own post when muted word is in tags`, () => {
|
||||||
|
const rt = new RichText({
|
||||||
|
text: `Mute #words!`,
|
||||||
|
})
|
||||||
|
|
||||||
|
const match = hasMutedWord({
|
||||||
|
mutedWords: [{value: 'words', targets: ['tags']}],
|
||||||
|
text: rt.text,
|
||||||
|
facets: rt.facets,
|
||||||
|
outlineTags: [],
|
||||||
|
isOwnPost: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(match).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -41,13 +41,17 @@ export function hasMutedWord({
|
||||||
facets,
|
facets,
|
||||||
outlineTags,
|
outlineTags,
|
||||||
languages,
|
languages,
|
||||||
|
isOwnPost,
|
||||||
}: {
|
}: {
|
||||||
mutedWords: AppBskyActorDefs.MutedWord[]
|
mutedWords: AppBskyActorDefs.MutedWord[]
|
||||||
text: string
|
text: string
|
||||||
facets?: AppBskyRichtextFacet.Main[]
|
facets?: AppBskyRichtextFacet.Main[]
|
||||||
outlineTags?: string[]
|
outlineTags?: string[]
|
||||||
languages?: string[]
|
languages?: string[]
|
||||||
|
isOwnPost: boolean
|
||||||
}) {
|
}) {
|
||||||
|
if (isOwnPost) return false
|
||||||
|
|
||||||
const exception = LANGUAGE_EXCEPTIONS.includes(languages?.[0] || '')
|
const exception = LANGUAGE_EXCEPTIONS.includes(languages?.[0] || '')
|
||||||
const tags = ([] as string[])
|
const tags = ([] as string[])
|
||||||
.concat(outlineTags || [])
|
.concat(outlineTags || [])
|
||||||
|
@ -142,6 +146,7 @@ export function moderatePost_wrapped(
|
||||||
) {
|
) {
|
||||||
const {hiddenPosts = [], mutedWords = [], ...options} = opts
|
const {hiddenPosts = [], mutedWords = [], ...options} = opts
|
||||||
const moderations = moderatePost(subject, options)
|
const moderations = moderatePost(subject, options)
|
||||||
|
const isOwnPost = subject.author.did === opts.userDid
|
||||||
|
|
||||||
if (hiddenPosts.includes(subject.uri)) {
|
if (hiddenPosts.includes(subject.uri)) {
|
||||||
moderations.content.filter = true
|
moderations.content.filter = true
|
||||||
|
@ -163,6 +168,7 @@ export function moderatePost_wrapped(
|
||||||
facets: subject.record.facets || [],
|
facets: subject.record.facets || [],
|
||||||
outlineTags: subject.record.tags || [],
|
outlineTags: subject.record.tags || [],
|
||||||
languages: subject.record.langs,
|
languages: subject.record.langs,
|
||||||
|
isOwnPost,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -178,6 +184,7 @@ export function moderatePost_wrapped(
|
||||||
facets: [],
|
facets: [],
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
languages: subject.record.langs,
|
languages: subject.record.langs,
|
||||||
|
isOwnPost,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,6 +217,7 @@ export function moderatePost_wrapped(
|
||||||
facets: subject.embed.record.value.facets,
|
facets: subject.embed.record.value.facets,
|
||||||
outlineTags: subject.embed.record.value.tags,
|
outlineTags: subject.embed.record.value.tags,
|
||||||
languages: subject.embed.record.value.langs,
|
languages: subject.embed.record.value.langs,
|
||||||
|
isOwnPost,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (AppBskyEmbedImages.isMain(subject.embed.record.value.embed)) {
|
if (AppBskyEmbedImages.isMain(subject.embed.record.value.embed)) {
|
||||||
|
@ -222,6 +230,7 @@ export function moderatePost_wrapped(
|
||||||
facets: [],
|
facets: [],
|
||||||
outlineTags: [],
|
outlineTags: [],
|
||||||
languages: subject.embed.record.value.langs,
|
languages: subject.embed.record.value.langs,
|
||||||
|
isOwnPost,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,32 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {DialogControlProps} from '#/components/Dialog'
|
import {DialogControlRefProps} from '#/components/Dialog'
|
||||||
import {Provider as GlobalDialogsProvider} from '#/components/dialogs/Context'
|
import {Provider as GlobalDialogsProvider} from '#/components/dialogs/Context'
|
||||||
|
|
||||||
const DialogContext = React.createContext<{
|
const DialogContext = React.createContext<{
|
||||||
|
/**
|
||||||
|
* The currently active `useDialogControl` hooks.
|
||||||
|
*/
|
||||||
activeDialogs: React.MutableRefObject<
|
activeDialogs: React.MutableRefObject<
|
||||||
Map<string, React.MutableRefObject<DialogControlProps>>
|
Map<string, React.MutableRefObject<DialogControlRefProps>>
|
||||||
>
|
>
|
||||||
|
/**
|
||||||
|
* The currently open dialogs, referenced by their IDs, generated from
|
||||||
|
* `useId`.
|
||||||
|
*/
|
||||||
|
openDialogs: React.MutableRefObject<Set<string>>
|
||||||
}>({
|
}>({
|
||||||
activeDialogs: {
|
activeDialogs: {
|
||||||
current: new Map(),
|
current: new Map(),
|
||||||
},
|
},
|
||||||
|
openDialogs: {
|
||||||
|
current: new Set(),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const DialogControlContext = React.createContext<{
|
const DialogControlContext = React.createContext<{
|
||||||
closeAllDialogs(): void
|
closeAllDialogs(): boolean
|
||||||
}>({
|
}>({
|
||||||
closeAllDialogs: () => {},
|
closeAllDialogs: () => false,
|
||||||
})
|
})
|
||||||
|
|
||||||
export function useDialogStateContext() {
|
export function useDialogStateContext() {
|
||||||
|
@ -28,13 +39,18 @@ export function useDialogStateControlContext() {
|
||||||
|
|
||||||
export function Provider({children}: React.PropsWithChildren<{}>) {
|
export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||||
const activeDialogs = React.useRef<
|
const activeDialogs = React.useRef<
|
||||||
Map<string, React.MutableRefObject<DialogControlProps>>
|
Map<string, React.MutableRefObject<DialogControlRefProps>>
|
||||||
>(new Map())
|
>(new Map())
|
||||||
|
const openDialogs = React.useRef<Set<string>>(new Set())
|
||||||
|
|
||||||
const closeAllDialogs = React.useCallback(() => {
|
const closeAllDialogs = React.useCallback(() => {
|
||||||
activeDialogs.current.forEach(dialog => dialog.current.close())
|
activeDialogs.current.forEach(dialog => dialog.current.close())
|
||||||
|
return openDialogs.current.size > 0
|
||||||
}, [])
|
}, [])
|
||||||
const context = React.useMemo(() => ({activeDialogs}), [])
|
|
||||||
|
const context = React.useMemo(() => ({activeDialogs, openDialogs}), [])
|
||||||
const controls = React.useMemo(() => ({closeAllDialogs}), [closeAllDialogs])
|
const controls = React.useMemo(() => ({closeAllDialogs}), [closeAllDialogs])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DialogContext.Provider value={context}>
|
<DialogContext.Provider value={context}>
|
||||||
<DialogControlContext.Provider value={controls}>
|
<DialogControlContext.Provider value={controls}>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {useLightboxControls} from './lightbox'
|
||||||
import {useModalControls} from './modals'
|
import {useModalControls} from './modals'
|
||||||
import {useComposerControls} from './shell/composer'
|
import {useComposerControls} from './shell/composer'
|
||||||
import {useSetDrawerOpen} from './shell/drawer-open'
|
import {useSetDrawerOpen} from './shell/drawer-open'
|
||||||
import {useDialogStateControlContext} from 'state/dialogs'
|
import {useDialogStateControlContext} from '#/state/dialogs'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns true if something was closed
|
* returns true if something was closed
|
||||||
|
@ -13,6 +13,7 @@ export function useCloseAnyActiveElement() {
|
||||||
const {closeLightbox} = useLightboxControls()
|
const {closeLightbox} = useLightboxControls()
|
||||||
const {closeModal} = useModalControls()
|
const {closeModal} = useModalControls()
|
||||||
const {closeComposer} = useComposerControls()
|
const {closeComposer} = useComposerControls()
|
||||||
|
const {closeAllDialogs} = useDialogStateControlContext()
|
||||||
const setDrawerOpen = useSetDrawerOpen()
|
const setDrawerOpen = useSetDrawerOpen()
|
||||||
return useCallback(() => {
|
return useCallback(() => {
|
||||||
if (closeLightbox()) {
|
if (closeLightbox()) {
|
||||||
|
@ -24,9 +25,12 @@ export function useCloseAnyActiveElement() {
|
||||||
if (closeComposer()) {
|
if (closeComposer()) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if (closeAllDialogs()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
setDrawerOpen(false)
|
setDrawerOpen(false)
|
||||||
return false
|
return false
|
||||||
}, [closeLightbox, closeModal, closeComposer, setDrawerOpen])
|
}, [closeLightbox, closeModal, closeComposer, setDrawerOpen, closeAllDialogs])
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue