Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ const Dropdown = (p: DropdownProps) => {
direction="horizontal"
alignItems="center"
style={styles.dropdown}
ref={isMobile ? null : popupAnchor}
ref={popupAnchor}
onClick={showPopup}
>
<Kb.Box2 direction="horizontal" alignItems="center" fullWidth={true} style={styles.label}>
Expand Down
2 changes: 1 addition & 1 deletion shared/chat/conversation/input-area/normal/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ const EmojiButton = function EmojiButton(p: EmojiButtonProps) {
const makePopup = (p: Kb.Popup2Parms) => {
const {attachTo, hidePopup} = p
return (
<Kb.Popup attachTo={attachTo} visible={true} onHidden={hidePopup} position="top right">
<Kb.Popup intent="menu" attachTo={attachTo} onHidden={hidePopup} position="top right">
<EmojiPickerDesktop
conversationIDKey={conversationIDKey}
onPickAction={insertEmoji}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jest.mock('../../thread-context', () => ({useConversationThreadID: () => 'conv'}
jest.mock('../input-state', () => ({useConversationInput: () => false}))
jest.mock('@/common-adapters', () => {
const actual = jest.requireActual<Record<string, unknown>>('@/common-adapters')
return {...actual, Popup: (p: {children: React.ReactNode}) => <>{p.children}</>}
return {...actual, AnchoredPopup: (p: {children: React.ReactNode}) => <>{p.children}</>}
})

// the suggestors read the caret through the input ref; drive it directly so the
Expand Down
6 changes: 2 additions & 4 deletions shared/chat/conversation/input-area/suggestors/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -479,20 +479,18 @@ const Popup = (p: PopupProps) => {
const attachRef = inputRef as React.RefObject<Kb.MeasureRef | null>

return (
<Kb.Popup
<Kb.AnchoredPopup
attachTo={attachRef}
mobileAnchored={true}
matchDimension={true}
position="top center"
positionFallbacks={positionFallbacks}
visible={true}
propagateOutsideClicks={false}
onHidden={setInactive}
containerStyle={suggestionOverlayStyle}
style={suggestionOverlayStyle}
>
{isMobile ? <MobileSuggestionArea>{children}</MobileSuggestionArea> : children}
</Kb.Popup>
</Kb.AnchoredPopup>
)
}

Expand Down
1 change: 1 addition & 0 deletions shared/chat/conversation/messages/emoji-row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ function EmojiRowContainer(p: OwnProps) {
</Kb.Box2>
{showingPicker && message && hasMessageID && (
<Kb.Popup
intent="menu"
attachTo={popupAnchor}
containerStyle={styles.pickerContainer}
position="top right"
Expand Down
8 changes: 4 additions & 4 deletions shared/chat/conversation/messages/reaction-tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ const ReactionTooltip = (p: OwnProps) => {

if (isMobile) {
return (
<Kb.Popup
<Kb.Sheet
onHidden={onHidden}
style={styles.sheet}
footer={
Expand Down Expand Up @@ -173,12 +173,12 @@ const ReactionTooltip = (p: OwnProps) => {
))}
</Kb.Box2>
</MessageContext>
</Kb.Popup>
</Kb.Sheet>
)
}

return (
<Kb.Popup
<Kb.AnchoredPopup
attachTo={attachmentRef}
onHidden={onHidden}
position="top center"
Expand All @@ -205,7 +205,7 @@ const ReactionTooltip = (p: OwnProps) => {
/>
</Kb.Box2>
</MessageContext>
</Kb.Popup>
</Kb.AnchoredPopup>
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ const ChooseConversation = (props: Props) => {
const {attachTo, hidePopup} = p
return (
<Kb.Popup
intent="menu"
attachTo={attachTo}
onHidden={hidePopup}
position="center center"
style={styles.overlay}
visible={true}
>
<ConversationList onSelect={onSelect} onDone={hidePopup} />
</Kb.Popup>
Expand Down
2 changes: 1 addition & 1 deletion shared/common-adapters/dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,9 @@ function Dropdown<N extends React.ReactNode>(p: Props<N>) {
))
return (
<Kb.Popup
intent="menu"
style={Styles.collapseStyles([styles.overlay, overlayStyle])}
attachTo={attachTo}
visible={true}
onHidden={hidePopup}
position={position || 'center center'}
>
Expand Down
26 changes: 26 additions & 0 deletions shared/common-adapters/floating-menu/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/** @jest-environment jsdom */
/// <reference types="jest" />

import {cleanup, render} from '@testing-library/react'
import FloatingMenu from '.'

const items = [{onClick: () => {}, title: 'an item'}]

describe('FloatingMenu visibility', () => {
afterEach(() => {
cleanup()
})

// 'modal' used to skip this guard and rely on Popup dropping an invisible
// popup on the way past. Popup no longer takes visible, so the guard is the
// only thing keeping a hidden menu off the screen.
test.each([undefined, 'bottomsheet', 'modal'] as const)(
'renders nothing when hidden in %s mode',
mode => {
const {container} = render(
<FloatingMenu closeOnSelect={true} items={items} mode={mode} onHidden={() => {}} visible={false} />
)
expect(container.innerHTML).toBe('')
}
)
})
8 changes: 4 additions & 4 deletions shared/common-adapters/floating-menu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ function FloatingMenu(props: Props) {
return unsub
}, [navigation, onHidden])

// modal mode callers control mounting themselves; sheets present on mount so
// they must unmount when not visible
if (!visible && mode !== 'modal') {
// sheets present on mount, so an invisible menu must not render at all. Popup
// used to catch the modal case on the way past; it no longer takes visible.
if (!visible) {
return null
}

Expand All @@ -77,9 +77,9 @@ function FloatingMenu(props: Props) {

return (
<Popup
intent="menu"
attachTo={props.attachTo}
onHidden={onHidden}
visible={props.visible}
position={props.position}
positionFallbacks={props.positionFallbacks}
propagateOutsideClicks={props.propagateOutsideClicks}
Expand Down
11 changes: 4 additions & 7 deletions shared/common-adapters/floating-picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as Styles from '@/styles'
import SafeAreaView from './safe-area-view'
import {Picker} from '@react-native-picker/picker'
import {Box2} from './box'
import Popup from './popup'
import {Sheet} from './popup/sheet'
import Text from './text'

type PickerItem<T> = {
Expand All @@ -24,7 +24,7 @@ export type Props<T> = {
visible: boolean
}

const Kb = {Box2, Picker, Popup, SafeAreaView, Text}
const Kb = {Box2, Picker, SafeAreaView, Sheet, Text}

function WrapPicker<T>(p: {
initialValue?: T
Expand Down Expand Up @@ -68,10 +68,7 @@ const FloatingPicker = <T extends string | number>(props: Props<T>): React.React
}

return (
<Kb.Popup
key={isAndroid ? props.selectedValue || 0 : undefined}
onHidden={props.onHidden}
>
<Kb.Sheet key={isAndroid ? props.selectedValue || 0 : undefined} onHidden={props.onHidden}>
<Kb.Box2 direction="vertical" fullWidth={true} alignItems="stretch" justifyContent="flex-end" style={styles.menu}>
{props.header}
<Kb.Box2
Expand Down Expand Up @@ -100,7 +97,7 @@ const FloatingPicker = <T extends string | number>(props: Props<T>): React.React
/>
<Kb.SafeAreaView style={styles.safeArea} />
</Kb.Box2>
</Kb.Popup>
</Kb.Sheet>
)
}

Expand Down
4 changes: 4 additions & 0 deletions shared/common-adapters/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ export {default as Markdown} from './markdown'
export {default as Meta} from './meta'
export {default as NameWithIcon} from './name-with-icon'
export {default as Popup, type PopupProps} from './popup/index'
export {AnchoredPopup, type AnchoredPopupProps} from './popup/anchored'
export {ModalCover, type ModalCoverProps} from './popup/modal-cover'
export {Sheet, type SheetProps} from './popup/sheet'
export {Portal} from './portal'
export {default as PhoneInput} from './phone-input'
export {default as Placeholder} from './placeholder'
export {default as ProgressBar} from './progress-bar'
Expand Down
56 changes: 56 additions & 0 deletions shared/common-adapters/popup/anchored.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import * as Styles from '@/styles'
import {Box2} from '../box'
import FloatingBox from './floating-box'
import type {AnchoredPopupProps} from './index.shared'
export type {AnchoredPopupProps} from './index.shared'

export const AnchoredPopup = (props: AnchoredPopupProps) => {
const {attachTo, children, containerStyle, hideKeyboard, matchDimension, offset, onHidden} = props
const {position, positionFallbacks, propagateOutsideClicks, remeasureHint, style} = props
const styles = useStyles()

if (isMobile) {
// on mobile FloatingBox is the portal + keyboard-dismiss overlay this needs,
// and there is no positioner, so the anchor and placement props go unused
return (
<FloatingBox containerStyle={containerStyle} hideKeyboard={hideKeyboard}>
{children}
</FloatingBox>
)
}

return (
<FloatingBox
attachTo={attachTo}
containerStyle={containerStyle}
matchDimension={!!matchDimension}
onHidden={onHidden}
remeasureHint={remeasureHint}
position={position}
positionFallbacks={positionFallbacks}
propagateOutsideClicks={propagateOutsideClicks}
offset={offset}
>
{onHidden ? (
<Box2 direction="vertical" style={Styles.collapseStyles([styles.positioned, style])}>
{children}
</Box2>
) : (
children
)}
</FloatingBox>
)
}

const useStyles = Styles.createStyleHook(() => ({
positioned: Styles.platformStyles({
isElectron: {
...Styles.desktopStyles.boxShadow,
...Styles.globalStyles.rounded,
overflowX: 'hidden',
overflowY: 'auto',
},
}),
}))

export default AnchoredPopup
72 changes: 0 additions & 72 deletions shared/common-adapters/popup/bottom-sheet.tsx

This file was deleted.

Loading