Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add `Menu` component (#3097)

* Add POC menu abstraction

* Better platform handling

* Remove ignore

* Add some menu items

* Add controlled dropdown

* Pass through a11y props

* Ignore uninitialized context

* Tweaks

* Usability improvements

* Rename handlers to props

* Add radix comment

* Ignore known type

* Remove todo

* Move storybook item

* Improve Group matching

* Adjust theming

authored by

Eric Bailey and committed by
GitHub
317e0cda e721f84a

+712 -11
+1
bskyweb/templates/base.html
··· 213 213 } 214 214 215 215 /* NativeDropdown component */ 216 + .radix-dropdown-item:focus, 216 217 .nativeDropdown-item:focus { 217 218 outline: none; 218 219 }
+2
package.json
··· 58 58 "@lingui/react": "^4.5.0", 59 59 "@mattermost/react-native-paste-input": "^0.6.4", 60 60 "@miblanchard/react-native-slider": "^2.3.1", 61 + "@radix-ui/react-dropdown-menu": "^2.0.6", 61 62 "@react-native-async-storage/async-storage": "1.21.0", 62 63 "@react-native-camera-roll/camera-roll": "^5.2.2", 63 64 "@react-native-clipboard/clipboard": "^1.10.0", ··· 148 149 "react-avatar-editor": "^13.0.0", 149 150 "react-circular-progressbar": "^2.1.0", 150 151 "react-dom": "^18.2.0", 152 + "react-keyed-flatten-children": "^3.0.0", 151 153 "react-native": "0.73.2", 152 154 "react-native-appstate-hook": "^1.0.6", 153 155 "react-native-drawer-layout": "^4.0.0-alpha.3",
+16 -11
src/components/Dialog/context.ts
··· 21 21 open: () => {}, 22 22 close: () => {}, 23 23 }) 24 - const {activeDialogs} = useDialogStateContext() 24 + const {activeDialogs, openDialogs} = useDialogStateContext() 25 + const isOpen = openDialogs.includes(id) 25 26 26 27 React.useEffect(() => { 27 28 activeDialogs.current.set(id, control) ··· 31 32 } 32 33 }, [id, activeDialogs]) 33 34 34 - return { 35 - id, 36 - ref: control, 37 - open: () => { 38 - control.current.open() 39 - }, 40 - close: cb => { 41 - control.current.close(cb) 42 - }, 43 - } 35 + return React.useMemo<DialogOuterProps['control']>( 36 + () => ({ 37 + id, 38 + ref: control, 39 + isOpen, 40 + open: () => { 41 + control.current.open() 42 + }, 43 + close: cb => { 44 + control.current.close(cb) 45 + }, 46 + }), 47 + [id, control, isOpen], 48 + ) 44 49 }
+1
src/components/Dialog/types.ts
··· 22 22 export type DialogControlProps = DialogControlRefProps & { 23 23 id: string 24 24 ref: React.RefObject<DialogControlRefProps> 25 + isOpen: boolean 25 26 } 26 27 27 28 export type DialogContextProps = {
+8
src/components/Menu/context.tsx
··· 1 + import React from 'react' 2 + 3 + import type {ContextType} from '#/components/Menu/types' 4 + 5 + export const Context = React.createContext<ContextType>({ 6 + // @ts-ignore 7 + control: null, 8 + })
+190
src/components/Menu/index.tsx
··· 1 + import React from 'react' 2 + import {View, Pressable} from 'react-native' 3 + import flattenReactChildren from 'react-keyed-flatten-children' 4 + 5 + import {atoms as a, useTheme} from '#/alf' 6 + import * as Dialog from '#/components/Dialog' 7 + import {useInteractionState} from '#/components/hooks/useInteractionState' 8 + import {Text} from '#/components/Typography' 9 + 10 + import {Context} from '#/components/Menu/context' 11 + import { 12 + ContextType, 13 + TriggerProps, 14 + ItemProps, 15 + GroupProps, 16 + ItemTextProps, 17 + ItemIconProps, 18 + } from '#/components/Menu/types' 19 + 20 + export {useDialogControl as useMenuControl} from '#/components/Dialog' 21 + 22 + export function useMemoControlContext() { 23 + return React.useContext(Context) 24 + } 25 + 26 + export function Root({ 27 + children, 28 + control, 29 + }: React.PropsWithChildren<{ 30 + control?: Dialog.DialogOuterProps['control'] 31 + }>) { 32 + const defaultControl = Dialog.useDialogControl() 33 + const context = React.useMemo<ContextType>( 34 + () => ({ 35 + control: control || defaultControl, 36 + }), 37 + [control, defaultControl], 38 + ) 39 + 40 + return <Context.Provider value={context}>{children}</Context.Provider> 41 + } 42 + 43 + export function Trigger({children, label}: TriggerProps) { 44 + const {control} = React.useContext(Context) 45 + const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState() 46 + const { 47 + state: pressed, 48 + onIn: onPressIn, 49 + onOut: onPressOut, 50 + } = useInteractionState() 51 + 52 + return children({ 53 + isNative: true, 54 + control, 55 + state: { 56 + hovered: false, 57 + focused, 58 + pressed, 59 + }, 60 + props: { 61 + onPress: control.open, 62 + onFocus, 63 + onBlur, 64 + onPressIn, 65 + onPressOut, 66 + accessibilityLabel: label, 67 + }, 68 + }) 69 + } 70 + 71 + export function Outer({children}: React.PropsWithChildren<{}>) { 72 + const context = React.useContext(Context) 73 + 74 + return ( 75 + <Dialog.Outer control={context.control}> 76 + <Dialog.Handle /> 77 + 78 + {/* Re-wrap with context since Dialogs are portal-ed to root */} 79 + <Context.Provider value={context}> 80 + <Dialog.ScrollableInner label="Menu TODO"> 81 + <View style={[a.gap_lg]}>{children}</View> 82 + <View style={{height: a.gap_lg.gap}} /> 83 + </Dialog.ScrollableInner> 84 + </Context.Provider> 85 + </Dialog.Outer> 86 + ) 87 + } 88 + 89 + export function Item({children, label, style, onPress, ...rest}: ItemProps) { 90 + const t = useTheme() 91 + const {control} = React.useContext(Context) 92 + const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState() 93 + const { 94 + state: pressed, 95 + onIn: onPressIn, 96 + onOut: onPressOut, 97 + } = useInteractionState() 98 + 99 + return ( 100 + <Pressable 101 + {...rest} 102 + accessibilityHint="" 103 + accessibilityLabel={label} 104 + onPress={e => { 105 + onPress(e) 106 + 107 + if (!e.defaultPrevented) { 108 + control?.close() 109 + } 110 + }} 111 + onFocus={onFocus} 112 + onBlur={onBlur} 113 + onPressIn={onPressIn} 114 + onPressOut={onPressOut} 115 + style={[ 116 + a.flex_row, 117 + a.align_center, 118 + a.gap_sm, 119 + a.px_md, 120 + a.rounded_md, 121 + a.border, 122 + t.atoms.bg_contrast_25, 123 + t.atoms.border_contrast_low, 124 + {minHeight: 44, paddingVertical: 10}, 125 + style, 126 + (focused || pressed) && [t.atoms.bg_contrast_50], 127 + ]}> 128 + {children} 129 + </Pressable> 130 + ) 131 + } 132 + 133 + export function ItemText({children, style}: ItemTextProps) { 134 + const t = useTheme() 135 + return ( 136 + <Text 137 + numberOfLines={1} 138 + ellipsizeMode="middle" 139 + style={[ 140 + a.flex_1, 141 + a.text_md, 142 + a.font_bold, 143 + t.atoms.text_contrast_medium, 144 + {paddingTop: 3}, 145 + style, 146 + ]}> 147 + {children} 148 + </Text> 149 + ) 150 + } 151 + 152 + export function ItemIcon({icon: Comp}: ItemIconProps) { 153 + const t = useTheme() 154 + return <Comp size="lg" fill={t.atoms.text_contrast_medium.color} /> 155 + } 156 + 157 + export function Group({children, style}: GroupProps) { 158 + const t = useTheme() 159 + return ( 160 + <View 161 + style={[ 162 + a.rounded_md, 163 + a.overflow_hidden, 164 + a.border, 165 + t.atoms.border_contrast_low, 166 + style, 167 + ]}> 168 + {flattenReactChildren(children).map((child, i) => { 169 + return React.isValidElement(child) && child.type === Item ? ( 170 + <React.Fragment key={i}> 171 + {i > 0 ? ( 172 + <View style={[a.border_b, t.atoms.border_contrast_low]} /> 173 + ) : null} 174 + {React.cloneElement(child, { 175 + // @ts-ignore 176 + style: { 177 + borderRadius: 0, 178 + borderWidth: 0, 179 + }, 180 + })} 181 + </React.Fragment> 182 + ) : null 183 + })} 184 + </View> 185 + ) 186 + } 187 + 188 + export function Divider() { 189 + return null 190 + }
+247
src/components/Menu/index.web.tsx
··· 1 + import React from 'react' 2 + import {View, Pressable} from 'react-native' 3 + import * as DropdownMenu from '@radix-ui/react-dropdown-menu' 4 + 5 + import * as Dialog from '#/components/Dialog' 6 + import {useInteractionState} from '#/components/hooks/useInteractionState' 7 + import {atoms as a, useTheme, flatten, web} from '#/alf' 8 + import {Text} from '#/components/Typography' 9 + 10 + import { 11 + ContextType, 12 + TriggerProps, 13 + ItemProps, 14 + GroupProps, 15 + ItemTextProps, 16 + ItemIconProps, 17 + } from '#/components/Menu/types' 18 + import {Context} from '#/components/Menu/context' 19 + 20 + export function useMenuControl(): Dialog.DialogControlProps { 21 + const id = React.useId() 22 + const [isOpen, setIsOpen] = React.useState(false) 23 + 24 + return React.useMemo( 25 + () => ({ 26 + id, 27 + ref: {current: null}, 28 + isOpen, 29 + open() { 30 + setIsOpen(true) 31 + }, 32 + close() { 33 + setIsOpen(false) 34 + }, 35 + }), 36 + [id, isOpen, setIsOpen], 37 + ) 38 + } 39 + 40 + export function useMemoControlContext() { 41 + return React.useContext(Context) 42 + } 43 + 44 + export function Root({ 45 + children, 46 + control, 47 + }: React.PropsWithChildren<{ 48 + control?: Dialog.DialogOuterProps['control'] 49 + }>) { 50 + const defaultControl = useMenuControl() 51 + const context = React.useMemo<ContextType>( 52 + () => ({ 53 + control: control || defaultControl, 54 + }), 55 + [control, defaultControl], 56 + ) 57 + const onOpenChange = React.useCallback( 58 + (open: boolean) => { 59 + if (context.control.isOpen && !open) { 60 + context.control.close() 61 + } else if (!context.control.isOpen && open) { 62 + context.control.open() 63 + } 64 + }, 65 + [context.control], 66 + ) 67 + 68 + return ( 69 + <Context.Provider value={context}> 70 + <DropdownMenu.Root 71 + open={context.control.isOpen} 72 + onOpenChange={onOpenChange}> 73 + {children} 74 + </DropdownMenu.Root> 75 + </Context.Provider> 76 + ) 77 + } 78 + 79 + export function Trigger({children, label, style}: TriggerProps) { 80 + const {control} = React.useContext(Context) 81 + const { 82 + state: hovered, 83 + onIn: onMouseEnter, 84 + onOut: onMouseLeave, 85 + } = useInteractionState() 86 + const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState() 87 + 88 + return ( 89 + <DropdownMenu.Trigger asChild> 90 + <Pressable 91 + accessibilityHint="" 92 + accessibilityLabel={label} 93 + onFocus={onFocus} 94 + onBlur={onBlur} 95 + style={flatten([style, web({outline: 0})])} 96 + onPointerDown={() => { 97 + control.open() 98 + }} 99 + {...web({ 100 + onMouseEnter, 101 + onMouseLeave, 102 + })}> 103 + {children({ 104 + isNative: false, 105 + control, 106 + state: { 107 + hovered, 108 + focused, 109 + pressed: false, 110 + }, 111 + props: {}, 112 + })} 113 + </Pressable> 114 + </DropdownMenu.Trigger> 115 + ) 116 + } 117 + 118 + export function Outer({children}: React.PropsWithChildren<{}>) { 119 + const t = useTheme() 120 + 121 + return ( 122 + <DropdownMenu.Portal> 123 + <DropdownMenu.Content sideOffset={5} loop aria-label="Test"> 124 + <View 125 + style={[ 126 + a.rounded_sm, 127 + a.p_xs, 128 + t.name === 'light' ? t.atoms.bg : t.atoms.bg_contrast_25, 129 + t.atoms.shadow_md, 130 + ]}> 131 + {children} 132 + </View> 133 + 134 + <DropdownMenu.Arrow 135 + className="DropdownMenuArrow" 136 + fill={ 137 + (t.name === 'light' ? t.atoms.bg : t.atoms.bg_contrast_25) 138 + .backgroundColor 139 + } 140 + /> 141 + </DropdownMenu.Content> 142 + </DropdownMenu.Portal> 143 + ) 144 + } 145 + 146 + export function Item({children, label, onPress, ...rest}: ItemProps) { 147 + const t = useTheme() 148 + const {control} = React.useContext(Context) 149 + const { 150 + state: hovered, 151 + onIn: onMouseEnter, 152 + onOut: onMouseLeave, 153 + } = useInteractionState() 154 + const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState() 155 + 156 + return ( 157 + <DropdownMenu.Item asChild> 158 + <Pressable 159 + {...rest} 160 + className="radix-dropdown-item" 161 + accessibilityHint="" 162 + accessibilityLabel={label} 163 + onPress={e => { 164 + onPress(e) 165 + 166 + /** 167 + * Ported forward from Radix 168 + * @see https://www.radix-ui.com/primitives/docs/components/dropdown-menu#item 169 + */ 170 + if (!e.defaultPrevented) { 171 + control.close() 172 + } 173 + }} 174 + onFocus={onFocus} 175 + onBlur={onBlur} 176 + // need `flatten` here for Radix compat 177 + style={flatten([ 178 + a.flex_row, 179 + a.align_center, 180 + a.gap_sm, 181 + a.py_sm, 182 + a.rounded_xs, 183 + {minHeight: 32, paddingHorizontal: 10}, 184 + web({outline: 0}), 185 + (hovered || focused) && [ 186 + web({outline: '0 !important'}), 187 + t.name === 'light' 188 + ? t.atoms.bg_contrast_25 189 + : t.atoms.bg_contrast_50, 190 + ], 191 + ])} 192 + {...web({ 193 + onMouseEnter, 194 + onMouseLeave, 195 + })}> 196 + {children} 197 + </Pressable> 198 + </DropdownMenu.Item> 199 + ) 200 + } 201 + 202 + export function ItemText({children, style}: ItemTextProps) { 203 + const t = useTheme() 204 + return ( 205 + <Text style={[a.flex_1, a.font_bold, t.atoms.text_contrast_high, style]}> 206 + {children} 207 + </Text> 208 + ) 209 + } 210 + 211 + export function ItemIcon({icon: Comp, position = 'left'}: ItemIconProps) { 212 + const t = useTheme() 213 + return ( 214 + <Comp 215 + size="md" 216 + fill={t.atoms.text_contrast_medium.color} 217 + style={[ 218 + position === 'left' && { 219 + marginLeft: -2, 220 + }, 221 + position === 'right' && { 222 + marginRight: -2, 223 + marginLeft: 12, 224 + }, 225 + ]} 226 + /> 227 + ) 228 + } 229 + 230 + export function Group({children}: GroupProps) { 231 + return children 232 + } 233 + 234 + export function Divider() { 235 + const t = useTheme() 236 + return ( 237 + <DropdownMenu.Separator 238 + style={flatten([ 239 + a.my_xs, 240 + t.atoms.bg_contrast_100, 241 + { 242 + height: 1, 243 + }, 244 + ])} 245 + /> 246 + ) 247 + }
+72
src/components/Menu/types.ts
··· 1 + import React from 'react' 2 + import {GestureResponderEvent, PressableProps} from 'react-native' 3 + 4 + import {Props as SVGIconProps} from '#/components/icons/common' 5 + import * as Dialog from '#/components/Dialog' 6 + import {TextStyleProp, ViewStyleProp} from '#/alf' 7 + 8 + export type ContextType = { 9 + control: Dialog.DialogOuterProps['control'] 10 + } 11 + 12 + export type TriggerProps = ViewStyleProp & { 13 + children(props: TriggerChildProps): React.ReactNode 14 + label: string 15 + } 16 + export type TriggerChildProps = 17 + | { 18 + isNative: true 19 + control: Dialog.DialogOuterProps['control'] 20 + state: { 21 + /** 22 + * Web only, `false` on native 23 + */ 24 + hovered: false 25 + focused: boolean 26 + pressed: boolean 27 + } 28 + /** 29 + * We don't necessarily know what these will be spread on to, so we 30 + * should add props one-by-one. 31 + * 32 + * On web, these properties are applied to a parent `Pressable`, so this 33 + * object is empty. 34 + */ 35 + props: { 36 + onPress: () => void 37 + onFocus: () => void 38 + onBlur: () => void 39 + onPressIn: () => void 40 + onPressOut: () => void 41 + accessibilityLabel: string 42 + } 43 + } 44 + | { 45 + isNative: false 46 + control: Dialog.DialogOuterProps['control'] 47 + state: { 48 + hovered: boolean 49 + focused: boolean 50 + /** 51 + * Native only, `false` on web 52 + */ 53 + pressed: false 54 + } 55 + props: {} 56 + } 57 + 58 + export type ItemProps = React.PropsWithChildren< 59 + Omit<PressableProps, 'style'> & 60 + ViewStyleProp & { 61 + label: string 62 + onPress: (e: GestureResponderEvent) => void 63 + } 64 + > 65 + 66 + export type ItemTextProps = React.PropsWithChildren<TextStyleProp & {}> 67 + export type ItemIconProps = React.PropsWithChildren<{ 68 + icon: React.ComponentType<SVGIconProps> 69 + position?: 'left' | 'right' 70 + }> 71 + 72 + export type GroupProps = React.PropsWithChildren<ViewStyleProp & {}>
+79
src/view/screens/Storybook/Menus.tsx
··· 1 + import React from 'react' 2 + import {View} from 'react-native' 3 + 4 + import {atoms as a, useTheme} from '#/alf' 5 + import {Text} from '#/components/Typography' 6 + import * as Menu from '#/components/Menu' 7 + import {MagnifyingGlass2_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass2' 8 + // import {useDialogStateControlContext} from '#/state/dialogs' 9 + 10 + export function Menus() { 11 + const t = useTheme() 12 + const menuControl = Menu.useMenuControl() 13 + // const {closeAllDialogs} = useDialogStateControlContext() 14 + 15 + return ( 16 + <View style={[a.gap_md]}> 17 + <View style={[a.flex_row, a.align_start]}> 18 + <Menu.Root control={menuControl}> 19 + <Menu.Trigger label="Open basic menu" style={[a.flex_1]}> 20 + {({state, props}) => { 21 + return ( 22 + <Text 23 + {...props} 24 + style={[ 25 + a.py_sm, 26 + a.px_md, 27 + a.rounded_sm, 28 + t.atoms.bg_contrast_50, 29 + (state.hovered || state.focused || state.pressed) && [ 30 + t.atoms.bg_contrast_200, 31 + ], 32 + ]}> 33 + Open 34 + </Text> 35 + ) 36 + }} 37 + </Menu.Trigger> 38 + 39 + <Menu.Outer> 40 + <Menu.Group> 41 + <Menu.Item label="Click me" onPress={() => {}}> 42 + <Menu.ItemIcon icon={Search} /> 43 + <Menu.ItemText>Click me</Menu.ItemText> 44 + </Menu.Item> 45 + 46 + <Menu.Item 47 + label="Another item" 48 + onPress={() => menuControl.close()}> 49 + <Menu.ItemText>Another item</Menu.ItemText> 50 + </Menu.Item> 51 + </Menu.Group> 52 + 53 + <Menu.Divider /> 54 + 55 + <Menu.Group> 56 + <Menu.Item label="Click me" onPress={() => {}}> 57 + <Menu.ItemIcon icon={Search} /> 58 + <Menu.ItemText>Click me</Menu.ItemText> 59 + </Menu.Item> 60 + 61 + <Menu.Item 62 + label="Another item" 63 + onPress={() => menuControl.close()}> 64 + <Menu.ItemText>Another item</Menu.ItemText> 65 + </Menu.Item> 66 + </Menu.Group> 67 + 68 + <Menu.Divider /> 69 + 70 + <Menu.Item label="Click me" onPress={() => {}}> 71 + <Menu.ItemIcon icon={Search} /> 72 + <Menu.ItemText>Click me</Menu.ItemText> 73 + </Menu.Item> 74 + </Menu.Outer> 75 + </Menu.Root> 76 + </View> 77 + </View> 78 + ) 79 + }
+2
src/view/screens/Storybook/index.tsx
··· 16 16 import {Breakpoints} from './Breakpoints' 17 17 import {Shadows} from './Shadows' 18 18 import {Icons} from './Icons' 19 + import {Menus} from './Menus' 19 20 20 21 export function Storybook() { 21 22 const t = useTheme() ··· 84 85 <Links /> 85 86 <Forms /> 86 87 <Dialogs /> 88 + <Menus /> 87 89 <Breakpoints /> 88 90 </View> 89 91 </CenteredView>
+1
web/index.html
··· 217 217 } 218 218 219 219 /* NativeDropdown component */ 220 + .radix-dropdown-item:focus, 220 221 .nativeDropdown-item:focus { 221 222 outline: none; 222 223 }
+93
yarn.lock
··· 4467 4467 "@radix-ui/react-use-callback-ref" "1.0.1" 4468 4468 "@radix-ui/react-use-escape-keydown" "1.0.3" 4469 4469 4470 + "@radix-ui/react-dismissable-layer@1.0.5": 4471 + version "1.0.5" 4472 + resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz#3f98425b82b9068dfbab5db5fff3df6ebf48b9d4" 4473 + integrity sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g== 4474 + dependencies: 4475 + "@babel/runtime" "^7.13.10" 4476 + "@radix-ui/primitive" "1.0.1" 4477 + "@radix-ui/react-compose-refs" "1.0.1" 4478 + "@radix-ui/react-primitive" "1.0.3" 4479 + "@radix-ui/react-use-callback-ref" "1.0.1" 4480 + "@radix-ui/react-use-escape-keydown" "1.0.3" 4481 + 4470 4482 "@radix-ui/react-dropdown-menu@^2.0.1": 4471 4483 version "2.0.5" 4472 4484 resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.0.5.tgz#19bf4de8ffa348b4eb6a86842f14eff93d741170" ··· 4481 4493 "@radix-ui/react-primitive" "1.0.3" 4482 4494 "@radix-ui/react-use-controllable-state" "1.0.1" 4483 4495 4496 + "@radix-ui/react-dropdown-menu@^2.0.6": 4497 + version "2.0.6" 4498 + resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.0.6.tgz#cdf13c956c5e263afe4e5f3587b3071a25755b63" 4499 + integrity sha512-i6TuFOoWmLWq+M/eCLGd/bQ2HfAX1RJgvrBQ6AQLmzfvsLdefxbWu8G9zczcPFfcSPehz9GcpF6K9QYreFV8hA== 4500 + dependencies: 4501 + "@babel/runtime" "^7.13.10" 4502 + "@radix-ui/primitive" "1.0.1" 4503 + "@radix-ui/react-compose-refs" "1.0.1" 4504 + "@radix-ui/react-context" "1.0.1" 4505 + "@radix-ui/react-id" "1.0.1" 4506 + "@radix-ui/react-menu" "2.0.6" 4507 + "@radix-ui/react-primitive" "1.0.3" 4508 + "@radix-ui/react-use-controllable-state" "1.0.1" 4509 + 4484 4510 "@radix-ui/react-focus-guards@1.0.1": 4485 4511 version "1.0.1" 4486 4512 resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz#1ea7e32092216b946397866199d892f71f7f98ad" ··· 4492 4518 version "1.0.3" 4493 4519 resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.3.tgz#9c2e8d4ed1189a1d419ee61edd5c1828726472f9" 4494 4520 integrity sha512-upXdPfqI4islj2CslyfUBNlaJCPybbqRHAi1KER7Isel9Q2AtSJ0zRBZv8mWQiFXD2nyAJ4BhC3yXgZ6kMBSrQ== 4521 + dependencies: 4522 + "@babel/runtime" "^7.13.10" 4523 + "@radix-ui/react-compose-refs" "1.0.1" 4524 + "@radix-ui/react-primitive" "1.0.3" 4525 + "@radix-ui/react-use-callback-ref" "1.0.1" 4526 + 4527 + "@radix-ui/react-focus-scope@1.0.4": 4528 + version "1.0.4" 4529 + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz#2ac45fce8c5bb33eb18419cdc1905ef4f1906525" 4530 + integrity sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA== 4495 4531 dependencies: 4496 4532 "@babel/runtime" "^7.13.10" 4497 4533 "@radix-ui/react-compose-refs" "1.0.1" ··· 4531 4567 aria-hidden "^1.1.1" 4532 4568 react-remove-scroll "2.5.5" 4533 4569 4570 + "@radix-ui/react-menu@2.0.6": 4571 + version "2.0.6" 4572 + resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-2.0.6.tgz#2c9e093c1a5d5daa87304b2a2f884e32288ae79e" 4573 + integrity sha512-BVkFLS+bUC8HcImkRKPSiVumA1VPOOEC5WBMiT+QAVsPzW1FJzI9KnqgGxVDPBcql5xXrHkD3JOVoXWEXD8SYA== 4574 + dependencies: 4575 + "@babel/runtime" "^7.13.10" 4576 + "@radix-ui/primitive" "1.0.1" 4577 + "@radix-ui/react-collection" "1.0.3" 4578 + "@radix-ui/react-compose-refs" "1.0.1" 4579 + "@radix-ui/react-context" "1.0.1" 4580 + "@radix-ui/react-direction" "1.0.1" 4581 + "@radix-ui/react-dismissable-layer" "1.0.5" 4582 + "@radix-ui/react-focus-guards" "1.0.1" 4583 + "@radix-ui/react-focus-scope" "1.0.4" 4584 + "@radix-ui/react-id" "1.0.1" 4585 + "@radix-ui/react-popper" "1.1.3" 4586 + "@radix-ui/react-portal" "1.0.4" 4587 + "@radix-ui/react-presence" "1.0.1" 4588 + "@radix-ui/react-primitive" "1.0.3" 4589 + "@radix-ui/react-roving-focus" "1.0.4" 4590 + "@radix-ui/react-slot" "1.0.2" 4591 + "@radix-ui/react-use-callback-ref" "1.0.1" 4592 + aria-hidden "^1.1.1" 4593 + react-remove-scroll "2.5.5" 4594 + 4534 4595 "@radix-ui/react-popper@1.1.2": 4535 4596 version "1.1.2" 4536 4597 resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.1.2.tgz#4c0b96fcd188dc1f334e02dba2d538973ad842e9" ··· 4548 4609 "@radix-ui/react-use-size" "1.0.1" 4549 4610 "@radix-ui/rect" "1.0.1" 4550 4611 4612 + "@radix-ui/react-popper@1.1.3": 4613 + version "1.1.3" 4614 + resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.1.3.tgz#24c03f527e7ac348fabf18c89795d85d21b00b42" 4615 + integrity sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w== 4616 + dependencies: 4617 + "@babel/runtime" "^7.13.10" 4618 + "@floating-ui/react-dom" "^2.0.0" 4619 + "@radix-ui/react-arrow" "1.0.3" 4620 + "@radix-ui/react-compose-refs" "1.0.1" 4621 + "@radix-ui/react-context" "1.0.1" 4622 + "@radix-ui/react-primitive" "1.0.3" 4623 + "@radix-ui/react-use-callback-ref" "1.0.1" 4624 + "@radix-ui/react-use-layout-effect" "1.0.1" 4625 + "@radix-ui/react-use-rect" "1.0.1" 4626 + "@radix-ui/react-use-size" "1.0.1" 4627 + "@radix-ui/rect" "1.0.1" 4628 + 4551 4629 "@radix-ui/react-portal@1.0.3": 4552 4630 version "1.0.3" 4553 4631 resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.3.tgz#ffb961244c8ed1b46f039e6c215a6c4d9989bda1" 4554 4632 integrity sha512-xLYZeHrWoPmA5mEKEfZZevoVRK/Q43GfzRXkWV6qawIWWK8t6ifIiLQdd7rmQ4Vk1bmI21XhqF9BN3jWf+phpA== 4633 + dependencies: 4634 + "@babel/runtime" "^7.13.10" 4635 + "@radix-ui/react-primitive" "1.0.3" 4636 + 4637 + "@radix-ui/react-portal@1.0.4": 4638 + version "1.0.4" 4639 + resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.4.tgz#df4bfd353db3b1e84e639e9c63a5f2565fb00e15" 4640 + integrity sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q== 4555 4641 dependencies: 4556 4642 "@babel/runtime" "^7.13.10" 4557 4643 "@radix-ui/react-primitive" "1.0.3" ··· 18371 18457 version "17.0.2" 18372 18458 resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" 18373 18459 integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== 18460 + 18461 + react-keyed-flatten-children@^3.0.0: 18462 + version "3.0.0" 18463 + resolved "https://registry.yarnpkg.com/react-keyed-flatten-children/-/react-keyed-flatten-children-3.0.0.tgz#b6ad0bde437d3ab86c8af3a1902d164be2a29d67" 18464 + integrity sha512-tSH6gvOyQjt3qtjG+kU9sTypclL1672yjpVufcE3aHNM0FhvjBUQZqsb/awIux4zEuVC3k/DP4p0GdTT/QUt/Q== 18465 + dependencies: 18466 + react-is "^18.2.0" 18374 18467 18375 18468 react-native-appstate-hook@^1.0.6: 18376 18469 version "1.0.6"