// @ts-nocheck
import { isEqual } from '@o/fast-compare'
import { idFn, selectDefined } from '@o/utils'
import { differenceInCalendarDays } from 'date-fns'
import { Box, gloss, Theme, ThemeByName } from 'gloss'
import React, { isValidElement, memo, useCallback } from 'react'
import { BorderBottom } from '../Border'
import { Button } from '../buttons/Button'
import { RoundButtonSmall } from '../buttons/RoundButtonSmall'
import { useFocus } from '../Focus'
import { HighlightText } from '../Highlight'
import { Icon } from '../Icon'
import { ListSeparator } from '../ListSeparator'
import { Space } from '../Space'
import { Surface } from '../Surface'
import { DateFormat } from '../text/DateFormat'
import { SimpleText } from '../text/SimpleText'
import { Text } from '../text/Text'
import { paddingTheme } from '../View/paddingTheme'
import { Stack } from '../View/Stack'
import { View } from '../View/View'
import { ListItemSimpleProps } from './ListItemViewProps'
import { useIsSelected } from './useIsSelected'
// this wrapper required for virtualization to measure/style */}
// prevents hard re-renders on resize by taking out the style prop
export function ListItemSimple({
style,
nodeRef,
draggableItem,
...listProps
}: ListItemSimpleProps) {
draggableItem
return (
)
}
const ListItemInner = memo(function ListItemInner(props: ListItemSimpleProps) {
const {
date,
location,
preview,
icon,
subTitle,
title,
borderRadius,
children,
onClick,
titleProps,
subTitleProps,
padding,
onClickLocation,
separator,
separatorProps,
oneLine,
before,
above,
iconBefore: iconBeforeProp,
subTextOpacity = 0.6,
after,
indent = 0,
alignItems,
selectable,
hideBorder,
editable,
onEdit,
onStartEdit,
onCancelEdit,
deletable,
onDelete,
...surfaceProps
} = props
const isFocused = useFocus()
const isSelected = useIsSelected(props)
const showChildren = !props.hideBody
const showSubtitle = !!subTitle && !props.hideSubtitle
const showDate = !!date && !props.hideDate
const showIcon = !!icon && !props.hideIcon
const showTitle = !!title && !props.hideTitle
const showPreview = !!preview && !children && !props.hideBody
const showPreviewInSubtitle = !showTitle && oneLine
// 13 instead of 12px here fixed a very odd clipping bug
const iconBefore = iconBeforeProp || !showTitle
const hasMouseDownEvent = !!surfaceProps.onMouseDown
const disablePsuedoProps = selectable === false && {
hoverStyle: false,
activeStyle: false,
}
const iconElement = showIcon && getIcon(props)
const paddingIn = selectDefined(padding, 12)
const paddingVerticalPx = Array.isArray(paddingIn) ? +paddingIn[0] : +paddingIn
// @ts-ignore TODO
const listItemAdjustedPadding = paddingTheme({ padding: paddingIn })
const space = listItemAdjustedPadding ? listItemAdjustedPadding.paddingTop : undefined
const hasChildren = showChildren && !!children
const childrenElement = hasChildren && (
{children}
)
// TODO could let a prop control content
const afterHeaderElement = showDate && (
)
const locationElement = !!location && (
<>
{`${location}`}
>
)
const hasAfterTitle = !!(props.afterTitle || afterHeaderElement)
const coat = isSelected ? (isFocused ? 'selected' : 'selectedInactive') : undefined
// its a lot easier at times to just get the props from the click event
const handleClick = useCallback(
onClick
? e => {
onClick(e, props)
}
: idFn,
[onClick],
)
// move click to mouseup and automatically wrap click if wanted
// TODO check why this logic is necessary, has to do with selection/drag
const handleMouseUp = useCallback(
e => {
!!surfaceProps.onMouseUp && surfaceProps.onMouseUp!(e)
hasMouseDownEvent && handleClick(e)
},
[hasMouseDownEvent, surfaceProps.onMouseUp, handleClick],
)
return (
<>
{above && {above}}
{/* unset the theme for the separator */}
{!!separator && (
// remove any special indicator we add for alt themes
// TODO this is awkward (the split)
<>
{isValidElement(separator) ? (
separator
) : (
{separator}
)}
>
)}
{before}
{!!before && }
{!hideBorder && }
>
}
space={space}
icon={iconBefore && iconElement}
showInnerElement={iconElement ? 'always' : 'never'}
{...disablePsuedoProps}
{...surfaceProps}
onMouseUp={handleMouseUp}
>
{showTitle && (
{showIcon && !iconBefore && iconElement}
{isValidElement(title) ? (
title
) : (
{title}
)}
)}
{showSubtitle && (
<>
{!!location && locationElement}
{!!subTitle &&
(typeof subTitle === 'string' ? (
{subTitle}
) : (
subTitle
))}
{!subTitle && (
<>
>
)}
{!showTitle && (
<>
{afterHeaderElement}
>
)}
>
)}
{/* vertical space only if needed */}
{showSubtitle && !!(children || showPreview) && (
)}
{showPreview && (
<>
{locationElement}
{typeof preview !== 'string' && preview}
{typeof preview === 'string' && (
{preview}
)}
>
)}
{coat ? {childrenElement} : childrenElement}
{hasAfterTitle && (
<>
{props.afterTitle}
{afterHeaderElement}
>
)}
{/* TODO we should make this a right click option at least in electron */}
{!!deletable && (
<>
>
)
}, isEqual)
const ListItemTitleBar = gloss(Stack, {
width: '100%',
flex: 1,
justifyContent: 'flex-start',
alignItems: 'flex-start',
textAlign: 'left',
})
const Preview = gloss(Box, {
flex: 1,
zIndex: -1,
})
const ListItemSubtitle = gloss(View, {
flexDirection: 'row',
alignItems: 'center',
flex: 1,
overflow: 'hidden',
// prevents RoundButton/location from getting cropped
minHeight: 'min-content',
})
const AfterHeader = gloss(Box, {
alignItems: 'flex-end',
// why? for some reason this is really hard to align the text with the title,
// check the visual date in list items to see if this helps align it in the row
marginBottom: -4,
})
const ListItemMainContent = gloss(Box, {
flex: 1,
margin: ['auto', 0],
flexDirection: 'row',
})
const getIconSize = props =>
props.iconSize ||
(props.iconProps && props.iconProps.size) ||
(props.iconBefore ? (!(props.subTitle || props.children) ? 20 : 24) : 14)
function getIcon(props: ListItemSimpleProps) {
const size = getIconSize(props)
const iconPropsFinal = {
size,
...props.iconProps,
}
let element = props.icon
if (React.isValidElement(props.icon)) {
const type = props.icon.type
// @ts-ignore
if (type.acceptsProps && type.acceptsProps.icon) {
element = React.cloneElement(props.icon, iconPropsFinal)
}
} else {
element =
}
return element
}