Add POC menu abstraction
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import React from 'react'
|
||||
|
||||
import type {ContextType} from '#/components/Menu/types'
|
||||
|
||||
export const Context = React.createContext<ContextType>({
|
||||
// @ts-ignore
|
||||
control: null,
|
||||
})
|
||||
@@ -0,0 +1,80 @@
|
||||
import React from 'react'
|
||||
|
||||
import * as Dialog from '#/components/Dialog'
|
||||
import {useInteractionState} from '#/components/hooks/useInteractionState'
|
||||
|
||||
import {ContextType, TriggerChildProps} from '#/components/Menu/types'
|
||||
import {Context} from '#/components/Menu/context'
|
||||
|
||||
export {useDialogControl as useMenuControl} from '#/components/Dialog'
|
||||
|
||||
export function Root({
|
||||
children,
|
||||
control,
|
||||
}: React.PropsWithChildren<{
|
||||
control?: Dialog.DialogOuterProps['control']
|
||||
}>) {
|
||||
const defaultControl = Dialog.useDialogControl()
|
||||
const context = React.useMemo<ContextType>(
|
||||
() => ({
|
||||
control: control || defaultControl,
|
||||
}),
|
||||
[control, defaultControl],
|
||||
)
|
||||
|
||||
return <Context.Provider value={context}>{children}</Context.Provider>
|
||||
}
|
||||
|
||||
export function Trigger({
|
||||
children,
|
||||
}: {
|
||||
children(props: TriggerChildProps): React.ReactNode
|
||||
}) {
|
||||
const {control} = React.useContext(Context)
|
||||
const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
|
||||
const {
|
||||
state: pressed,
|
||||
onIn: onPressIn,
|
||||
onOut: onPressOut,
|
||||
} = useInteractionState()
|
||||
|
||||
if (!control) {
|
||||
throw new Error('Menu.Trigger must be used within a Menu.Root')
|
||||
}
|
||||
|
||||
return children({
|
||||
isNative: true,
|
||||
control,
|
||||
state: {
|
||||
hovered: false,
|
||||
focused,
|
||||
pressed,
|
||||
},
|
||||
handlers: {
|
||||
onPress: control.open,
|
||||
onFocus,
|
||||
onBlur,
|
||||
onPressIn,
|
||||
onPressOut,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export function Outer({children}: React.PropsWithChildren<{}>) {
|
||||
const {control} = React.useContext(Context)
|
||||
|
||||
if (!control) {
|
||||
throw new Error('Menu.Outer must be used within a Menu.Root')
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog.Outer control={control}>
|
||||
<Dialog.Handle />
|
||||
<Dialog.ScrollableInner label="Menu TODO">
|
||||
{children}
|
||||
</Dialog.ScrollableInner>
|
||||
</Dialog.Outer>
|
||||
)
|
||||
}
|
||||
|
||||
export function Button({}: {}) {}
|
||||
@@ -0,0 +1,101 @@
|
||||
import React from 'react'
|
||||
import {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 {flatten, web} from '#/alf'
|
||||
|
||||
import {ContextType, TriggerChildProps} from '#/components/Menu/types'
|
||||
import {Context} from '#/components/Menu/context'
|
||||
|
||||
export function useMenuControl(): Dialog.DialogControlProps {
|
||||
return {
|
||||
id: '',
|
||||
// @ts-ignore
|
||||
ref: null,
|
||||
open: () => {
|
||||
throw new Error(`Menu controls are only available on native platforms`)
|
||||
},
|
||||
close: () => {
|
||||
throw new Error(`Menu controls are only available on native platforms`)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function Root({
|
||||
children,
|
||||
}: React.PropsWithChildren<{
|
||||
control?: Dialog.DialogOuterProps['control']
|
||||
}>) {
|
||||
const context = React.useMemo<ContextType>(
|
||||
() => ({
|
||||
control: null,
|
||||
}),
|
||||
[],
|
||||
)
|
||||
|
||||
return (
|
||||
<Context.Provider value={context}>
|
||||
<DropdownMenu.Root>{children}</DropdownMenu.Root>
|
||||
</Context.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function Trigger({
|
||||
children,
|
||||
}: {
|
||||
children(props: TriggerChildProps): React.ReactNode
|
||||
}) {
|
||||
const {
|
||||
state: hovered,
|
||||
onIn: onMouseEnter,
|
||||
onOut: onMouseLeave,
|
||||
} = useInteractionState()
|
||||
const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
|
||||
const {
|
||||
state: pressed,
|
||||
onIn: onPressIn,
|
||||
onOut: onPressOut,
|
||||
} = useInteractionState()
|
||||
|
||||
return (
|
||||
<DropdownMenu.Trigger asChild>
|
||||
<Pressable
|
||||
onPressIn={onPressIn}
|
||||
onPressOut={onPressOut}
|
||||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
style={flatten([web({outline: 0})])}
|
||||
{...web({
|
||||
onMouseEnter,
|
||||
onMouseLeave,
|
||||
})}>
|
||||
{children({
|
||||
isNative: false,
|
||||
control: null,
|
||||
state: {
|
||||
hovered,
|
||||
focused,
|
||||
pressed,
|
||||
},
|
||||
handlers: {},
|
||||
})}
|
||||
</Pressable>
|
||||
</DropdownMenu.Trigger>
|
||||
)
|
||||
}
|
||||
|
||||
export function Outer(_props: React.PropsWithChildren<{}>) {
|
||||
return (
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content sideOffset={5}>
|
||||
<DropdownMenu.Item>
|
||||
New Tab <div className="RightSlot">⌘+T</div>
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Portal>
|
||||
)
|
||||
}
|
||||
|
||||
export function Button({}: {}) {}
|
||||
@@ -0,0 +1,33 @@
|
||||
import * as Dialog from '#/components/Dialog'
|
||||
|
||||
export type ContextType = {
|
||||
control: Dialog.DialogOuterProps['control'] | null
|
||||
}
|
||||
|
||||
export type TriggerChildProps =
|
||||
| {
|
||||
isNative: true
|
||||
control: Dialog.DialogOuterProps['control']
|
||||
state: {
|
||||
hovered: false
|
||||
focused: boolean
|
||||
pressed: boolean
|
||||
}
|
||||
handlers: {
|
||||
onPress: () => void
|
||||
onFocus: () => void
|
||||
onBlur: () => void
|
||||
onPressIn: () => void
|
||||
onPressOut: () => void
|
||||
}
|
||||
}
|
||||
| {
|
||||
isNative: false
|
||||
control: null
|
||||
state: {
|
||||
hovered: boolean
|
||||
focused: boolean
|
||||
pressed: boolean
|
||||
}
|
||||
handlers: {}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import React from 'react'
|
||||
import {View} from 'react-native'
|
||||
|
||||
import {atoms as a} from '#/alf'
|
||||
import {Text} from '#/components/Typography'
|
||||
import * as Menu from '#/components/Menu'
|
||||
// import {useDialogStateControlContext} from '#/state/dialogs'
|
||||
|
||||
export function Menus() {
|
||||
// const {closeAllDialogs} = useDialogStateControlContext()
|
||||
|
||||
return (
|
||||
<View style={[a.gap_md]}>
|
||||
<Menu.Root>
|
||||
<Menu.Trigger>
|
||||
{({state, handlers}) => {
|
||||
console.log(state)
|
||||
return <Text {...handlers}>Open</Text>
|
||||
}}
|
||||
</Menu.Trigger>
|
||||
|
||||
<Menu.Outer>
|
||||
<Text>Open</Text>
|
||||
</Menu.Outer>
|
||||
</Menu.Root>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@@ -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()
|
||||
@@ -65,6 +66,7 @@ export function Storybook() {
|
||||
Dark
|
||||
</Button>
|
||||
</View>
|
||||
<Menus />
|
||||
|
||||
<ThemeProvider theme="light">
|
||||
<Theming />
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user