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/src/components/Menu/index.tsx b/src/components/Menu/index.tsx index 9885b2aead..2d0f0addee 100644 --- a/src/components/Menu/index.tsx +++ b/src/components/Menu/index.tsx @@ -1,10 +1,20 @@ import React from 'react' +import {View, Pressable} from 'react-native' +import {atoms as a, useTheme, ViewStyleProp} from '#/alf' import * as Dialog from '#/components/Dialog' import {useInteractionState} from '#/components/hooks/useInteractionState' +import {Text} from '#/components/Typography' -import {ContextType, TriggerChildProps} from '#/components/Menu/types' import {Context} from '#/components/Menu/context' +import { + ContextType, + TriggerChildProps, + ItemProps, + GroupProps, + ItemTextProps, + ItemIconProps, +} from '#/components/Menu/types' export {useDialogControl as useMenuControl} from '#/components/Dialog' @@ -27,7 +37,7 @@ export function Root({ export function Trigger({ children, -}: { +}: ViewStyleProp & { children(props: TriggerChildProps): React.ReactNode }) { const {control} = React.useContext(Context) @@ -71,10 +81,99 @@ export function Outer({children}: React.PropsWithChildren<{}>) { - {children} + {children} + ) } -export function Button({}: {}) {} +export function Item({children, label, style, onPress}: ItemProps) { + const t = useTheme() + const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState() + const { + state: pressed, + onIn: onPressIn, + onOut: onPressOut, + } = useInteractionState() + + return ( + + {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 ( + + {React.Children.toArray(children).map((child, i) => { + // ignore null children, like Dividers + return React.isValidElement(child) && child.props.children ? ( + + {i > 0 ? ( + + ) : null} + {React.cloneElement(child, { + // @ts-ignore + style: { + borderRadius: 0, + }, + })} + + ) : null + })} + + ) +} + +export function Divider() { + return null +} diff --git a/src/components/Menu/index.web.tsx b/src/components/Menu/index.web.tsx index 9c0348773f..dadd890eab 100644 --- a/src/components/Menu/index.web.tsx +++ b/src/components/Menu/index.web.tsx @@ -1,12 +1,20 @@ import React from 'react' -import {Pressable} from 'react-native' +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 {flatten, web} from '#/alf' +import {atoms as a, useTheme, flatten, web, ViewStyleProp} from '#/alf' +import {Text} from '#/components/Typography' -import {ContextType, TriggerChildProps} from '#/components/Menu/types' +import { + ContextType, + TriggerChildProps, + ItemProps, + GroupProps, + ItemTextProps, + ItemIconProps, +} from '#/components/Menu/types' import {Context} from '#/components/Menu/context' export function useMenuControl(): Dialog.DialogControlProps { @@ -44,7 +52,8 @@ export function Root({ export function Trigger({ children, -}: { + style, +}: ViewStyleProp & { children(props: TriggerChildProps): React.ReactNode }) { const { @@ -59,7 +68,7 @@ export function Trigger({ ) { +export function Outer({children}: React.PropsWithChildren<{}>) { + const t = useTheme() + return ( - - - New Tab
⌘+T
-
+ + + {children} + + +
) } -export function Button({}: {}) {} +export function Item({children, label, onPress}: ItemProps) { + const t = useTheme() + const { + state: hovered, + onIn: onMouseEnter, + onOut: onMouseLeave, + } = useInteractionState() + const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState() + + return ( + + + {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 index 2eeb3d5cdb..9b38f1d7ad 100644 --- a/src/components/Menu/types.ts +++ b/src/components/Menu/types.ts @@ -1,4 +1,8 @@ +import React from 'react' +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'] | null @@ -37,3 +41,18 @@ export type TriggerChildProps = } handlers: {} } + +export type ItemProps = React.PropsWithChildren< + ViewStyleProp & { + label: string + onPress: () => 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 index e359d98a70..12efccdf1a 100644 --- a/src/view/screens/Storybook/Menus.tsx +++ b/src/view/screens/Storybook/Menus.tsx @@ -4,6 +4,7 @@ import {View} from 'react-native' import {atoms as a} 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() { @@ -11,18 +12,30 @@ export function Menus() { return ( - - - {({state, handlers}) => { - console.log(state.hovered, state.focused, state.pressed) - return Open - }} - + + + + {({handlers}) => { + return Open + }} + - - Open - - + + + {}}> + + Click me + + + + + {}}> + Another item + + + + + ) } 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; }