index.tsx 2.4 KB

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