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;
}