mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
at new-image-api 221 lines 5.4 kB view raw
1import React from 'react' 2import {GestureResponderEvent, View} from 'react-native' 3import {msg} from '@lingui/macro' 4import {useLingui} from '@lingui/react' 5 6import {atoms as a, useBreakpoints, useTheme} from '#/alf' 7import {Button, ButtonColor, ButtonText} from '#/components/Button' 8import * as Dialog from '#/components/Dialog' 9import {Text} from '#/components/Typography' 10import {BottomSheetViewProps} from '../../modules/bottom-sheet' 11 12export { 13 type DialogControlProps as PromptControlProps, 14 useDialogControl as usePromptControl, 15} from '#/components/Dialog' 16 17const Context = React.createContext<{ 18 titleId: string 19 descriptionId: string 20}>({ 21 titleId: '', 22 descriptionId: '', 23}) 24 25export function Outer({ 26 children, 27 control, 28 testID, 29 nativeOptions, 30}: React.PropsWithChildren<{ 31 control: Dialog.DialogControlProps 32 testID?: string 33 nativeOptions?: Omit<BottomSheetViewProps, 'children'> 34}>) { 35 const {gtMobile} = useBreakpoints() 36 const titleId = React.useId() 37 const descriptionId = React.useId() 38 39 const context = React.useMemo( 40 () => ({titleId, descriptionId}), 41 [titleId, descriptionId], 42 ) 43 44 return ( 45 <Dialog.Outer 46 control={control} 47 testID={testID} 48 nativeOptions={{preventExpansion: true, ...nativeOptions}}> 49 <Dialog.Handle /> 50 <Context.Provider value={context}> 51 <Dialog.ScrollableInner 52 accessibilityLabelledBy={titleId} 53 accessibilityDescribedBy={descriptionId} 54 style={[ 55 gtMobile ? {width: 'auto', maxWidth: 400, minWidth: 200} : a.w_full, 56 ]}> 57 {children} 58 </Dialog.ScrollableInner> 59 </Context.Provider> 60 </Dialog.Outer> 61 ) 62} 63 64export function TitleText({children}: React.PropsWithChildren<{}>) { 65 const {titleId} = React.useContext(Context) 66 return ( 67 <Text 68 nativeID={titleId} 69 style={[a.text_2xl, a.font_bold, a.pb_sm, a.leading_snug]}> 70 {children} 71 </Text> 72 ) 73} 74 75export function DescriptionText({ 76 children, 77 selectable, 78}: React.PropsWithChildren<{selectable?: boolean}>) { 79 const t = useTheme() 80 const {descriptionId} = React.useContext(Context) 81 return ( 82 <Text 83 nativeID={descriptionId} 84 selectable={selectable} 85 style={[a.text_md, a.leading_snug, t.atoms.text_contrast_high, a.pb_lg]}> 86 {children} 87 </Text> 88 ) 89} 90 91export function Actions({children}: React.PropsWithChildren<{}>) { 92 const {gtMobile} = useBreakpoints() 93 94 return ( 95 <View 96 style={[ 97 a.w_full, 98 a.gap_md, 99 a.justify_end, 100 gtMobile 101 ? [a.flex_row, a.flex_row_reverse, a.justify_start] 102 : [a.flex_col], 103 ]}> 104 {children} 105 </View> 106 ) 107} 108 109export function Cancel({ 110 cta, 111}: { 112 /** 113 * Optional i18n string. If undefined, it will default to "Cancel". 114 */ 115 cta?: string 116}) { 117 const {_} = useLingui() 118 const {gtMobile} = useBreakpoints() 119 const {close} = Dialog.useDialogContext() 120 const onPress = React.useCallback(() => { 121 close() 122 }, [close]) 123 124 return ( 125 <Button 126 variant="solid" 127 color="secondary" 128 size={gtMobile ? 'small' : 'large'} 129 label={cta || _(msg`Cancel`)} 130 onPress={onPress}> 131 <ButtonText>{cta || _(msg`Cancel`)}</ButtonText> 132 </Button> 133 ) 134} 135 136export function Action({ 137 onPress, 138 color = 'primary', 139 cta, 140 testID, 141}: { 142 /** 143 * Callback to run when the action is pressed. The method is called _after_ 144 * the dialog closes. 145 * 146 * Note: The dialog will close automatically when the action is pressed, you 147 * should NOT close the dialog as a side effect of this method. 148 */ 149 onPress: (e: GestureResponderEvent) => void 150 color?: ButtonColor 151 /** 152 * Optional i18n string. If undefined, it will default to "Confirm". 153 */ 154 cta?: string 155 testID?: string 156}) { 157 const {_} = useLingui() 158 const {gtMobile} = useBreakpoints() 159 const {close} = Dialog.useDialogContext() 160 const handleOnPress = React.useCallback( 161 (e: GestureResponderEvent) => { 162 close(() => onPress?.(e)) 163 }, 164 [close, onPress], 165 ) 166 167 return ( 168 <Button 169 variant="solid" 170 color={color} 171 size={gtMobile ? 'small' : 'large'} 172 label={cta || _(msg`Confirm`)} 173 onPress={handleOnPress} 174 testID={testID}> 175 <ButtonText>{cta || _(msg`Confirm`)}</ButtonText> 176 </Button> 177 ) 178} 179 180export function Basic({ 181 control, 182 title, 183 description, 184 cancelButtonCta, 185 confirmButtonCta, 186 onConfirm, 187 confirmButtonColor, 188 showCancel = true, 189}: React.PropsWithChildren<{ 190 control: Dialog.DialogOuterProps['control'] 191 title: string 192 description: string 193 cancelButtonCta?: string 194 confirmButtonCta?: string 195 /** 196 * Callback to run when the Confirm button is pressed. The method is called 197 * _after_ the dialog closes. 198 * 199 * Note: The dialog will close automatically when the action is pressed, you 200 * should NOT close the dialog as a side effect of this method. 201 */ 202 onConfirm: (e: GestureResponderEvent) => void 203 confirmButtonColor?: ButtonColor 204 showCancel?: boolean 205}>) { 206 return ( 207 <Outer control={control} testID="confirmModal"> 208 <TitleText>{title}</TitleText> 209 <DescriptionText>{description}</DescriptionText> 210 <Actions> 211 <Action 212 cta={confirmButtonCta} 213 onPress={onConfirm} 214 color={confirmButtonColor} 215 testID="confirmBtn" 216 /> 217 {showCancel && <Cancel cta={cancelButtonCta} />} 218 </Actions> 219 </Outer> 220 ) 221}