mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 286 lines 7.5 kB view raw
1import {createContext, forwardRef, useContext, useMemo} from 'react' 2import {View} from 'react-native' 3import {Select as RadixSelect} from 'radix-ui' 4 5import {flatten, useTheme} from '#/alf' 6import {atoms as a} from '#/alf' 7import {useInteractionState} from '#/components/hooks/useInteractionState' 8import {Check_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Check' 9import { 10 ChevronBottom_Stroke2_Corner0_Rounded as ChevronDownIcon, 11 ChevronTop_Stroke2_Corner0_Rounded as ChevronUpIcon, 12} from '#/components/icons/Chevron' 13import {Text} from '#/components/Typography' 14import { 15 type ContentProps, 16 type IconProps, 17 type ItemIndicatorProps, 18 type ItemProps, 19 type RadixPassThroughTriggerProps, 20 type RootProps, 21 type TriggerProps, 22 type ValueProps, 23} from './types' 24 25const SelectedValueContext = createContext<string | undefined | null>(null) 26SelectedValueContext.displayName = 'SelectSelectedValueContext' 27 28export function Root(props: RootProps) { 29 return ( 30 <SelectedValueContext.Provider value={props.value}> 31 <RadixSelect.Root {...props} /> 32 </SelectedValueContext.Provider> 33 ) 34} 35 36const RadixTriggerPassThrough = forwardRef( 37 ( 38 props: { 39 children: ( 40 props: RadixPassThroughTriggerProps & { 41 ref: React.Ref<any> 42 }, 43 ) => React.ReactNode 44 }, 45 ref, 46 ) => { 47 // @ts-expect-error Radix provides no types of this stuff 48 49 return props.children?.({...props, ref}) 50 }, 51) 52RadixTriggerPassThrough.displayName = 'RadixTriggerPassThrough' 53 54export function Trigger({children, label}: TriggerProps) { 55 const t = useTheme() 56 const { 57 state: hovered, 58 onIn: onMouseEnter, 59 onOut: onMouseLeave, 60 } = useInteractionState() 61 const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState() 62 63 if (typeof children === 'function') { 64 return ( 65 <RadixSelect.Trigger asChild> 66 <RadixTriggerPassThrough> 67 {props => 68 children({ 69 isNative: false, 70 state: { 71 hovered, 72 focused, 73 pressed: false, 74 }, 75 props: { 76 ...props, 77 onPress: props.onClick, 78 onFocus: onFocus, 79 onBlur: onBlur, 80 onMouseEnter, 81 onMouseLeave, 82 accessibilityLabel: label, 83 }, 84 }) 85 } 86 </RadixTriggerPassThrough> 87 </RadixSelect.Trigger> 88 ) 89 } else { 90 return ( 91 <RadixSelect.Trigger 92 onFocus={onFocus} 93 onBlur={onBlur} 94 onMouseEnter={onMouseEnter} 95 onMouseLeave={onMouseLeave} 96 style={flatten([ 97 a.flex, 98 a.relative, 99 t.atoms.bg_contrast_25, 100 a.rounded_sm, 101 a.w_full, 102 a.align_center, 103 a.gap_sm, 104 a.justify_between, 105 a.py_sm, 106 a.px_md, 107 a.pointer, 108 { 109 maxWidth: 400, 110 outline: 0, 111 borderWidth: 2, 112 borderStyle: 'solid', 113 borderColor: focused 114 ? t.palette.primary_500 115 : hovered 116 ? t.palette.contrast_100 117 : t.palette.contrast_25, 118 }, 119 ])}> 120 {children} 121 </RadixSelect.Trigger> 122 ) 123 } 124} 125 126export function ValueText({children: _, style, ...props}: ValueProps) { 127 return ( 128 <Text style={style}> 129 <RadixSelect.Value {...props} /> 130 </Text> 131 ) 132} 133 134export function Icon({style}: IconProps) { 135 const t = useTheme() 136 return ( 137 <RadixSelect.Icon> 138 <ChevronDownIcon style={[t.atoms.text, style]} size="xs" /> 139 </RadixSelect.Icon> 140 ) 141} 142 143export function Content<T>({items, renderItem}: ContentProps<T>) { 144 const t = useTheme() 145 const selectedValue = useContext(SelectedValueContext) 146 147 const scrollBtnStyles: React.CSSProperties[] = [ 148 a.absolute, 149 a.flex, 150 a.align_center, 151 a.justify_center, 152 a.rounded_sm, 153 a.z_10, 154 ] 155 const up: React.CSSProperties[] = [ 156 ...scrollBtnStyles, 157 a.pt_sm, 158 a.pb_lg, 159 { 160 top: 0, 161 left: 0, 162 right: 0, 163 borderBottomLeftRadius: 0, 164 borderBottomRightRadius: 0, 165 background: `linear-gradient(to bottom, ${t.atoms.bg.backgroundColor} 0%, transparent 100%)`, 166 }, 167 ] 168 const down: React.CSSProperties[] = [ 169 ...scrollBtnStyles, 170 a.pt_lg, 171 a.pb_sm, 172 { 173 bottom: 0, 174 left: 0, 175 right: 0, 176 borderBottomLeftRadius: 0, 177 borderBottomRightRadius: 0, 178 background: `linear-gradient(to top, ${t.atoms.bg.backgroundColor} 0%, transparent 100%)`, 179 }, 180 ] 181 182 return ( 183 <RadixSelect.Portal> 184 <RadixSelect.Content 185 style={flatten([t.atoms.bg, a.rounded_sm, a.overflow_hidden])} 186 position="popper" 187 sideOffset={5} 188 className="radix-select-content"> 189 <View 190 style={[ 191 a.flex_1, 192 a.border, 193 t.atoms.border_contrast_low, 194 a.rounded_sm, 195 a.overflow_hidden, 196 ]}> 197 <RadixSelect.ScrollUpButton style={flatten(up)}> 198 <ChevronUpIcon style={[t.atoms.text]} size="xs" /> 199 </RadixSelect.ScrollUpButton> 200 <RadixSelect.Viewport style={flatten([a.p_xs])}> 201 {items.map((item, index) => renderItem(item, index, selectedValue))} 202 </RadixSelect.Viewport> 203 <RadixSelect.ScrollDownButton style={flatten(down)}> 204 <ChevronDownIcon style={[t.atoms.text]} size="xs" /> 205 </RadixSelect.ScrollDownButton> 206 </View> 207 </RadixSelect.Content> 208 </RadixSelect.Portal> 209 ) 210} 211 212const ItemContext = createContext<{ 213 hovered: boolean 214 focused: boolean 215 pressed: boolean 216 selected: boolean 217}>({ 218 hovered: false, 219 focused: false, 220 pressed: false, 221 selected: false, 222}) 223ItemContext.displayName = 'SelectItemContext' 224 225export function useItemContext() { 226 return useContext(ItemContext) 227} 228 229export function Item({ref, value, style, children}: ItemProps) { 230 const t = useTheme() 231 const { 232 state: hovered, 233 onIn: onMouseEnter, 234 onOut: onMouseLeave, 235 } = useInteractionState() 236 const selected = useContext(SelectedValueContext) === value 237 const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState() 238 const ctx = useMemo( 239 () => ({hovered, focused, pressed: false, selected}), 240 [hovered, focused, selected], 241 ) 242 return ( 243 <RadixSelect.Item 244 ref={ref} 245 value={value} 246 onMouseEnter={onMouseEnter} 247 onMouseLeave={onMouseLeave} 248 onFocus={onFocus} 249 onBlur={onBlur} 250 style={flatten([ 251 t.atoms.text, 252 a.relative, 253 a.flex, 254 {minHeight: 25, paddingLeft: 30, paddingRight: 35}, 255 a.user_select_none, 256 a.align_center, 257 a.rounded_xs, 258 a.py_2xs, 259 a.text_sm, 260 {outline: 0}, 261 (hovered || focused) && {backgroundColor: t.palette.primary_50}, 262 selected && [a.font_semi_bold], 263 a.transition_color, 264 style, 265 ])}> 266 <ItemContext.Provider value={ctx}>{children}</ItemContext.Provider> 267 </RadixSelect.Item> 268 ) 269} 270 271export const ItemText = RadixSelect.ItemText 272 273export function ItemIndicator({icon: Icon = CheckIcon}: ItemIndicatorProps) { 274 return ( 275 <RadixSelect.ItemIndicator 276 style={flatten([ 277 a.absolute, 278 {left: 0, width: 30}, 279 a.flex, 280 a.align_center, 281 a.justify_center, 282 ])}> 283 <Icon size="sm" /> 284 </RadixSelect.ItemIndicator> 285 ) 286}