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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import { Theme } from '@mui/material';
  2. import React, { useCallback } from 'react';
  3. import { makeStyles } from 'tss-react/mui';
  4. import { isMobileBrowser } from '../../../environment/utils';
  5. import { withPixelLineHeight } from '../../../styles/functions.web';
  6. interface TabProps {
  7. accessibilityLabel: 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: 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': {
  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. tabs,
  71. onChange,
  72. selected,
  73. accessibilityLabel
  74. }: TabProps) => {
  75. const { classes, cx } = useStyles();
  76. const isMobile = isMobileBrowser();
  77. const handleChange = useCallback((e: React.MouseEvent<HTMLButtonElement>) => {
  78. onChange(e.currentTarget.id);
  79. }, []);
  80. return (
  81. <div
  82. aria-label = { accessibilityLabel }
  83. className = { classes.container }
  84. role = 'tablist'>
  85. {tabs.map(tab => (
  86. <button
  87. aria-label = { tab.accessibilityLabel }
  88. aria-selected = { selected === tab.id }
  89. className = { cx(classes.tab, selected === tab.id && 'selected', isMobile && 'is-mobile') }
  90. disabled = { tab.disabled }
  91. id = { tab.id }
  92. key = { tab.id }
  93. onClick = { handleChange }
  94. role = 'tab'>
  95. {tab.label}
  96. {tab.countBadge && <span className = { classes.badge }>{tab.countBadge}</span>}
  97. </button>
  98. ))}
  99. </div>
  100. );
  101. };
  102. export default Tabs;