index.tsx 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import 'intersection-observer'; // polyfill
  2. import {createContext, useState} from 'react';
  3. import styled from '@emotion/styled';
  4. import {AriaTabListProps} from '@react-aria/tabs';
  5. import {Item} from '@react-stately/collections';
  6. import {TabListProps, TabListState} from '@react-stately/tabs';
  7. import {ItemProps, Orientation} from '@react-types/shared';
  8. import {TabList} from './tabList';
  9. import {TabPanels} from './tabPanels';
  10. import {tabsShouldForwardProp} from './utils';
  11. const _Item = Item as (
  12. props: ItemProps<any> & {disabled?: boolean; hidden?: boolean}
  13. ) => JSX.Element;
  14. export {_Item as Item, TabList, TabPanels};
  15. export interface TabsProps<T>
  16. extends Omit<TabListProps<any>, 'children'>,
  17. Omit<AriaTabListProps<any>, 'children'> {
  18. children?: React.ReactNode;
  19. className?: string;
  20. /**
  21. * [Uncontrolled] Default selected tab. Must match the `key` prop on the
  22. * selected tab item.
  23. */
  24. defaultValue?: T;
  25. disabled?: boolean;
  26. /**
  27. * Callback when the selected tab changes.
  28. */
  29. onChange?: (key: T) => void;
  30. /**
  31. * [Controlled] Selected tab . Must match the `key` prop on the selected tab
  32. * item.
  33. */
  34. value?: T;
  35. }
  36. interface TabContext {
  37. rootProps: TabsProps<any> & {orientation: Orientation};
  38. setTabListState: (state: TabListState<any>) => void;
  39. tabListState?: TabListState<any>;
  40. }
  41. export const TabsContext = createContext<TabContext>({
  42. rootProps: {orientation: 'horizontal', children: []},
  43. setTabListState: () => {},
  44. });
  45. /**
  46. * Root tabs component. Provides the necessary data (via React context) for
  47. * child components (TabList and TabPanels) to work together. See example
  48. * usage in tabs.stories.js
  49. */
  50. export function Tabs<T extends React.Key>({
  51. orientation = 'horizontal',
  52. className,
  53. ...props
  54. }: TabsProps<T>) {
  55. const [tabListState, setTabListState] = useState<TabListState<any>>();
  56. return (
  57. <TabsContext.Provider
  58. value={{rootProps: {...props, orientation}, tabListState, setTabListState}}
  59. >
  60. <TabsWrap orientation={orientation} className={className}>
  61. {props.children}
  62. </TabsWrap>
  63. </TabsContext.Provider>
  64. );
  65. }
  66. const TabsWrap = styled('div', {shouldForwardProp: tabsShouldForwardProp})<{
  67. orientation: Orientation;
  68. }>`
  69. display: flex;
  70. flex-direction: ${p => (p.orientation === 'horizontal' ? 'column' : 'row')};
  71. flex-grow: 1;
  72. ${p =>
  73. p.orientation === 'vertical' &&
  74. `
  75. height: 100%;
  76. align-items: stretch;
  77. `};
  78. `;