diff --git a/bskyweb/templates/base.html b/bskyweb/templates/base.html
index 413d7ff691..55447552ea 100644
--- a/bskyweb/templates/base.html
+++ b/bskyweb/templates/base.html
@@ -213,6 +213,7 @@
}
/* NativeDropdown component */
+ .radix-dropdown-item:focus,
.nativeDropdown-item:focus {
outline: none;
}
diff --git a/package.json b/package.json
index d694d26c31..cd8cc76519 100644
--- a/package.json
+++ b/package.json
@@ -58,6 +58,7 @@
"@lingui/react": "^4.5.0",
"@mattermost/react-native-paste-input": "^0.6.4",
"@miblanchard/react-native-slider": "^2.3.1",
+ "@radix-ui/react-dropdown-menu": "^2.0.6",
"@react-native-async-storage/async-storage": "1.21.0",
"@react-native-camera-roll/camera-roll": "^5.2.2",
"@react-native-clipboard/clipboard": "^1.10.0",
@@ -148,6 +149,7 @@
"react-avatar-editor": "^13.0.0",
"react-circular-progressbar": "^2.1.0",
"react-dom": "^18.2.0",
+ "react-keyed-flatten-children": "^3.0.0",
"react-native": "0.73.2",
"react-native-appstate-hook": "^1.0.6",
"react-native-drawer-layout": "^4.0.0-alpha.3",
diff --git a/src/components/Dialog/context.ts b/src/components/Dialog/context.ts
index eb717d8e2b..9b571e8e9c 100644
--- a/src/components/Dialog/context.ts
+++ b/src/components/Dialog/context.ts
@@ -21,7 +21,8 @@ export function useDialogControl(): DialogOuterProps['control'] {
open: () => {},
close: () => {},
})
- const {activeDialogs} = useDialogStateContext()
+ const {activeDialogs, openDialogs} = useDialogStateContext()
+ const isOpen = openDialogs.includes(id)
React.useEffect(() => {
activeDialogs.current.set(id, control)
@@ -31,14 +32,18 @@ export function useDialogControl(): DialogOuterProps['control'] {
}
}, [id, activeDialogs])
- return {
- id,
- ref: control,
- open: () => {
- control.current.open()
- },
- close: cb => {
- control.current.close(cb)
- },
- }
+ return React.useMemo(
+ () => ({
+ id,
+ ref: control,
+ isOpen,
+ open: () => {
+ control.current.open()
+ },
+ close: cb => {
+ control.current.close(cb)
+ },
+ }),
+ [id, control, isOpen],
+ )
}
diff --git a/src/components/Dialog/types.ts b/src/components/Dialog/types.ts
index 78dfedf5a8..fa9398fe05 100644
--- a/src/components/Dialog/types.ts
+++ b/src/components/Dialog/types.ts
@@ -22,6 +22,7 @@ export type DialogControlRefProps = {
export type DialogControlProps = DialogControlRefProps & {
id: string
ref: React.RefObject
+ isOpen: boolean
}
export type DialogContextProps = {
diff --git a/src/components/Menu/context.tsx b/src/components/Menu/context.tsx
new file mode 100644
index 0000000000..9fc91f6815
--- /dev/null
+++ b/src/components/Menu/context.tsx
@@ -0,0 +1,8 @@
+import React from 'react'
+
+import type {ContextType} from '#/components/Menu/types'
+
+export const Context = React.createContext({
+ // @ts-ignore
+ control: null,
+})
diff --git a/src/components/Menu/index.tsx b/src/components/Menu/index.tsx
new file mode 100644
index 0000000000..ee96a5667e
--- /dev/null
+++ b/src/components/Menu/index.tsx
@@ -0,0 +1,190 @@
+import React from 'react'
+import {View, Pressable} from 'react-native'
+import flattenReactChildren from 'react-keyed-flatten-children'
+
+import {atoms as a, useTheme} from '#/alf'
+import * as Dialog from '#/components/Dialog'
+import {useInteractionState} from '#/components/hooks/useInteractionState'
+import {Text} from '#/components/Typography'
+
+import {Context} from '#/components/Menu/context'
+import {
+ ContextType,
+ TriggerProps,
+ ItemProps,
+ GroupProps,
+ ItemTextProps,
+ ItemIconProps,
+} from '#/components/Menu/types'
+
+export {useDialogControl as useMenuControl} from '#/components/Dialog'
+
+export function useMemoControlContext() {
+ return React.useContext(Context)
+}
+
+export function Root({
+ children,
+ control,
+}: React.PropsWithChildren<{
+ control?: Dialog.DialogOuterProps['control']
+}>) {
+ const defaultControl = Dialog.useDialogControl()
+ const context = React.useMemo(
+ () => ({
+ control: control || defaultControl,
+ }),
+ [control, defaultControl],
+ )
+
+ return {children}
+}
+
+export function Trigger({children, label}: TriggerProps) {
+ const {control} = React.useContext(Context)
+ const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
+ const {
+ state: pressed,
+ onIn: onPressIn,
+ onOut: onPressOut,
+ } = useInteractionState()
+
+ return children({
+ isNative: true,
+ control,
+ state: {
+ hovered: false,
+ focused,
+ pressed,
+ },
+ props: {
+ onPress: control.open,
+ onFocus,
+ onBlur,
+ onPressIn,
+ onPressOut,
+ accessibilityLabel: label,
+ },
+ })
+}
+
+export function Outer({children}: React.PropsWithChildren<{}>) {
+ const context = React.useContext(Context)
+
+ return (
+
+
+
+ {/* Re-wrap with context since Dialogs are portal-ed to root */}
+
+
+ {children}
+
+
+
+
+ )
+}
+
+export function Item({children, label, style, onPress, ...rest}: ItemProps) {
+ const t = useTheme()
+ const {control} = React.useContext(Context)
+ const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
+ const {
+ state: pressed,
+ onIn: onPressIn,
+ onOut: onPressOut,
+ } = useInteractionState()
+
+ return (
+ {
+ onPress(e)
+
+ if (!e.defaultPrevented) {
+ control?.close()
+ }
+ }}
+ onFocus={onFocus}
+ onBlur={onBlur}
+ onPressIn={onPressIn}
+ onPressOut={onPressOut}
+ style={[
+ a.flex_row,
+ a.align_center,
+ a.gap_sm,
+ a.px_md,
+ a.rounded_md,
+ a.border,
+ t.atoms.bg_contrast_25,
+ t.atoms.border_contrast_low,
+ {minHeight: 44, paddingVertical: 10},
+ style,
+ (focused || pressed) && [t.atoms.bg_contrast_50],
+ ]}>
+ {children}
+
+ )
+}
+
+export function ItemText({children, style}: ItemTextProps) {
+ const t = useTheme()
+ return (
+
+ {children}
+
+ )
+}
+
+export function ItemIcon({icon: Comp}: ItemIconProps) {
+ const t = useTheme()
+ return
+}
+
+export function Group({children, style}: GroupProps) {
+ const t = useTheme()
+ return (
+
+ {flattenReactChildren(children).map((child, i) => {
+ return React.isValidElement(child) && child.type === Item ? (
+
+ {i > 0 ? (
+
+ ) : null}
+ {React.cloneElement(child, {
+ // @ts-ignore
+ style: {
+ borderRadius: 0,
+ borderWidth: 0,
+ },
+ })}
+
+ ) : null
+ })}
+
+ )
+}
+
+export function Divider() {
+ return null
+}
diff --git a/src/components/Menu/index.web.tsx b/src/components/Menu/index.web.tsx
new file mode 100644
index 0000000000..ca2e40566d
--- /dev/null
+++ b/src/components/Menu/index.web.tsx
@@ -0,0 +1,247 @@
+import React from 'react'
+import {View, Pressable} from 'react-native'
+import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
+
+import * as Dialog from '#/components/Dialog'
+import {useInteractionState} from '#/components/hooks/useInteractionState'
+import {atoms as a, useTheme, flatten, web} from '#/alf'
+import {Text} from '#/components/Typography'
+
+import {
+ ContextType,
+ TriggerProps,
+ ItemProps,
+ GroupProps,
+ ItemTextProps,
+ ItemIconProps,
+} from '#/components/Menu/types'
+import {Context} from '#/components/Menu/context'
+
+export function useMenuControl(): Dialog.DialogControlProps {
+ const id = React.useId()
+ const [isOpen, setIsOpen] = React.useState(false)
+
+ return React.useMemo(
+ () => ({
+ id,
+ ref: {current: null},
+ isOpen,
+ open() {
+ setIsOpen(true)
+ },
+ close() {
+ setIsOpen(false)
+ },
+ }),
+ [id, isOpen, setIsOpen],
+ )
+}
+
+export function useMemoControlContext() {
+ return React.useContext(Context)
+}
+
+export function Root({
+ children,
+ control,
+}: React.PropsWithChildren<{
+ control?: Dialog.DialogOuterProps['control']
+}>) {
+ const defaultControl = useMenuControl()
+ const context = React.useMemo(
+ () => ({
+ control: control || defaultControl,
+ }),
+ [control, defaultControl],
+ )
+ const onOpenChange = React.useCallback(
+ (open: boolean) => {
+ if (context.control.isOpen && !open) {
+ context.control.close()
+ } else if (!context.control.isOpen && open) {
+ context.control.open()
+ }
+ },
+ [context.control],
+ )
+
+ return (
+
+
+ {children}
+
+
+ )
+}
+
+export function Trigger({children, label, style}: TriggerProps) {
+ const {control} = React.useContext(Context)
+ const {
+ state: hovered,
+ onIn: onMouseEnter,
+ onOut: onMouseLeave,
+ } = useInteractionState()
+ const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
+
+ return (
+
+ {
+ control.open()
+ }}
+ {...web({
+ onMouseEnter,
+ onMouseLeave,
+ })}>
+ {children({
+ isNative: false,
+ control,
+ state: {
+ hovered,
+ focused,
+ pressed: false,
+ },
+ props: {},
+ })}
+
+
+ )
+}
+
+export function Outer({children}: React.PropsWithChildren<{}>) {
+ const t = useTheme()
+
+ return (
+
+
+
+ {children}
+
+
+
+
+
+ )
+}
+
+export function Item({children, label, onPress, ...rest}: ItemProps) {
+ const t = useTheme()
+ const {control} = React.useContext(Context)
+ const {
+ state: hovered,
+ onIn: onMouseEnter,
+ onOut: onMouseLeave,
+ } = useInteractionState()
+ const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
+
+ return (
+
+ {
+ onPress(e)
+
+ /**
+ * Ported forward from Radix
+ * @see https://www.radix-ui.com/primitives/docs/components/dropdown-menu#item
+ */
+ if (!e.defaultPrevented) {
+ control.close()
+ }
+ }}
+ onFocus={onFocus}
+ onBlur={onBlur}
+ // need `flatten` here for Radix compat
+ style={flatten([
+ a.flex_row,
+ a.align_center,
+ a.gap_sm,
+ a.py_sm,
+ a.rounded_xs,
+ {minHeight: 32, paddingHorizontal: 10},
+ web({outline: 0}),
+ (hovered || focused) && [
+ web({outline: '0 !important'}),
+ t.name === 'light'
+ ? t.atoms.bg_contrast_25
+ : t.atoms.bg_contrast_50,
+ ],
+ ])}
+ {...web({
+ onMouseEnter,
+ onMouseLeave,
+ })}>
+ {children}
+
+
+ )
+}
+
+export function ItemText({children, style}: ItemTextProps) {
+ const t = useTheme()
+ return (
+
+ {children}
+
+ )
+}
+
+export function ItemIcon({icon: Comp, position = 'left'}: ItemIconProps) {
+ const t = useTheme()
+ return (
+
+ )
+}
+
+export function Group({children}: GroupProps) {
+ return children
+}
+
+export function Divider() {
+ const t = useTheme()
+ return (
+
+ )
+}
diff --git a/src/components/Menu/types.ts b/src/components/Menu/types.ts
new file mode 100644
index 0000000000..2f52e63906
--- /dev/null
+++ b/src/components/Menu/types.ts
@@ -0,0 +1,72 @@
+import React from 'react'
+import {GestureResponderEvent, PressableProps} from 'react-native'
+
+import {Props as SVGIconProps} from '#/components/icons/common'
+import * as Dialog from '#/components/Dialog'
+import {TextStyleProp, ViewStyleProp} from '#/alf'
+
+export type ContextType = {
+ control: Dialog.DialogOuterProps['control']
+}
+
+export type TriggerProps = ViewStyleProp & {
+ children(props: TriggerChildProps): React.ReactNode
+ label: string
+}
+export type TriggerChildProps =
+ | {
+ isNative: true
+ control: Dialog.DialogOuterProps['control']
+ state: {
+ /**
+ * Web only, `false` on native
+ */
+ hovered: false
+ focused: boolean
+ pressed: boolean
+ }
+ /**
+ * We don't necessarily know what these will be spread on to, so we
+ * should add props one-by-one.
+ *
+ * On web, these properties are applied to a parent `Pressable`, so this
+ * object is empty.
+ */
+ props: {
+ onPress: () => void
+ onFocus: () => void
+ onBlur: () => void
+ onPressIn: () => void
+ onPressOut: () => void
+ accessibilityLabel: string
+ }
+ }
+ | {
+ isNative: false
+ control: Dialog.DialogOuterProps['control']
+ state: {
+ hovered: boolean
+ focused: boolean
+ /**
+ * Native only, `false` on web
+ */
+ pressed: false
+ }
+ props: {}
+ }
+
+export type ItemProps = React.PropsWithChildren<
+ Omit &
+ ViewStyleProp & {
+ label: string
+ onPress: (e: GestureResponderEvent) => void
+ }
+>
+
+export type ItemTextProps = React.PropsWithChildren
+export type ItemIconProps = React.PropsWithChildren<{
+ icon: React.ComponentType
+ position?: 'left' | 'right'
+}>
+
+export type GroupProps = React.PropsWithChildren
diff --git a/src/view/screens/Storybook/Menus.tsx b/src/view/screens/Storybook/Menus.tsx
new file mode 100644
index 0000000000..082fb2b6e1
--- /dev/null
+++ b/src/view/screens/Storybook/Menus.tsx
@@ -0,0 +1,79 @@
+import React from 'react'
+import {View} from 'react-native'
+
+import {atoms as a, useTheme} from '#/alf'
+import {Text} from '#/components/Typography'
+import * as Menu from '#/components/Menu'
+import {MagnifyingGlass2_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass2'
+// import {useDialogStateControlContext} from '#/state/dialogs'
+
+export function Menus() {
+ const t = useTheme()
+ const menuControl = Menu.useMenuControl()
+ // const {closeAllDialogs} = useDialogStateControlContext()
+
+ return (
+
+
+
+
+ {({state, props}) => {
+ return (
+
+ Open
+
+ )
+ }}
+
+
+
+
+ {}}>
+
+ Click me
+
+
+ menuControl.close()}>
+ Another item
+
+
+
+
+
+
+ {}}>
+
+ Click me
+
+
+ menuControl.close()}>
+ Another item
+
+
+
+
+
+ {}}>
+
+ Click me
+
+
+
+
+
+ )
+}
diff --git a/src/view/screens/Storybook/index.tsx b/src/view/screens/Storybook/index.tsx
index 40929555e5..e43d756de5 100644
--- a/src/view/screens/Storybook/index.tsx
+++ b/src/view/screens/Storybook/index.tsx
@@ -16,6 +16,7 @@ import {Dialogs} from './Dialogs'
import {Breakpoints} from './Breakpoints'
import {Shadows} from './Shadows'
import {Icons} from './Icons'
+import {Menus} from './Menus'
export function Storybook() {
const t = useTheme()
@@ -84,6 +85,7 @@ export function Storybook() {
+
diff --git a/web/index.html b/web/index.html
index 8f2275a7f4..b6e01ba4c2 100644
--- a/web/index.html
+++ b/web/index.html
@@ -217,6 +217,7 @@
}
/* NativeDropdown component */
+ .radix-dropdown-item:focus,
.nativeDropdown-item:focus {
outline: none;
}
diff --git a/yarn.lock b/yarn.lock
index ceb712ce27..c3ddb8ee04 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4467,6 +4467,18 @@
"@radix-ui/react-use-callback-ref" "1.0.1"
"@radix-ui/react-use-escape-keydown" "1.0.3"
+"@radix-ui/react-dismissable-layer@1.0.5":
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz#3f98425b82b9068dfbab5db5fff3df6ebf48b9d4"
+ integrity sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/primitive" "1.0.1"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-use-callback-ref" "1.0.1"
+ "@radix-ui/react-use-escape-keydown" "1.0.3"
+
"@radix-ui/react-dropdown-menu@^2.0.1":
version "2.0.5"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.0.5.tgz#19bf4de8ffa348b4eb6a86842f14eff93d741170"
@@ -4481,6 +4493,20 @@
"@radix-ui/react-primitive" "1.0.3"
"@radix-ui/react-use-controllable-state" "1.0.1"
+"@radix-ui/react-dropdown-menu@^2.0.6":
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.0.6.tgz#cdf13c956c5e263afe4e5f3587b3071a25755b63"
+ integrity sha512-i6TuFOoWmLWq+M/eCLGd/bQ2HfAX1RJgvrBQ6AQLmzfvsLdefxbWu8G9zczcPFfcSPehz9GcpF6K9QYreFV8hA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/primitive" "1.0.1"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-id" "1.0.1"
+ "@radix-ui/react-menu" "2.0.6"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-use-controllable-state" "1.0.1"
+
"@radix-ui/react-focus-guards@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz#1ea7e32092216b946397866199d892f71f7f98ad"
@@ -4498,6 +4524,16 @@
"@radix-ui/react-primitive" "1.0.3"
"@radix-ui/react-use-callback-ref" "1.0.1"
+"@radix-ui/react-focus-scope@1.0.4":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz#2ac45fce8c5bb33eb18419cdc1905ef4f1906525"
+ integrity sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-use-callback-ref" "1.0.1"
+
"@radix-ui/react-id@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.0.1.tgz#73cdc181f650e4df24f0b6a5b7aa426b912c88c0"
@@ -4531,6 +4567,31 @@
aria-hidden "^1.1.1"
react-remove-scroll "2.5.5"
+"@radix-ui/react-menu@2.0.6":
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-2.0.6.tgz#2c9e093c1a5d5daa87304b2a2f884e32288ae79e"
+ integrity sha512-BVkFLS+bUC8HcImkRKPSiVumA1VPOOEC5WBMiT+QAVsPzW1FJzI9KnqgGxVDPBcql5xXrHkD3JOVoXWEXD8SYA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/primitive" "1.0.1"
+ "@radix-ui/react-collection" "1.0.3"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-direction" "1.0.1"
+ "@radix-ui/react-dismissable-layer" "1.0.5"
+ "@radix-ui/react-focus-guards" "1.0.1"
+ "@radix-ui/react-focus-scope" "1.0.4"
+ "@radix-ui/react-id" "1.0.1"
+ "@radix-ui/react-popper" "1.1.3"
+ "@radix-ui/react-portal" "1.0.4"
+ "@radix-ui/react-presence" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-roving-focus" "1.0.4"
+ "@radix-ui/react-slot" "1.0.2"
+ "@radix-ui/react-use-callback-ref" "1.0.1"
+ aria-hidden "^1.1.1"
+ react-remove-scroll "2.5.5"
+
"@radix-ui/react-popper@1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.1.2.tgz#4c0b96fcd188dc1f334e02dba2d538973ad842e9"
@@ -4548,6 +4609,23 @@
"@radix-ui/react-use-size" "1.0.1"
"@radix-ui/rect" "1.0.1"
+"@radix-ui/react-popper@1.1.3":
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.1.3.tgz#24c03f527e7ac348fabf18c89795d85d21b00b42"
+ integrity sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@floating-ui/react-dom" "^2.0.0"
+ "@radix-ui/react-arrow" "1.0.3"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-use-callback-ref" "1.0.1"
+ "@radix-ui/react-use-layout-effect" "1.0.1"
+ "@radix-ui/react-use-rect" "1.0.1"
+ "@radix-ui/react-use-size" "1.0.1"
+ "@radix-ui/rect" "1.0.1"
+
"@radix-ui/react-portal@1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.3.tgz#ffb961244c8ed1b46f039e6c215a6c4d9989bda1"
@@ -4556,6 +4634,14 @@
"@babel/runtime" "^7.13.10"
"@radix-ui/react-primitive" "1.0.3"
+"@radix-ui/react-portal@1.0.4":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.4.tgz#df4bfd353db3b1e84e639e9c63a5f2565fb00e15"
+ integrity sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-primitive" "1.0.3"
+
"@radix-ui/react-presence@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.0.1.tgz#491990ba913b8e2a5db1b06b203cb24b5cdef9ba"
@@ -18372,6 +18458,13 @@ react-is@^17.0.1:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
+react-keyed-flatten-children@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/react-keyed-flatten-children/-/react-keyed-flatten-children-3.0.0.tgz#b6ad0bde437d3ab86c8af3a1902d164be2a29d67"
+ integrity sha512-tSH6gvOyQjt3qtjG+kU9sTypclL1672yjpVufcE3aHNM0FhvjBUQZqsb/awIux4zEuVC3k/DP4p0GdTT/QUt/Q==
+ dependencies:
+ react-is "^18.2.0"
+
react-native-appstate-hook@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/react-native-appstate-hook/-/react-native-appstate-hook-1.0.6.tgz#cbc16e7b89cfaea034cabd999f00e99053cabd06"