Bluesky app fork with some witchin' additions 💫

[APP-1310] Button refresh (#8758)

* Rm gradient buttons from Storybook

* TEMP move storybook button section

* Remove gradient_sky

* Remove actual defs for gradient_sky and gradient_primary

* Remove other gradient defs

* Remove gradient support entirely

* Deprecate 'variant' in favor of 'color'

* Fork base styles codepath to make variant deprecation more obvious

* Remove text styles for when no color is set, never been used

* Fork text styles codepath to make variant deprecation more obvious

* Revert temp storybook commit, remove deprecated values

* Replace remaining gradient button usage

* Update Buttons storybook section

* Update tiny styles

* Update small styles

* Update large sizes

* Ensure proper alignment of buttons in storybook

* Update button colors

* Rename negative_secondary to negative_subtle

* Remove unnecessary select()

* Update icon size and gap

* Update negative_subtle styles

* Custom button colors

* Add borderCurve

authored by

Eric Bailey and committed by
GitHub
cb54082e 20ac2e27

+170 -206
+100 -60
src/components/Button.tsx
··· 37 37 | 'secondary' 38 38 | 'secondary_inverted' 39 39 | 'negative' 40 - | 'negative_secondary' 40 + | 'primary_subtle' 41 + | 'negative_subtle' 41 42 export type ButtonSize = 'tiny' | 'small' | 'large' 42 43 export type ButtonShape = 'round' | 'square' | 'default' 43 44 export type VariantProps = { ··· 214 215 ) 215 216 216 217 const {baseStyles, hoverStyles} = React.useMemo(() => { 217 - const baseStyles: ViewStyle[] = [] 218 + const baseStyles: ViewStyle[] = [ 219 + { 220 + borderCurve: 'continuous', 221 + }, 222 + ] 218 223 const hoverStyles: ViewStyle[] = [] 219 224 220 225 /* ··· 233 238 }) 234 239 } else { 235 240 baseStyles.push({ 236 - backgroundColor: select(t.name, { 237 - light: t.palette.primary_700, 238 - dim: t.palette.primary_300, 239 - dark: t.palette.primary_300, 240 - }), 241 + backgroundColor: t.palette.primary_200, 241 242 }) 242 243 } 243 244 } else if (color === 'secondary') { 244 245 if (!disabled) { 245 246 baseStyles.push(t.atoms.bg_contrast_25) 246 - hoverStyles.push(t.atoms.bg_contrast_50) 247 + hoverStyles.push(t.atoms.bg_contrast_100) 247 248 } else { 248 - baseStyles.push(t.atoms.bg_contrast_100) 249 + baseStyles.push(t.atoms.bg_contrast_50) 249 250 } 250 251 } else if (color === 'secondary_inverted') { 251 252 if (!disabled) { ··· 253 254 backgroundColor: t.palette.contrast_900, 254 255 }) 255 256 hoverStyles.push({ 256 - backgroundColor: t.palette.contrast_950, 257 + backgroundColor: t.palette.contrast_975, 257 258 }) 258 259 } else { 259 260 baseStyles.push({ ··· 270 271 }) 271 272 } else { 272 273 baseStyles.push({ 274 + backgroundColor: t.palette.negative_700, 275 + }) 276 + } 277 + } else if (color === 'primary_subtle') { 278 + if (!disabled) { 279 + baseStyles.push({ 273 280 backgroundColor: select(t.name, { 274 - light: t.palette.negative_700, 275 - dim: t.palette.negative_300, 276 - dark: t.palette.negative_300, 281 + light: t.palette.primary_50, 282 + dim: t.palette.primary_100, 283 + dark: t.palette.primary_100, 284 + }), 285 + }) 286 + hoverStyles.push({ 287 + backgroundColor: select(t.name, { 288 + light: t.palette.primary_100, 289 + dim: t.palette.primary_200, 290 + dark: t.palette.primary_200, 291 + }), 292 + }) 293 + } else { 294 + baseStyles.push({ 295 + backgroundColor: select(t.name, { 296 + light: t.palette.primary_25, 297 + dim: t.palette.primary_50, 298 + dark: t.palette.primary_50, 277 299 }), 278 300 }) 279 301 } 280 - } else if (color === 'negative_secondary') { 302 + } else if (color === 'negative_subtle') { 281 303 if (!disabled) { 282 304 baseStyles.push({ 283 305 backgroundColor: select(t.name, { ··· 296 318 } else { 297 319 baseStyles.push({ 298 320 backgroundColor: select(t.name, { 299 - light: t.palette.negative_100, 321 + light: t.palette.negative_25, 300 322 dim: t.palette.negative_50, 301 323 dark: t.palette.negative_50, 302 324 }), ··· 407 429 }) 408 430 } 409 431 } 410 - } else if (color === 'negative_secondary') { 432 + } else if (color === 'negative_subtle') { 411 433 if (variant === 'outline') { 412 434 baseStyles.push(a.border, t.atoms.bg, { 413 435 borderWidth: 1, ··· 442 464 if (shape === 'default') { 443 465 if (size === 'large') { 444 466 baseStyles.push({ 445 - paddingVertical: 13, 446 - paddingHorizontal: 20, 447 - borderRadius: 8, 448 - gap: 8, 467 + paddingVertical: 14, 468 + paddingHorizontal: 24, 469 + borderRadius: 10, 470 + gap: 4, 449 471 }) 450 472 } else if (size === 'small') { 451 473 baseStyles.push({ 452 - paddingVertical: 9, 474 + paddingVertical: 8, 453 475 paddingHorizontal: 12, 454 - borderRadius: 6, 455 - gap: 6, 476 + borderRadius: 8, 477 + gap: 3, 456 478 }) 457 479 } else if (size === 'tiny') { 458 480 baseStyles.push({ 459 - paddingVertical: 4, 481 + paddingVertical: 6, 460 482 paddingHorizontal: 8, 461 - borderRadius: 4, 462 - gap: 4, 483 + borderRadius: 6, 484 + gap: 2, 463 485 }) 464 486 } 465 487 } else if (shape === 'round' || shape === 'square') { 488 + /* 489 + * These sizes match the actual rendered size on screen, based on 490 + * Chrome's web inspector 491 + */ 466 492 if (size === 'large') { 467 493 if (shape === 'round') { 468 - baseStyles.push({height: 46, width: 46}) 494 + baseStyles.push({height: 45, width: 45}) 469 495 } else { 470 - baseStyles.push({height: 44, width: 44}) 496 + baseStyles.push({height: 45, width: 45}) 471 497 } 472 498 } else if (size === 'small') { 473 499 if (shape === 'round') { 474 - baseStyles.push({height: 34, width: 34}) 500 + baseStyles.push({height: 33, width: 33}) 475 501 } else { 476 - baseStyles.push({height: 34, width: 34}) 502 + baseStyles.push({height: 33, width: 33}) 477 503 } 478 504 } else if (size === 'tiny') { 479 505 if (shape === 'round') { 480 - baseStyles.push({height: 22, width: 22}) 506 + baseStyles.push({height: 25, width: 25}) 481 507 } else { 482 - baseStyles.push({height: 21, width: 21}) 508 + baseStyles.push({height: 25, width: 25}) 483 509 } 484 510 } 485 511 ··· 487 513 baseStyles.push(a.rounded_full) 488 514 } else if (shape === 'square') { 489 515 if (size === 'tiny') { 490 - baseStyles.push(a.rounded_xs) 516 + baseStyles.push({ 517 + borderRadius: 6, 518 + }) 491 519 } else { 492 520 baseStyles.push(a.rounded_sm) 493 521 } ··· 567 595 if (!disabled) { 568 596 baseStyles.push({color: t.palette.white}) 569 597 } else { 570 - baseStyles.push({color: t.palette.white, opacity: 0.5}) 598 + baseStyles.push({color: t.palette.white}) 571 599 } 572 600 } else if (color === 'secondary') { 573 601 if (!disabled) { 574 - baseStyles.push({ 575 - color: t.palette.contrast_700, 576 - }) 602 + baseStyles.push(t.atoms.text_contrast_medium) 577 603 } else { 578 604 baseStyles.push({ 579 - color: t.palette.contrast_400, 605 + color: t.palette.contrast_300, 580 606 }) 581 607 } 582 608 } else if (color === 'secondary_inverted') { 583 609 if (!disabled) { 584 - baseStyles.push({ 585 - color: t.palette.contrast_50, 586 - }) 610 + baseStyles.push(t.atoms.text_inverted) 587 611 } else { 588 612 baseStyles.push({ 589 - color: t.palette.contrast_400, 613 + color: t.palette.contrast_300, 590 614 }) 591 615 } 592 616 } else if (color === 'negative') { 593 617 if (!disabled) { 594 618 baseStyles.push({color: t.palette.white}) 595 619 } else { 596 - baseStyles.push({color: t.palette.white, opacity: 0.5}) 620 + baseStyles.push({color: t.palette.negative_300}) 597 621 } 598 - } else if (color === 'negative_secondary') { 622 + } else if (color === 'primary_subtle') { 599 623 if (!disabled) { 600 624 baseStyles.push({ 601 625 color: select(t.name, { 602 - light: t.palette.negative_500, 603 - dim: t.palette.negative_950, 604 - dark: t.palette.negative_900, 626 + light: t.palette.primary_600, 627 + dim: t.palette.primary_800, 628 + dark: t.palette.primary_800, 605 629 }), 606 630 }) 607 631 } else { 608 632 baseStyles.push({ 609 633 color: select(t.name, { 610 - light: t.palette.negative_500, 611 - dim: t.palette.negative_700, 612 - dark: t.palette.negative_700, 634 + light: t.palette.primary_200, 635 + dim: t.palette.primary_200, 636 + dark: t.palette.primary_200, 613 637 }), 614 - opacity: 0.5, 638 + }) 639 + } 640 + } else if (color === 'negative_subtle') { 641 + if (!disabled) { 642 + baseStyles.push({ 643 + color: select(t.name, { 644 + light: t.palette.negative_600, 645 + dim: t.palette.negative_800, 646 + dark: t.palette.negative_800, 647 + }), 648 + }) 649 + } else { 650 + baseStyles.push({ 651 + color: select(t.name, { 652 + light: t.palette.negative_200, 653 + dim: t.palette.negative_200, 654 + dark: t.palette.negative_200, 655 + }), 615 656 }) 616 657 } 617 658 } ··· 693 734 baseStyles.push({color: t.palette.negative_400, opacity: 0.5}) 694 735 } 695 736 } 696 - } else if (color === 'negative_secondary') { 737 + } else if (color === 'negative_subtle') { 697 738 if (variant === 'outline') { 698 739 if (!disabled) { 699 740 baseStyles.push({color: t.palette.negative_400}) ··· 716 757 if (size === 'large') { 717 758 baseStyles.push(a.text_md, a.leading_tight) 718 759 } else if (size === 'small') { 719 - baseStyles.push(a.text_sm, a.leading_tight) 760 + baseStyles.push(a.text_md, a.leading_tight) 720 761 } else if (size === 'tiny') { 721 762 baseStyles.push(a.text_xs, a.leading_tight) 722 763 } ··· 737 778 738 779 export function ButtonIcon({ 739 780 icon: Comp, 740 - position, 741 781 size, 742 782 }: { 743 783 icon: React.ComponentType<SVGIconProps> 784 + /** 785 + * @deprecated no longer needed 786 + */ 744 787 position?: 'left' | 'right' 745 788 size?: SVGIconProps['size'] 746 789 }) { 747 - const {size: buttonSize, disabled} = useButtonContext() 790 + const {size: buttonSize} = useButtonContext() 748 791 const textStyles = useSharedButtonTextStyles() 749 792 const {iconSize, iconContainerSize} = React.useMemo(() => { 750 793 /** ··· 779 822 * don't increase button size 780 823 */ 781 824 const iconContainerSize = { 782 - large: 18, 783 - small: 16, 825 + large: 17, 826 + small: 17, 784 827 tiny: 13, 785 828 }[buttonSize || 'small'] 786 829 ··· 797 840 { 798 841 width: iconContainerSize, 799 842 height: iconContainerSize, 800 - opacity: disabled ? 0.7 : 1, 801 - marginLeft: position === 'left' ? -2 : 0, 802 - marginRight: position === 'right' ? -2 : 0, 803 843 }, 804 844 ]}> 805 845 <View
+1 -1
src/components/live/EditLiveDialog.tsx
··· 240 240 label={_(msg`Remove live status`)} 241 241 onPress={() => removeLiveStatus()} 242 242 size={platform({native: 'large', web: 'small'})} 243 - color="negative_secondary" 243 + color="negative_subtle" 244 244 variant="solid" 245 245 disabled={isRemovingLiveStatus || isGoingLive}> 246 246 <ButtonText>
+68 -144
src/view/screens/Storybook/Buttons.tsx
··· 1 + import {Fragment} from 'react' 1 2 import {View} from 'react-native' 2 3 3 4 import {atoms as a} from '#/alf' ··· 5 6 Button, 6 7 type ButtonColor, 7 8 ButtonIcon, 9 + type ButtonSize, 8 10 ButtonText, 9 11 } from '#/components/Button' 10 12 import {ChevronLeft_Stroke2_Corner0_Rounded as ChevronLeft} from '#/components/icons/Chevron' 11 13 import {Globe_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe' 12 - import {H1} from '#/components/Typography' 14 + import {Text} from '#/components/Typography' 13 15 14 16 export function Buttons() { 15 17 return ( 16 18 <View style={[a.gap_md]}> 17 - <H1>Buttons</H1> 18 - 19 - <View style={[a.flex_row, a.flex_wrap, a.gap_md, a.align_start]}> 20 - {[ 21 - 'primary', 22 - 'secondary', 23 - 'secondary_inverted', 24 - 'negative', 25 - 'negative_secondary', 26 - ].map(color => ( 27 - <View key={color} style={[a.gap_md, a.align_start]}> 28 - <Button 29 - color={color as ButtonColor} 30 - size="large" 31 - label="Click here"> 32 - <ButtonText>Button</ButtonText> 33 - </Button> 34 - <Button 35 - disabled 36 - color={color as ButtonColor} 37 - size="large" 38 - label="Click here"> 39 - <ButtonText>Button</ButtonText> 40 - </Button> 41 - </View> 42 - ))} 43 - </View> 44 - 45 - <View style={[a.flex_wrap, a.gap_md, a.align_start]}> 46 - <Button color="primary" size="large" label="Link out"> 47 - <ButtonText>Button</ButtonText> 48 - </Button> 49 - <Button color="primary" size="large" label="Link out"> 50 - <ButtonText>Button</ButtonText> 51 - <ButtonIcon icon={Globe} position="right" /> 52 - </Button> 53 - 54 - <Button color="primary" size="small" label="Link out"> 55 - <ButtonText>Button</ButtonText> 56 - </Button> 57 - <Button color="primary" size="small" label="Link out"> 58 - <ButtonText>Button</ButtonText> 59 - <ButtonIcon icon={Globe} position="right" /> 60 - </Button> 61 - 62 - <Button color="primary" size="tiny" label="Link out"> 63 - <ButtonIcon icon={Globe} position="left" /> 64 - <ButtonText>Button</ButtonText> 65 - </Button> 66 - </View> 67 - 68 - <View style={[a.flex_row, a.gap_md, a.align_center]}> 69 - <Button color="primary" size="large" label="Link out"> 70 - <ButtonText>Button</ButtonText> 71 - </Button> 72 - <Button color="primary" size="large" label="Link out"> 73 - <ButtonText>Button</ButtonText> 74 - <ButtonIcon icon={Globe} position="right" /> 75 - </Button> 76 - <Button color="primary" size="large" label="Link out"> 77 - <ButtonText>Button</ButtonText> 78 - <ButtonIcon icon={Globe} position="right" size="lg" /> 79 - </Button> 80 - <Button color="primary" size="large" shape="round" label="Link out"> 81 - <ButtonIcon icon={ChevronLeft} /> 82 - </Button> 83 - <Button color="primary" size="large" shape="round" label="Link out"> 84 - <ButtonIcon icon={ChevronLeft} size="lg" /> 85 - </Button> 86 - </View> 87 - 88 - <View style={[a.flex_row, a.gap_md, a.align_center]}> 89 - <Button color="primary" size="small" label="Link out"> 90 - <ButtonText>Button</ButtonText> 91 - </Button> 92 - <Button color="primary" size="small" label="Link out"> 93 - <ButtonText>Button</ButtonText> 94 - <ButtonIcon icon={Globe} position="right" /> 95 - </Button> 96 - <Button color="primary" size="small" shape="round" label="Link out"> 97 - <ButtonIcon icon={ChevronLeft} /> 98 - </Button> 99 - <Button color="primary" size="small" shape="round" label="Link out"> 100 - <ButtonIcon icon={ChevronLeft} size="lg" /> 101 - </Button> 102 - </View> 103 - 104 - <View style={[a.flex_row, a.gap_md, a.align_center]}> 105 - <Button color="primary" size="tiny" label="Link out"> 106 - <ButtonText>Button</ButtonText> 107 - </Button> 108 - <Button color="primary" size="tiny" label="Link out"> 109 - <ButtonText>Button</ButtonText> 110 - <ButtonIcon icon={Globe} position="right" /> 111 - </Button> 112 - <Button color="primary" size="tiny" shape="round" label="Link out"> 113 - <ButtonIcon icon={ChevronLeft} /> 114 - </Button> 115 - <Button color="primary" size="tiny" shape="round" label="Link out"> 116 - <ButtonIcon icon={ChevronLeft} size="md" /> 117 - </Button> 118 - </View> 19 + <Text style={[a.font_heavy, a.text_5xl]}>Buttons</Text> 119 20 120 - <View style={[a.flex_row, a.gap_md, a.align_center]}> 121 - <Button color="primary" size="large" shape="round" label="Link out"> 122 - <ButtonIcon icon={ChevronLeft} /> 123 - </Button> 124 - <Button color="primary" size="small" shape="round" label="Link out"> 125 - <ButtonIcon icon={ChevronLeft} /> 126 - </Button> 127 - <Button color="primary" size="tiny" shape="round" label="Link out"> 128 - <ButtonIcon icon={ChevronLeft} /> 129 - </Button> 130 - <Button color="primary" size="large" shape="round" label="Link out"> 131 - <ButtonIcon icon={ChevronLeft} /> 132 - </Button> 133 - <Button color="primary" size="small" shape="round" label="Link out"> 134 - <ButtonIcon icon={ChevronLeft} /> 135 - </Button> 136 - <Button color="primary" size="tiny" shape="round" label="Link out"> 137 - <ButtonIcon icon={ChevronLeft} /> 138 - </Button> 139 - </View> 140 - 141 - <View style={[a.flex_row, a.gap_md, a.align_start]}> 142 - <Button color="primary" size="large" shape="square" label="Link out"> 143 - <ButtonIcon icon={ChevronLeft} /> 144 - </Button> 145 - <Button color="primary" size="small" shape="square" label="Link out"> 146 - <ButtonIcon icon={ChevronLeft} /> 147 - </Button> 148 - <Button color="primary" size="tiny" shape="square" label="Link out"> 149 - <ButtonIcon icon={ChevronLeft} /> 150 - </Button> 151 - <Button color="primary" size="large" shape="square" label="Link out"> 152 - <ButtonIcon icon={ChevronLeft} /> 153 - </Button> 154 - <Button color="primary" size="small" shape="square" label="Link out"> 155 - <ButtonIcon icon={ChevronLeft} /> 156 - </Button> 157 - <Button color="primary" size="tiny" shape="square" label="Link out"> 158 - <ButtonIcon icon={ChevronLeft} /> 159 - </Button> 160 - </View> 21 + {[ 22 + 'primary', 23 + 'secondary', 24 + 'secondary_inverted', 25 + 'negative', 26 + 'primary_subtle', 27 + 'negative_subtle', 28 + ].map(color => ( 29 + <Fragment key={color}> 30 + {['tiny', 'small', 'large'].map(size => ( 31 + <Fragment key={size}> 32 + <Text style={[a.font_heavy, a.text_2xl]}> 33 + color={color} size={size} 34 + </Text> 35 + <View style={[a.flex_row, a.align_start, a.gap_md]}> 36 + <Button 37 + color={color as ButtonColor} 38 + size={size as ButtonSize} 39 + label="Click here"> 40 + <ButtonText>Button</ButtonText> 41 + </Button> 42 + <Button 43 + disabled 44 + color={color as ButtonColor} 45 + size={size as ButtonSize} 46 + label="Click here"> 47 + <ButtonText>Button</ButtonText> 48 + </Button> 49 + <Button 50 + color={color as ButtonColor} 51 + size={size as ButtonSize} 52 + shape="round" 53 + label="Click here"> 54 + <ButtonIcon icon={ChevronLeft} /> 55 + </Button> 56 + <Button 57 + color={color as ButtonColor} 58 + size={size as ButtonSize} 59 + shape="square" 60 + label="Click here"> 61 + <ButtonIcon icon={ChevronLeft} /> 62 + </Button> 63 + </View> 64 + <View style={[a.flex_row, a.gap_md]}> 65 + <Button 66 + color={color as ButtonColor} 67 + size={size as ButtonSize} 68 + label="Click here"> 69 + <ButtonIcon icon={Globe} position="left" /> 70 + <ButtonText>Button</ButtonText> 71 + </Button> 72 + <Button 73 + disabled 74 + color={color as ButtonColor} 75 + size={size as ButtonSize} 76 + label="Click here"> 77 + <ButtonText>Button</ButtonText> 78 + <ButtonIcon icon={Globe} position="right" /> 79 + </Button> 80 + </View> 81 + </Fragment> 82 + ))} 83 + </Fragment> 84 + ))} 161 85 </View> 162 86 ) 163 87 }
+1 -1
src/view/screens/Storybook/index.tsx
··· 87 87 </Button> 88 88 </View> 89 89 90 + <Buttons /> 90 91 <Toasts /> 91 92 92 93 <Button ··· 109 110 </ThemeProvider> 110 111 111 112 <Forms /> 112 - <Buttons /> 113 113 <Typography /> 114 114 <Spacing /> 115 115 <Shadows />