You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Tabs.tsx 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import React, { useCallback } from 'react';
  2. import { makeStyles } from 'tss-react/mui';
  3. import { isMobileBrowser } from '../../../environment/utils';
  4. import { withPixelLineHeight } from '../../../styles/functions.web';
  5. interface ITabProps {
  6. accessibilityLabel: string;
  7. className?: string;
  8. onChange: (id: string) => void;
  9. selected: string;
  10. tabs: Array<{
  11. accessibilityLabel: string;
  12. countBadge?: number;
  13. disabled?: boolean;
  14. id: string;
  15. label: string;
  16. }>;
  17. }
  18. const useStyles = makeStyles()(theme => {
  19. return {
  20. container: {
  21. display: 'flex'
  22. },
  23. tab: {
  24. ...withPixelLineHeight(theme.typography.bodyShortBold),
  25. color: theme.palette.text02,
  26. flex: 1,
  27. padding: '14px',
  28. background: 'none',
  29. border: 0,
  30. appearance: 'none',
  31. borderBottom: `2px solid ${theme.palette.ui05}`,
  32. transition: 'color, border-color 0.2s',
  33. display: 'flex',
  34. alignItems: 'center',
  35. justifyContent: 'center',
  36. borderRadius: 0,
  37. '&:hover': {
  38. color: theme.palette.text01,
  39. borderColor: theme.palette.ui10
  40. },
  41. '&.focus-visible': {
  42. outline: 0,
  43. boxShadow: `0px 0px 0px 2px ${theme.palette.focus01}`,
  44. border: 0,
  45. color: theme.palette.text01
  46. },
  47. '&.selected': {
  48. color: theme.palette.text01,
  49. borderColor: theme.palette.action01
  50. },
  51. '&:disabled': {
  52. color: theme.palette.text03,
  53. borderColor: theme.palette.ui05
  54. },
  55. '&.is-mobile': {
  56. ...withPixelLineHeight(theme.typography.bodyShortBoldLarge)
  57. }
  58. },
  59. badge: {
  60. ...withPixelLineHeight(theme.typography.labelBold),
  61. color: theme.palette.text04,
  62. padding: `0 ${theme.spacing(1)}`,
  63. borderRadius: '100%',
  64. backgroundColor: theme.palette.warning01,
  65. marginLeft: theme.spacing(2)
  66. }
  67. };
  68. });
  69. const Tabs = ({
  70. accessibilityLabel,
  71. className,
  72. onChange,
  73. selected,
  74. tabs
  75. }: ITabProps) => {
  76. const { classes, cx } = useStyles();
  77. const isMobile = isMobileBrowser();
  78. const handleChange = useCallback((e: React.MouseEvent<HTMLButtonElement>) => {
  79. onChange(e.currentTarget.id);
  80. }, []);
  81. return (
  82. <div
  83. aria-label = { accessibilityLabel }
  84. className = { cx(classes.container, className) }
  85. role = 'tablist'>
  86. {tabs.map(tab => (
  87. <button
  88. aria-label = { tab.accessibilityLabel }
  89. aria-selected = { selected === tab.id }
  90. className = { cx(classes.tab, selected === tab.id && 'selected', isMobile && 'is-mobile') }
  91. disabled = { tab.disabled }
  92. id = { tab.id }
  93. key = { tab.id }
  94. onClick = { handleChange }
  95. role = 'tab'>
  96. {tab.label}
  97. {tab.countBadge && <span className = { classes.badge }>{tab.countBadge}</span>}
  98. </button>
  99. ))}
  100. </div>
  101. );
  102. };
  103. export default Tabs;