1import * as React from 'react' 2import * as Kb from '../../../../../common-adapters' 3import * as Styles from '../../../../../styles' 4import * as Types from '../../../../../constants/types/chat2' 5 6const skinTones: Array<undefined | Types.EmojiSkinTone> = [ 7 undefined, 8 '1F3FB', 9 '1F3FC', 10 '1F3FD', 11 '1F3FE', 12 '1F3FF', 13] 14 15const circle = (skinTone: undefined | Types.EmojiSkinTone, isExpanded: boolean, outerCircle: boolean) => { 16 return ( 17 <Kb.Box style={{position: 'relative'}}> 18 {outerCircle && <Kb.Box style={styles.circleOuter} />} 19 <Kb.Box 20 style={Styles.collapseStyles([ 21 !isExpanded && styles.circleCollapsed, 22 isExpanded && styles.circleExpanded, 23 {backgroundColor: Types.SkinToneToDotColor(skinTone)}, 24 ])} 25 ></Kb.Box> 26 </Kb.Box> 27 ) 28} 29 30type Props = { 31 currentSkinTone?: Types.EmojiSkinTone 32 onExpandChange?: (expanded: boolean) => void 33 setSkinTone: (skinTone: undefined | Types.EmojiSkinTone) => void 34} 35 36const reorderedSkinTones = (props: Props): Array<undefined | Types.EmojiSkinTone> => 37 Styles.isMobile 38 ? skinTones 39 : [props.currentSkinTone, ...skinTones.filter(st => st !== props.currentSkinTone)] 40 41const SkinTonePicker = (props: Props) => { 42 const [expanded, _setExpanded] = React.useState(false) 43 const setExpanded = (toSet: boolean) => { 44 _setExpanded(toSet) 45 props.onExpandChange?.(toSet) 46 } 47 const optionSkinTones = reorderedSkinTones(props).map((skinTone, index) => ( 48 <Kb.ClickableBox 49 key={index.toString()} 50 style={styles.dotContainerExpanded} 51 onClick={() => { 52 props.setSkinTone(skinTone) 53 setExpanded(false) 54 }} 55 > 56 {circle(skinTone, true, Styles.isMobile && skinTone === props.currentSkinTone)} 57 </Kb.ClickableBox> 58 )) 59 return Styles.isMobile ? ( 60 expanded ? ( 61 <Kb.Box2 62 direction="horizontal" 63 fullWidth={true} 64 alignItems="center" 65 style={styles.optionSkinTonesContainerMobile} 66 > 67 {optionSkinTones} 68 </Kb.Box2> 69 ) : ( 70 <Kb.ClickableBox onClick={() => setExpanded(true)}> 71 <Kb.Box2 direction="horizontal" alignItems="center" gap="tiny"> 72 {circle(props.currentSkinTone, false, false)} 73 <Kb.Text type="BodySmallSemibold">Skin tone</Kb.Text> 74 </Kb.Box2> 75 </Kb.ClickableBox> 76 ) 77 ) : ( 78 <Kb.Box style={styles.relative}> 79 {expanded ? ( 80 <Kb.Animated to={{height: 126}} from={{height: 26}} config={reactSprintConfig}> 81 {({height}) => ( 82 <Kb.Box2 direction="vertical" style={Styles.collapseStyles([styles.popupContainer, {height}])}> 83 {optionSkinTones} 84 </Kb.Box2> 85 )} 86 </Kb.Animated> 87 ) : ( 88 <Kb.WithTooltip tooltip="Skin tone" containerStyle={styles.absolute}> 89 <Kb.ClickableBox style={styles.dotContainerDesktop} onClick={() => setExpanded(true)}> 90 {circle(props.currentSkinTone, false, false)} 91 </Kb.ClickableBox> 92 </Kb.WithTooltip> 93 )} 94 <Kb.Box style={styles.dotPlaceholder} /> 95 </Kb.Box> 96 ) 97} 98 99export default SkinTonePicker 100 101const styles = Styles.styleSheetCreate(() => ({ 102 absolute: {position: 'absolute'}, 103 circleCollapsed: { 104 borderRadius: Styles.globalMargins.small / 2, 105 height: Styles.globalMargins.small, 106 width: Styles.globalMargins.small, 107 }, 108 circleExpanded: Styles.platformStyles({ 109 isElectron: { 110 borderRadius: Styles.globalMargins.small / 2, 111 height: Styles.globalMargins.small, 112 width: Styles.globalMargins.small, 113 }, 114 isMobile: { 115 borderRadius: (Styles.globalMargins.small + Styles.globalMargins.xtiny) / 2, 116 height: Styles.globalMargins.small + Styles.globalMargins.xtiny, 117 width: Styles.globalMargins.small + Styles.globalMargins.xtiny, 118 }, 119 }), 120 circleOuter: { 121 backgroundColor: Styles.globalColors.white, 122 borderColor: Styles.globalColors.black_10, 123 borderRadius: (Styles.globalMargins.mediumLarge - Styles.globalMargins.xxtiny) / 2, 124 borderStyle: 'solid', 125 borderWidth: 1, 126 height: Styles.globalMargins.mediumLarge - Styles.globalMargins.xxtiny, 127 left: -5, 128 position: 'absolute', 129 top: -5, 130 width: Styles.globalMargins.mediumLarge - Styles.globalMargins.xxtiny, 131 }, 132 dotContainerDesktop: { 133 padding: Styles.globalMargins.tiny, 134 }, 135 dotContainerExpanded: { 136 padding: Styles.globalMargins.xxtiny, 137 }, 138 dotPlaceholder: { 139 height: Styles.globalMargins.small * 2, 140 width: Styles.globalMargins.small * 2, 141 }, 142 optionSkinTonesContainerMobile: { 143 justifyContent: 'space-between', 144 }, 145 popupContainer: { 146 backgroundColor: Styles.globalColors.white, 147 borderColor: Styles.globalColors.black_10, 148 borderRadius: Styles.globalMargins.small, 149 borderStyle: 'solid', 150 borderWidth: 1, 151 marginLeft: Styles.globalMargins.xtiny - 1, 152 marginTop: Styles.globalMargins.xtiny - 1, 153 overflow: 'hidden', 154 padding: Styles.globalMargins.xxtiny, 155 position: 'absolute', 156 zIndex: 1, 157 }, 158 relative: {position: 'relative'}, 159})) 160 161const reactSprintConfig = {clamp: true, friction: 20, tension: 210} 162